Comments 42
двусторонняя связь с input-ами различных типов (text, checkbox, radio);
css-атрибута;
css-классы;
модификаторы;
и другое.
А если надо элемент целиком удалять из DOM-дерева (и добавлять обратно потом)?
0
Есть html-биндинг — можно вставлять целые куски html-кода в определенный DOM-элемент. Если речь не об этом, то опишите задачу подробнее.
+2
Вот кусочек из реального проекта, задача — убирать кнопку из DOM-дерева, если девайс нельзя отключить. Сделано на rivets.js.
<button rv-if="device:CanBeRemoved" class="btn-del js-deleteDevice">✖</button>
+1
Могу предложить вот такой вариант. У вас в модели есть некое поле flag, которое отвечает за наличие DOM-элемента в дереве.
В модель добавляем вычисляемое поле:
А во view добавляем биндинг:
В модель добавляем вычисляемое поле:
computeds: {
template: {
deps: ['flag'],
get: function (flag) {
return flag ? '<button rv-if="device:CanBeRemoved" class="btn-del js-deleteDevice">✖</button>' : '';
}
}
}
А во view добавляем биндинг:
bindings: {
'.some-wrapper': {
html: 'model.template'
}
}
0
Я понял. Пихать кусок верстки в модель как-то не очень хочется, если честно…
+1
Да, не спорю, это просто пример для наглядности. Но вы можете хранить верстку, где вам удобно, а в js ее получать с помощью require.js, например.
+1
Ну все равно получается, что мы в модели храним ссылку на верстку:)
0
Вы всегда можете вызвать метод, который сгенерирует/вернет вам вёрстку необходимого элемента, в этом нет ничего зазорного. Тем самым и не «ссылка на вёрстку» и вполне себе изящное решение. Но вообще, в подобных случаях, обычно либо просто скрывают/показывают элемент, либо пользуются методикой, аналогичной предложенной мной.
0
А если вам нужно просто прятать элемент в зависимости от состояния флага, то просто добавляете toggle-биндинг:
bindings: {
'.js-deleteDevice': {
toggle: 'model.flag'
}
}
+4
Иногда нужно именно убирать (если верстка зависит от :nth-child селекторов, например).
Вот я вижу у вас есть toggle-биндинг, есть text и есть html — а насколько легко добавить свой? В упомянутом rivets.js тоже есть встроенные (там они называются байндеры), и легко можно добавить свой — примерно для таких вот случаев.
Вот я вижу у вас есть toggle-биндинг, есть text и есть html — а насколько легко добавить свой? В упомянутом rivets.js тоже есть встроенные (там они называются байндеры), и легко можно добавить свой — примерно для таких вот случаев.
0
Добавление своих типов биндингов в самых ближайших планах.
+1
Добавил возможность определения своих типов биндингов. Документация будет позже, а пока просто приведу пример:
Если до появления документации возникнут вопросы, обращайтесь.
Backbone.Ribs.View.extend({
bindings: {
'.bind-text': {
textCustom: 'model.text'
},
'.bind-css': {
cssCustom: {
'color': 'model.color',
'font-weight': 'model.weight'
}
},
},
handlers = {
textCustom: function ($el, value) {
$el.text(value);
},
cssCustom: {
set: function ($el, value, key) {
$el.css(key, value);
},
multiple: true
}
}
})
Если до появления документации возникнут вопросы, обращайтесь.
+1
А вообще штука очень клевая, мне нравится.
+4
backbone это конструктор с разделением концепций. ближайший аналог можно приготовить из backbone-nested и backbone-computedfields для моделей, а так же backbone.stickit для вьюх.
0
А backbone-computedfields нормально работает с backbone-nested? Из моего опыта — не все и не всегда можно безболезненно подружить без манки-патчинга.
+1
смотрите сами jsfiddle.net/n7Sfp/. backbone-nested обеспечивает полную обратную совместимость со стандартными моделями backbone, а backbone-computedfields просто аккуратная надстройка над моделями.
0
Ясно. Спасибо, что сделали фиддл:)
0
мне не сложно. вот пример со stikit — jsfiddle.net/n7Sfp/2/ :)
+1
Выбор за вами. Использовать три библиотеки, которые придется еще стыковать друг с другом, или одну, в которой все это связано из коробки.
0
хорошие библиотеки Backbone стыкуются между собой практически без швов. мне кажется, что в этой магии вся соль экологии Backbone — что качественно выделяет его среди других. имхо, конечно.
+1
Скажем так. Если нет серьёзных оснований что-то делать цельным большим комком вместо кучки раздельных модулей — всегда лучше делать несколько мелких модулей (ибо проще писать, поддерживать, и увеличивается гибкость). Понятно, что «выбор за нами», но от Вас, как от автора цельного решения, хочется услышать несколько более аргументированный ответ: в чём именно сложности стыковки конкретно этих трёх библиотек или какие преимущества даёт реализация этой функциональности цельным куском (которые невозможно или слишком сложно или очень медленно реализуются при использовании отдельных библиотек).
+1
Вот простейший пример того, что создатели разных библиотек могут относиться к одним и тем же вещам по-разному. К примеру, {silent: true}:
jsfiddle.net/n7Sfp/3/
backbone-nested — проигнорировал {silent: true}
backbone-computedfields — отреагировал на {silent: true} правильно
Такая, казалось бы, мелочь в большом сложном проекта обойдется очень дорого. А если копнуть глубже, то я найду еще примеры «стыковки без швов».
jsfiddle.net/n7Sfp/3/
backbone-nested — проигнорировал {silent: true}
backbone-computedfields — отреагировал на {silent: true} правильно
Такая, казалось бы, мелочь в большом сложном проекта обойдется очень дорого. А если копнуть глубже, то я найду еще примеры «стыковки без швов».
+2
По-моему в данном примере всё происходит абсолютно правильно. А чего конкретно Вы ожидали от nested — чтобы он не сработал и вместо установки значения для model.attributes.profile.email установилось значение для model.attributes['profile.email']? {silent:true} блокирует отправку события, а не «всё ломает». Событие не было отправлено. computedfields работает на событиях, поэтому он не «отреагировал правильно» а просто не сработал. На мой взгляд — всё ведёт себя корректно и предсказуемо.
А как в аналогичных условиях отреагирует ribs.js?
А как в аналогичных условиях отреагирует ribs.js?
0
А Вас не смущает, что одни биндинг обновился, а другой нет? Такое поведение ну никак не подходит под «корректно и предсказуемо».
В ribs.js при set-е с {silent: true} ни один биндинг не обновится.
При обычном set-е, соответственно, обновятся оба биндинга.
В ribs.js при set-е с {silent: true} ни один биндинг не обновится.
При обычном set-е, соответственно, обновятся оба биндинга.
0
А, я понял о чём Вы. Но ведь дело вовсе не в {silent:true}! Поменяйте местами model.set и view.render — и оба биндинга не обновятся, как Вы и хотели.
А так получается, что Вы сначала явным {silent:true} рассинхронизируете обычные и вычисляемые поля, потом рендерите модель в этом состоянии, а потом почему-то обвиняете биндинги — которые вообще в этом процессе пока никак не участвовали.
А так получается, что Вы сначала явным {silent:true} рассинхронизируете обычные и вычисляемые поля, потом рендерите модель в этом состоянии, а потом почему-то обвиняете биндинги — которые вообще в этом процессе пока никак не участвовали.
0
рассинхронизируете обычные и вычисляемые поля
А вот этого быть не должно! Вычисляемое поле должно обновиться не зависимо от флага {silent: true}. А иначе вы получаете неконсистентную модель, и из этого вытекают нюансы, когда дергать render и др.
0
Вычисляемое поле должно обновиться не зависимо от флага {silent: true}.С какой стати? Есть базовая функциональность Backbone — она работает всегда. Есть много разной дополнительной функциональности — предоставляемой плагинами Backbone или реализованной в самом приложении — которая обычно работает на событиях Backbone. В официальной документации по поводу {silent:true} сказано предельно чётко:
Note that this is rarely, perhaps even never, a good idea.Что логично, т.к. обычно это сломает вышеупомянутую дополнительную функциональность.
И получается, что (если я Вас правильно понял) Вы утверждаете, что бывает разные виды этой дополнительной функциональности: которые должны ломаться при {silent:true} (плагины второго сорта), и которые не должны ломаться при {silent:true} (плагины первого сорта). Вот это как раз и вносит совершенно лишние нюансы, непредсказуемость и неконсистентность поведения.
Если я передаю {silent:true} я хочу, чтобы отработала только базовая функциональность Backbone — а иначе зачем бы мне это вообще делать? И я не думаю, что плагины вроде Ribs.js должны считать меня идиотом и игнорировать {silent:true} только потому, что им кажется что я бы этого хотел. Вообще, пытаться защищать пользователя от стрельбы себе в ногу имеет смысл на некоторых языках, но Javascript, Perl и им подобные к ним никак не относятся.
Ещё какие-то примеры проблем вызванных стыковкой nested, computedfields и stickit есть?
0
Давайте захватим цитату чуть раньше:
Если я передаю {silent:true}, я хочу, чтобы не было триггера событий и ничего больше. Ни о какой базовой и дополнительной функциональности речи не идет. Этот флаг нужен исключительно для этого. Если приведенный пример для Вас является нормой, и это ровно то поведение, которое вы ожидаете, то мне нечего добавить. Я считаю такое поведение неправильным и неприемлемым.
И я не разделяю библиотеки на сорта и уж тем более не считаю никого идиотом. У нас с Вами разные взгляды на вещи, и я предлагаю остаться каждому при своем мнении, и закончить эту исчерпавшую себя дискуссию.
if you'd like to prevent the event from being triggered, you may pass {silent: true} as an option.
Если я передаю {silent:true}, я хочу, чтобы не было триггера событий и ничего больше. Ни о какой базовой и дополнительной функциональности речи не идет. Этот флаг нужен исключительно для этого. Если приведенный пример для Вас является нормой, и это ровно то поведение, которое вы ожидаете, то мне нечего добавить. Я считаю такое поведение неправильным и неприемлемым.
И я не разделяю библиотеки на сорта и уж тем более не считаю никого идиотом. У нас с Вами разные взгляды на вещи, и я предлагаю остаться каждому при своем мнении, и закончить эту исчерпавшую себя дискуссию.
0
Если я передаю {silent:true}, я хочу, чтобы не было триггера событий и ничего больше.Вам не кажется, что это звучит бессмысленно? События сами по себе ничего не меняют, и никто не отключает события ради самого отключения событий. Их отключают для того, чтобы не запустились обработчики событий — т.е. чтобы не сработала та самая дополнительная функциональность, о которой я говорил.
Я считаю такое поведение неправильным и неприемлемым.Понятно. Я согласен, что у нас разные взгляды и что продолжать дискуссию смысла нет — Вы абсолютно в своём праве делать так, как считаете правильным. Но я бы хотел обратить Ваше внимание на то, что по сути Ваш подход нарушает базовый принцип Backbone:
Philosophically, Backbone is an attempt to discover the minimal set of data-structuring (models and collections) and user interface (views and URLs) primitives that are generally useful when building web applications with JavaScript. In an ecosystem where overarching, decides-everything-for-you frameworks are commonplace, and many libraries require your site to be reorganized to suit their look, feel, and default behavior — Backbone should continue to be a tool that gives you the freedom to design the full experience of your web application.Приняв решение, что в Ribs.js целостность данных важнее свободы пользователя заблокировать функциональность Ribs.js явно передав {silent:true} Вы двинулись по вышеупомянутому пути «decides-everything-for-you». Это абсолютно нормально если Вы делаете полноценный высокоуровневый фреймворк поверх Backbone, но, на мой взгляд, является ошибкой в случае разработки плагина к Backbone — потому что плагин в первую очередь должен вести себя предсказуемо и единообразно — так, как большинство остальных плагинов.
0
Здравствуйте, powerman.
Вот Вы пишите:
А как тогда быть с тем фактом, что бекбон самостоятельно поддерживает целостность данных?
Простой пример: пусть у нас есть коллекция col с 5ю моделями.
События добавления в коллекцию не произошли, но бекбон не смотря на переданную инструкцию {silent:true} сохраняет целостность коллекции.
Так что подход ZaValera никак не идет в разрез с концепцией бекбона.
Get вычисляемых полей должен по сути всегда забирать их зависимости и вычислять правильные значения — это логичное и понятное поведение. Не только лишь в Ribs, но и в упомянутом в статье Epoxy.
{silent: true} на get никак не влияет — что в модели лежит, то мы и получим.
В Ribs, как я понял, для того, чтобы по много раз при get'е вычисляемых полей не обсчитывать одно и тоже, они вычисляются один раз при set'е их зависимостей. Что логично с точки зрения оптимизации.
P.S. Вообще я с трудом представляю практический смысл в неконсистентых вычисляемых полях. Равно как не вижу в чем Ribs ограничивает меня как разработчика.
Вот Вы пишите:
Приняв решение, что в Ribs.js целостность данных важнее свободы пользователя заблокировать функциональность Ribs.js явно передав {silent:true} Вы двинулись по вышеупомянутому пути «decides-everything-for-you».
А как тогда быть с тем фактом, что бекбон самостоятельно поддерживает целостность данных?
Простой пример: пусть у нас есть коллекция col с 5ю моделями.
console.log(col.length); // 5
col.add({foo:'bar'}, {silent: true});
console.log(col.length); // 6
События добавления в коллекцию не произошли, но бекбон не смотря на переданную инструкцию {silent:true} сохраняет целостность коллекции.
Так что подход ZaValera никак не идет в разрез с концепцией бекбона.
Get вычисляемых полей должен по сути всегда забирать их зависимости и вычислять правильные значения — это логичное и понятное поведение. Не только лишь в Ribs, но и в упомянутом в статье Epoxy.
{silent: true} на get никак не влияет — что в модели лежит, то мы и получим.
В Ribs, как я понял, для того, чтобы по много раз при get'е вычисляемых полей не обсчитывать одно и тоже, они вычисляются один раз при set'е их зависимостей. Что логично с точки зрения оптимизации.
P.S. Вообще я с трудом представляю практический смысл в неконсистентых вычисляемых полях. Равно как не вижу в чем Ribs ограничивает меня как разработчика.
+1
Вообще я с трудом представляю практический смысл в неконсистентых вычисляемых полях.Никто этого смысла не видит — потому что его нет. Как и в том, чтобы передавать {silent:true}. Изначально я попросил ZaValera привести причину, по которой вместо трёх простых маленьких плагинов сделан один большой цельный — он привёл единственный пример с {silent:true} — на мой взгляд не особо адекватный пример, т.к. не понятно кому и зачем нужно будет использовать {silent:true}, но тем не менее пример имеет право на жизнь (тем более, что других примеров нет). Поэтому мы и обсуждаем неконсистентность вычисляемых полей.
Равно как не вижу в чем Ribs ограничивает меня как разработчика.Он ограничивает в том, что пытается решать за разработчика что тот хотел получить в результате {silent:true} — возможно в большинстве случаев он угадает и разработчик будет счастлив, но что делать в оставшихся случаях? Backbone хорош именно тем, что не накладывает никаких ограничений и даёт возможность стоить поверх себя абсолютно любую архитектуру. Как правило нет никакого смысла передавать {silent:true}, о чём говорит и официальная дока, но если всё-таки передали — ожидается, что это заблокирует выполнение всех обработчиков события 'change:' (в нашем примере), а не всех кроме вычисляемых полей ribs.js.
События добавления в коллекцию не произошли, но … Так что подход ZaValera никак не идет в разрез с концепцией бекбона.По этой логике {silent:true} не должен иметь вообще никакого эффекта — всё должно работать не зависимо от того, произошли события или нет. Или не всё, а только некоторые «критичные» плагины — я об этом уже писал выше, про плагины первого и второго сорта.
0
Никто этого смысла не видит — потому что его нет. Как и в том, чтобы передавать {silent:true}
Если нет смысла в неконсистентых вычисляемых полях, то зачем ожидать их неконсистентности при передаче {silent:true}?
он привёл единственный пример с {silent:true} — на мой взгляд не особо адекватный пример, т.к. не понятно кому и зачем нужно будет использовать {silent:true}
Пример ZaValera более чем адекватный — неоднократно сталкивался в рабочих задачах с необходимостью провести несколько «тихих» пакетных изменений в куче моделей (в случае с множеством подписок на change, которые, например, меняют сильно DOM). После, конечно же, руками триггерились нужные события/вызывались нужные методы. Т.е. я хочу привести в пример задачу по оптимизации.
По этой логике {silent:true} не должен иметь вообще никакого эффекта — всё должно работать не зависимо от того, произошли события или нет. Или не всё, а только некоторые «критичные» плагины — я об этом уже писал выше, про плагины первого и второго сорта.
Так про то и речь, что silent:true — не инструмент для блокирования какой-то «дополнительной» функциональности, а просто режим, в котором не триггерятся события.
Он ограничивает в том, что пытается решать за разработчика что тот хотел получить в результате {silent:true} — возможно в большинстве случаев он угадает и разработчик будет счастлив, но что делать в оставшихся случаях? Backbone хорош именно тем, что не накладывает никаких ограничений и даёт возможность стоить поверх себя абсолютно любую архитектуру. Как правило нет никакого смысла передавать {silent:true}, о чём говорит и официальная дока, но если всё-таки передали — ожидается, что это заблокирует выполнение всех обработчиков события 'change:' (в нашем примере), а не всех кроме вычисляемых полей ribs.js.
Просто Вы воспринимаете вычисляемые поля как механизм, связанный с подписками на события. В то время они таковым не являются. И следовательно никак не должны зависеть от {silent:true}.
Если же мыслить не в контексте «основная и дополнительная» функциональность, а в контексте Ribs.js, то все очень стройно.
И да, Вы всегда можете описать вычисление каких-то атрибутов модели самостоятельно через подписки, так что {silent:true} не будет их менять. Или используете механизм Ribs, с иным поведением. Т.е. у Вас есть выбор. Так что скорее тут не ограничение, а расширение возможностей разработчика.
+1
Просто Вы воспринимаете вычисляемые поля как механизм, связанный с подписками на события. В то время они таковым не являются.Отлично, мы потихоньку подбираемся к сути вопроса. А почему, собственно, не являются? Кто решает, какие механизмы (реализованные через подписки на события!) считать связанными с подписками, а какие нет?
0
А с чего Вы решили, что механизм вычисляемых полей в Ribs реализован через подписки на события?
Я, как автор библиотеки, решаю какие механизмы я буду реализовывать и КАК я их буду реализовывать.
Кто решает, какие механизмы (реализованные через подписки на события!) считать связанными с подписками, а какие нет?
Я, как автор библиотеки, решаю какие механизмы я буду реализовывать и КАК я их буду реализовывать.
0
Очевидно, что разработчик решает и предлагает Вам свой подход. Вы можете с ним согласиться и использовать инструмент, а можете не согласиться и не использовать. Все очень просто. :)
0
неоднократно сталкивался в рабочих задачах с необходимостью провести несколько «тихих» пакетных изменений в куче моделей (в случае с множеством подписок на change, которые, например, меняют сильно DOM). После, конечно же, руками триггерились нужные события/вызывались нужные методы.Кстати, а почему Вы решили не делать так, как рекомендует Backbone?
Passing through a specific flag in the options for your event callback to look at, and choose to ignore, will usually work out better.
0
{silent: true} отличный инструмент, которой прекрасно справляется со своими задачами. Да, в неумелых руках он может привести к нежелательным последствиям, поэтому разработчики Backbone об этом предупреждают. Зачем мне придумывать лишние флаги, когда это уже заложено в Backbone. А на поздних этапах разработки, когда подписчиков уже достаточное количество, вводить новый флаг и его обработку крайне затратное мероприятие.
0
И в итоге получился canjs
+1
И прелесть в том, что именно расширяет, а не изменяет. Вы можете использовать ваш любимый Backbone, как и прежде, но по необходимости задействовать новые возможности:
Я не встречал ни одной библиотеки для Backbone, которая поступает иначе. Перекрывать возможности этого фреймворка, имхо, кощунство.
+1
Sign up to leave a comment.
Ribs.js — вложенные атрибуты, вычисляемые поля и биндинги для Backbone.js