> Потому что это чушь же :) Хреновая верстка на голом html от аутсорсера/фрилансера может быть такого же градуса бредовости. Если не хуже
Вы опять уходите в сторону обсуждения принципиальной возможности чего-то, когда на практике важна именно количественная оценка. Следуя вашим рассуждениям — неплохо писать на брейнфаке. Потмоу что по факту любой аргумент против брейнфака применим и к другим языкам. Просто в меньшей степени. Иногда — в намного меньшей :)
> Ну то есть можно так, а можно этак
Ну какбы нельзя :)
И даже если бы было можно — опять возвращаемся к количественной оценке.
> Строки, строки, аттрибуты — строки.
Ну нет. Не будет там нигде строки «let value blablabla»
> Не понял, pure это в кривых реактовских терминах pure? Типа аргумент не меняется, пайп не пересчиваем?
Значит, чистая функция. В ФП-смысле — без сайд-эффектов, результат зависит только от аргумента.
> Для этого есть язык, и именно поэтому можно (и нужно) и обычные функции мемоизировать в рамках языка и дергать их с тем же успехом.
Это не будет работать внутри шаблонов. И там речь не о мемоизации. Если аргумент не изменился — пайп просто не запускается, а дом не перестраивается. Это внутренность алгоритма чендж-детекшона и «снаружи» такое поведение, фактически, не получить.
> Естественно, варианты из серии следующего — бред и не принимаются:
Почему не принимаются? И это только один из вариантов. Кроме map могут быть другие варианты преобразования (к списку может быть прихреначен и какой-нибудь фильтр там же, и список может как-то хитро строиться, и map у вас может быть какой-то свой, и вообще это все может быть в похожем на директивы варианты — куча вариантов, в общем).
> Да это-то понятно, просто вот вам и пример, что в этом «строгом DSL» тоже есть несколько путей для реализации.
На самом деле не совсем. Мой вариант со звездочкой неточен, т.к. на самом деле раскроется в:
<ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
<ng-container>
My name is: <i [innerHTML]="row['name']"></i> and <i>{{value}}</i>
<div>{{joke}}</div>
</ng-template>
</ng-container>
звездочковый эквивалент тут не написать. Возможно, именно по-этому и выбран рассахаренный вариант :)
> второй — совсем же дичь, всевдокод внутри строки, о боги :)
> То-то в рамках этих ограничений стало тесно, и тут же придумали наикостыльнейшие пайпы!
Какая теснота? Смысл пайпов исключительно в том, что они бывают pure, и в этом случае пересчитываются только тогда, когда изменится аргумент. Такого поведения затруднительно достичь, не замусорив код, это надо реализовывать на уровне компилятора шаблонов.
В противном случае (при отсутствии pure) пайпы были бы совершенно не нужны и ничего бы не давали, можно с тем же успехом дергать обычные функции.
Если ограничить JSX так, что другого способа написать эти конструкции в принципе не будет (вообще), то не сложнее. Тогда JSX станет тем же дслем, только с другим синтаксисом.
> На практике и map с первого раза в голове оседает. Знаю о чем говорю :)
Я же говорил — не было бы беды, если бы там ВСЕГДА был map. Но там произвольный js-код. Если ограничить JSX каким-то вменяемым подмножеством JS — он будет вполне ок. Проблема именно в том, что там может использоваться ВЕСЬ JS.
> По идее по ним там выборка какая-нибудь идет через @ContentChildren какой-нибудь.
Но именно атрибуты — ничего не делают, то есть это просто темплейт, в который потом на места let-атрибутов подставляются значения из контекста (контекст применяет уже внешняя директиваб ngx-datatable).
И на самом деле (кстати) это и есть рассахаренный «звездочковый» синтаксис
<ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
My name is: <i [innerHTML]="row['name']"></i> and <i>{{value}}</i>
<div>{{joke}}</div>
</ng-template>
->
<ng-container *ngx-datatable-cell-template="let row=row; let value=value">
My name is: <i [innerHTML]="row['name']"></i> and <i>{{value}}</i>
<div>{{joke}}</div>
</ng-container>
> теперь представьте что шаблонизатор настолько продвинут, что позволяет разработчику расширить и так расширенный синтаксис
Смысл шаблонизатора (как и любого ДСЛя или узкоспециализированного инструмента) ИМЕННО в том, что он ограничен в возможностях. Мы платим универсальностью за более удобное решение задач из узкого класса. Если вы делаете шаблонизатор универсальным — основное преимущество (ограниченность) сразу теряется.
> От navigate(route, anyObject)? Никто не помешает, ясен перец.
А, так вы тип генерика руками записывать собираетесь? я сразу просто это не понял. Непонятно, чем тогда не устраивает вариант navigate(routeFrom(route, params)).
> Отличный ответ. Лично мне ни в каком не удобно.
Непонятно тогда, зачем вы требуете функционал, который вам будет неудобен.
Очевидно же, первый вариант — это использование шаблонизатора (ng-repeat), а второй — универсальных инструментов, предоставленных хост-языком (map). Кстати, хороший пример :)
> Ну нет же, я ж написал уже, ng-repeat — не результат.
Конечно, результат. Вы смотрите и видите, какая нода получилась. А потом, увидев ng-repeat, понимаете, что там не одна она такая, а их много. гляда на произвольный js-код в JSX вам надо в уме выполнить этот код, чтобы получить ту информацию, которая вслучае шаблонизатора есть _сразу_.
> Но я ж не знаю, что там скрыто в ней? Придется «выполнить ее в уме» :)
Только вот кастомные структурные директивы встречаются в ангуляре примерно раз на несколько тысяч строк. Насколько часто в JSX встречаются кастомные функции? :)
> Вы же в коде на это не жалуетесь.
Потому что код предназначен для другого. Код потому и пишется на тьюринг-полном языке со всякими встроенными свистоперделками, что массив задач, который может решаться при помощи этого кода — очень большой и задачи очень разные. Код шаблона же (или jsx) решает очень узкую задачу (и только одну) — генерация представления дом-дерева (кусков дом-дерева) во вполне конкретном и четко определенном формате.
Это, например, как конечные автоматы. Вы можете написать конечный автомат на любом тьюринг-полном языке (на том же js), но на практике предпочитаете пользоваться узким и специально заточенным языком (регекспами), который специально для описания КА и предназначен.
Конечно, не напишет. Однако, он может сам за меня смержить полный стейт.
> Перепрыгивая все слои абстракции?
Какое перепрыгивание? Рендер — просто ф-я из стейта в дом. Стейт изменился (кнопка нажата) дом перерендерился. Проблема в том, что по дефолту случившиеся эвенты не входят в стейт, в итоге приходится руками создавать кусок локального стейта и обновлять его в коллбеке на эвент. Вместо того, чтобы просто написать event => dom.
> Да нет, ивент выкидывается, а стейт меняется. Это ж реакция.
Сам факт того, что произошел эвент — _уже_ меняет стейт вашего приложения. Кнопка была нажата. По-этому, в принципе, не должно требоваться вводить и менять какой-то _дополнительный_ стейт.
> Один класс генерится, другой его расширяет и добавляет логику.
Я как должен догадаться, что у вас где генерится и чего меняет? Давайте вы уже напишите нормальный код, который будет полон, понятен и который можно будет обсуждать, а не какие-то куски, требующие прокачанного навыка чтения мыслей для понимания?
> Единообразно. Разница лишь в направлении движения. стейт «затягивается», а ивенты (как и любые новые значения) «проталкиваются». На каком-то уровне (от локального, до глобального) «проталкивание» меняет состояние и далее оно уже «затягивается» в обратную сторону.
Вот этот момент (где проталкивание меняет состояние) я и не хочу делать руками. Я хочу, чтобы «проталкивание» могло сразу менять результат рендера, дом.
> Вот же:
В примере выше — другой sub(). Кроме того — непонятно, где меняется само killed. Давайте вы уже целиком рабочий код приведете?
> Ничего там не мержится. «проталкивание» ивента приводит к императивному изменению стейта.
Вот это и есть тот самый «мерж», о котором я говорю. Вы делаете эвент куском стейта, и делаете это _руками_.
В общем, я вижу, что в вашей модели нет единообразия — точно так же вручную вешаются коллбеки на эвенты, эвенты становятся, таким образом, частью локального стейта, а потом уже по локальному стейту генерится дом.
Вы опять уходите в сторону обсуждения принципиальной возможности чего-то, когда на практике важна именно количественная оценка. Следуя вашим рассуждениям — неплохо писать на брейнфаке. Потмоу что по факту любой аргумент против брейнфака применим и к другим языкам. Просто в меньшей степени. Иногда — в намного меньшей :)
> Ну то есть можно так, а можно этак
Ну какбы нельзя :)
И даже если бы было можно — опять возвращаемся к количественной оценке.
> Строки, строки, аттрибуты — строки.
Ну нет. Не будет там нигде строки «let value blablabla»
Значит, чистая функция. В ФП-смысле — без сайд-эффектов, результат зависит только от аргумента.
> Для этого есть язык, и именно поэтому можно (и нужно) и обычные функции мемоизировать в рамках языка и дергать их с тем же успехом.
Это не будет работать внутри шаблонов. И там речь не о мемоизации. Если аргумент не изменился — пайп просто не запускается, а дом не перестраивается. Это внутренность алгоритма чендж-детекшона и «снаружи» такое поведение, фактически, не получить.
Почему не принимаются? И это только один из вариантов. Кроме map могут быть другие варианты преобразования (к списку может быть прихреначен и какой-нибудь фильтр там же, и список может как-то хитро строиться, и map у вас может быть какой-то свой, и вообще это все может быть в похожем на директивы варианты — куча вариантов, в общем).
> Да это-то понятно, просто вот вам и пример, что в этом «строгом DSL» тоже есть несколько путей для реализации.
На самом деле не совсем. Мой вариант со звездочкой неточен, т.к. на самом деле раскроется в:
звездочковый эквивалент тут не написать. Возможно, именно по-этому и выбран рассахаренный вариант :)
> второй — совсем же дичь, всевдокод внутри строки, о боги :)
Он не внутри строки :)
Какая теснота? Смысл пайпов исключительно в том, что они бывают pure, и в этом случае пересчитываются только тогда, когда изменится аргумент. Такого поведения затруднительно достичь, не замусорив код, это надо реализовывать на уровне компилятора шаблонов.
В противном случае (при отсутствии pure) пайпы были бы совершенно не нужны и ничего бы не давали, можно с тем же успехом дергать обычные функции.
Я же говорил — не было бы беды, если бы там ВСЕГДА был map. Но там произвольный js-код. Если ограничить JSX каким-то вменяемым подмножеством JS — он будет вполне ок. Проблема именно в том, что там может использоваться ВЕСЬ JS.
> По идее по ним там выборка какая-нибудь идет через @ContentChildren какой-нибудь.
Но именно атрибуты — ничего не делают, то есть это просто темплейт, в который потом на места let-атрибутов подставляются значения из контекста (контекст применяет уже внешняя директиваб ngx-datatable).
И на самом деле (кстати) это и есть рассахаренный «звездочковый» синтаксис
->
примерно как-то так
Смысл шаблонизатора (как и любого ДСЛя или узкоспециализированного инструмента) ИМЕННО в том, что он ограничен в возможностях. Мы платим универсальностью за более удобное решение задач из узкого класса. Если вы делаете шаблонизатор универсальным — основное преимущество (ограниченность) сразу теряется.
На практике важен не сам факт того, что прогоняем, а как раз то, насколько сложно это и как часто приходится делать :)
> Что там делают эти магические атрибуты, черт знает.
Будете смеяться — но ничего не делает :D
И я, блин, серьезно — правда ничего (в плане перестройки dom-дерева).
А, так вы тип генерика руками записывать собираетесь? я сразу просто это не понял. Непонятно, чем тогда не устраивает вариант navigate(routeFrom(route, params)).
> Отличный ответ. Лично мне ни в каком не удобно.
Непонятно тогда, зачем вы требуете функционал, который вам будет неудобен.
Именно. По-этому ngRepeat значительно проще и удобнее.
Ттак я и говорю о том, что JSX проигрывает шаблонизаторам из-за того, что приходится выполнять в уме JS-код.
Это можно пример такого кода?
> Ну и получается, что с директивами все-равно нужно маркап прогонять в уме
Раз в несколько тысяч строк — нужно. В остальное время — не нужно :)
Это совсем не то, что требуется.
> Там много разных ивентов происходит. Далеко не все из них имеют смысл в моём приложении.
Ну так берите только нужные, какие проблемы?
> Это полный код приложения по ссылке.
Дайте полный код предыдущей задачи, я не знаю, что должен делать код приложения по ссылке.
Конечно, результат. Вы смотрите и видите, какая нода получилась. А потом, увидев ng-repeat, понимаете, что там не одна она такая, а их много. гляда на произвольный js-код в JSX вам надо в уме выполнить этот код, чтобы получить ту информацию, которая вслучае шаблонизатора есть _сразу_.
> Но я ж не знаю, что там скрыто в ней? Придется «выполнить ее в уме» :)
Только вот кастомные структурные директивы встречаются в ангуляре примерно раз на несколько тысяч строк. Насколько часто в JSX встречаются кастомные функции? :)
> Вы же в коде на это не жалуетесь.
Потому что код предназначен для другого. Код потому и пишется на тьюринг-полном языке со всякими встроенными свистоперделками, что массив задач, который может решаться при помощи этого кода — очень большой и задачи очень разные. Код шаблона же (или jsx) решает очень узкую задачу (и только одну) — генерация представления дом-дерева (кусков дом-дерева) во вполне конкретном и четко определенном формате.
Это, например, как конечные автоматы. Вы можете написать конечный автомат на любом тьюринг-полном языке (на том же js), но на практике предпочитаете пользоваться узким и специально заточенным языком (регекспами), который специально для описания КА и предназначен.
Конечно, не напишет. Однако, он может сам за меня смержить полный стейт.
> Перепрыгивая все слои абстракции?
Какое перепрыгивание? Рендер — просто ф-я из стейта в дом. Стейт изменился (кнопка нажата) дом перерендерился. Проблема в том, что по дефолту случившиеся эвенты не входят в стейт, в итоге приходится руками создавать кусок локального стейта и обновлять его в коллбеке на эвент. Вместо того, чтобы просто написать event => dom.
> Да нет, ивент выкидывается, а стейт меняется. Это ж реакция.
Сам факт того, что произошел эвент — _уже_ меняет стейт вашего приложения. Кнопка была нажата. По-этому, в принципе, не должно требоваться вводить и менять какой-то _дополнительный_ стейт.
> Один класс генерится, другой его расширяет и добавляет логику.
Я как должен догадаться, что у вас где генерится и чего меняет? Давайте вы уже напишите нормальный код, который будет полон, понятен и который можно будет обсуждать, а не какие-то куски, требующие прокачанного навыка чтения мыслей для понимания?
Ответ на вопрос-то где? Вот я пишу navigate(route, anyObject), все прекрасно тайпчекается. В чем смысл такого ограничения на типы?
> А где я описываю роут, например, в случае lazyLoad? В каком из двух файлов?
В каком вам удобно, в таком и описывайте.
Вот этот момент (где проталкивание меняет состояние) я и не хочу делать руками. Я хочу, чтобы «проталкивание» могло сразу менять результат рендера, дом.
> Вот же:
В примере выше — другой sub(). Кроме того — непонятно, где меняется само killed. Давайте вы уже целиком рабочий код приведете?
> Ничего там не мержится. «проталкивание» ивента приводит к императивному изменению стейта.
Вот это и есть тот самый «мерж», о котором я говорю. Вы делаете эвент куском стейта, и делаете это _руками_.
В общем, я вижу, что в вашей модели нет единообразия — точно так же вручную вешаются коллбеки на эвенты, эвенты становятся, таким образом, частью локального стейта, а потом уже по локальному стейту генерится дом.