Здравствуйте, подскажите пожалуйста по следующией конструкции bemhtml. Элементу item, из условия необходимо добавить произвольный класс. Но не могу понять доступную конструкцию обрабатываемого элемента. Вызывается ошибка "TypeError: string is not a function" Пробовал item.cls()('my-class') и item.ctx.cls()('my-class') и this.. Но кажется что-то я совсем не то делаю.
this.ctx.items.forEach(function(item){
var sub = [],
num = 0;
if(item.items != null){
item.cls()('my-class');
item.items.forEach(function(subItem, i){
sub.push({
elem: 'sub-item',
content: {
elem: 'link',
url: subItem.url,
content: [subItem.text]
}
});
});
}
...
})
Внутри вашего forEach не надо использовать bemhtml конструкции. Укажите поле cls прямо в bemjson элемента
sub-item
Может просто переопределить моду cls у нужного айтема?
сразу в bemjson определить клас к сожалению не получится, т.к. ctx в bemhtml переопределяется и затирает cls из bemjson.
Тут я пытаюсь реализовать типичный блок навигации в шапке, через шаблоны. Взяв за основу пример из руководства про модификаторы: https://github.com/bem/bem-js-tutorial/tree/master/pure.bundles/006-before-set-mod
вот полная версия моего bemhtml:
bemjson:
ну наверное придется пока отказаться подобной сложности из-за нехватки опыта с bemhtml =) сделаю просто в bemjson и стилями. К тому же сразу не заметил, такой подход добавлял ненужные вложенные элементы elem('sub-menu').
не могу понять, зачем понадобилось задавать кастомный класс через
cls
?по мелочи: вместо
можно просто
@Bumerang47 под bemjson я имел ввиду не файл, а кусок bemjson с элементом sub-item который пушится в коде вашего шаблона. Теперь когда я повнимательнее изучил ваш фрагмент за компом, поясню.
item.cls()('my-class');
не работает, потому что в переменнойitem
находится кусок исходного bemjson соответсвующего этомуitem
. Если я правильно понял, то вы зачем то хотите установить кастомный класс для элемента 'item' у которого есть подпункты. Этого можно достичь следующими способами:И правильным, который я сейчас напишу отдельным постом. А вообще хотелось бы услышать ответ на вопрос @veged.
UPD: исправил
Второй вариант, обрабатывать дерево в отдельных шаблонах. Получилось приблизительно так (код не проверял, но должен передать общую идею о принципе):
До сих пор, правда остался небольшой копипаст и в целом шаблон сложно воспринимать.
Вообще данные шаблоны лучше разделить на шаблоны в bemtree и bemhtml. В первых обходить исходное дерево блока nav и генерировать соответсвующие элементы блока в bemjson. А на bemhtml останется непосредственное превращение bemjson в ожидаемый html.
Я делал обход подобной структуры в своём компоненте только на
BH
, а неBEMHTML
. Получилось тоже довольно громоздко, т.к. не используются плюсы двухпроходной шаблонизации.Совсем скоро я его переделаю на bemtree + bemhtml.
Спасибо за ответы, сейчас изучу, протестирую код подробней.
По поводу вопроса @veged, хочу добавить, как верно предположил @Guria, для элемента 'item' у которого есть подпункты стиль, выделяющий его среди прочих подпунктов.
@Bumerang47 Если я правильно понял кейс, то такой класс правильнее задавать через модификатор. Свойство
cls
существует для гибкости и, если хотите, математической полноты, но используется крайне редко, в случаях, когда нет возможности использовать модификаторы или миксы — например, для работы с какими-то плагинами, которые используют кастомные классы, и которые нет возможности поправить. В общем случае использованиеcls
не рекомендуется, как и изменять DOM напрямую.@zxqfox, верно подметили. Миксы и модификаторы скорее больше подойдут, пробовал их применять, написал про cls, т.к. он был как последняя попытка, более грубого приёма. =\ Думаю от этого суть не сильно изменится, если получиться назначить cls, можно будет заменить на mix?
@veged, спасибо за подсказки "по мелочи", это важно :)
@Guria, первый метод про
item.cls = 'my-class'; sub.push({
результата не дает, класс не добавляется. Судя по всему т.к. в этом блоке суть в переменной sub, которая потом через json подставляется в контент ко всем item.Концепт второго варианта мне очень понравился, попробую его развить. Сейчас этот код вызвал ошибку "AssertionError: mode literal predicates can't have arguments", к моему стыду пока не могу понять почему. Подобная проблема была когда контент не был обернут в функцию, но тут везде как надо.
@Bumerang47 Да, суть, как раз, останется той же, но появится некоторый простор для маневра. Кастомные классы сильно сложнее шаблонизировать, сложнее слушать их изменения, и пр. пр.
@Bumerang47 в моём примере ошибка в использовании cls. Надо заменить на:
cls()('my-class')
. А лучше на соответствующие mods или mix.@Guria cls()('my-class') не решили ошибку, если речь о втором примере. Ошибку вызывает что-то тут кажется (могу ошибаться):
у меня главный вопрос — зачем вообще городить всё это с преобразованием кастомного json в БЭМ-термины? почему бы просто не написать примерно так:
и дальше простые шаблоны, без всякого ада с
applyCtx
и подменами какими-то не прозрачнымиесли говорить, почему не работает
applyCtx(this.ctx.items.forEach(function(item){
, то потому, что вapplyCtx
нужно передавать новый контекст, а функцияforEach
ничего такого не возвращает — нужно её заменить наmap
(во втором использованииthis.ctx.items.forEach
тоже)@veged откровенно говоря до меня после нескольких постов этой темы дошло, что тут попахивает избыточным подходом. Да и компонент я делал на основе примера из руководства, задачи которых немного разные. Хотя нагородив в шаблоне bemhtml, можно минимизировать код в файле.bemjson, удобно для быстого конфигурирования блока в будущем на других проектах... но это не было конечно целью и притянуто за уши. Так что вы скорее правы :)
@Bumerang47 Он же дедушка @veged, конечно он прав ;-)