bem-site / bem-forum-content-ru

Content BEM forum for Russian speak users
MIT License
56 stars 6 forks source link

Установка модификаторов для блока и i-bem.js #792

Closed godfreyd closed 8 years ago

godfreyd commented 8 years ago

Всем привет! Такой вопрос, если я делаю так:

provide(BEMDOM.decl(this.name, {
onSetMod : {
    'js' : {
        'inited' : function() {

            this.setMod('calling');

        }

    },
    'calling' : function() {

     }

   }
}));

, то у меня все работает, но если я прописываю модификатор mods : { calling : true }, в bemjson файле и оставляю так:

provide(BEMDOM.decl(this.name, {
onSetMod : {
    'calling' : function() {

     }

   }
}));

работать перестает. Почему? (Полный код не привожу, думаю смысл понятен).

qfox commented 8 years ago

Потому что onSetMod отрабатывает только при установке модификатора. Если установка была в bemjson — считается, что он уже установлен. При инициализации не происходит установки, хотя для меня это тоже странно, почему работает именно так.

Хотелось бы отдельно обсудить какие плюсы и минусы есть у безусловной установки. Возможно, стоит подумать об изменении поведения в этом месте.

/cc @veged @tadatuta

godfreyd commented 8 years ago

Жаль, хотел разделить действие одного блока, разбив его по модификаторам (если внутри родительского блока вложен блок link, один модификатор, если вложен button, то другой, если checkbox - третий). Теперь, наверное, придется условные выражения писать.

tadatuta commented 8 years ago

Возможно, стоит подумать об изменении поведения в этом месте.

@zxqfox Обсуждали несколько раз. Думаю, в недрах форума можно даже какие-то артефакты найти.

хотел разделить действие одного блока, разбив его по модификаторам (если внутри родительского блока вложен блок link, один модификатор, если вложен button, то другой, если checkbox - третий)

@Sergei-b84 можно в зависимости от модификатора по-разному определять кастомный метод init, который вызывать на onSetMod -> js -> inited. Это решает задачу?

qfox commented 8 years ago

@tadatuta Ради людей-то можно и еще раз обсудить, чтобы они в будущем не натыкались. Правда же?)

tadatuta commented 8 years ago

Процитирую @veged из закромов родины:

мы всегда подразумевали, что для лучшего пользовательского экспириенса нужно минимизировать инициализацию и присылать блок сразу в нужном состоянии — в каком-то смысле это требует реализации одной и той же логики в динамическом переключении модификаторов и в шаблонах, но это же ради блага

ну да, что-то в этом есть — давайте вы сделаете тикет на https://github.com/bem/bem-core/issues, а мы с Димой ещё раз подумаем, что можно сделать

До issue, вроде, дело тогда так и не дошло, но, насколько я понимаю, такое поведение едва ли может появиться до какого-нибудь реактивного bem-core@v4.

qfox commented 8 years ago

Соглашусь, что это мажорное изменение, да.

Давайте молиться, чтобы у нас появилось свободное время ;-)

godfreyd commented 8 years ago

@Sergei-b84 можно в зависимости от модификатора по-разному определять кастомный метод init, который вызывать на onSetMod -> js -> inited. Это решает задачу?

Думаю, что не решит. Ранее мы с Вами обсуждали блок tooltip. который привязывали к ссылке (блок link). Теперь же у меня добавились еще блоки chekbox и button. В будущем возможно еще что-то добавится. В связи с чем, я хотел расширить возможности блока tooltip, вешая на него такие модификаторы (link: true, checkbox: true, button: true ..). И расписать код tooltip.js

modules.define('tooltip', ['i-bem__dom'], function(provide, BEMDOM) {
provide(BEMDOM.decl(this.name, {
onSetMod : {
    'link': {
        'true': function() {

            var link = this.findBlockInside('link'),
                popup = this.findBlockInside('popup')
                    .setAnchor(link);

            link.on({ modName: 'hovered', modVal: '*' }, function() {
                popup.toggleMod('visible');
            });

        }

    },
    'button': {
        'true': function() {

            ....

        }

    },
    'checkbox': {
        'true': function() {

            ....

        }

        }

    }
}));

});
tadatuta commented 8 years ago

@Sergei-b84 Вроде это не противоречит тому решению, которое я предложил:

// tooltip.js

modules.define('tooltip', ['i-bem__dom'], function(provide, BEMDOM) {

provide(BEMDOM.decl(this.name, {
    onSetMod: {
        js: {
            inited: function() {
                this.init();
            }
        }
    },
    init: function() { throw new Error('Модификатор target является обязательным!'); }
}));

});

// tooltip_target_link.js
modules.define('tooltip', function(provide, Tooltip) {

provide(Tooltip.decl({ block: this.name, modName: 'target', modVal: 'link' }, {
    init: function() {
        var link = this.findBlockInside('link'),
            popup = this.findBlockInside('popup')
                .setAnchor(link);

        link.on({ modName: 'hovered', modVal: '*' }, function() {
            popup.toggleMod('visible');
        });
    }
}));

});

// tooltip_target_button.js
modules.define('tooltip', function(provide, Tooltip) {

provide(Tooltip.decl({ block: this.name, modName: 'target', modVal: 'button' }, {
    init: function() {
        var button = this.findBlockInside('button'),
            popup = this.findBlockInside('popup')
                .setAnchor(button);

        button.on({ modName: 'hovered', modVal: '*' }, function() {
            popup.toggleMod('visible');
        });
    }
}));

});

Другое дело, что если других отличий не будет, то это можно сократить до одного общего кода:

modules.define('tooltip', ['i-bem__dom'], function(provide, BEMDOM) {

provide(BEMDOM.decl(this.name, {
    onSetMod: {
        js: {
            inited: function() {
                var control = this.findBlockInside(this.getMod('target')),
                    popup = this.findBlockInside('popup')
                        .setAnchor(control);

                control.on({ modName: 'hovered', modVal: '*' }, function() {
                    popup.toggleMod('visible');
                });
            }
        }
    }
}));

});

Либо можно воспользоваться тем фактом, что все перечисленные блоки наследуются от control, так что достаточно повесить событие на него вместо link и должно работать ровно как в исходном варианте, вообще без модификаторов.