bem / bem-components

Set of components for sites development
https://bem.info/libraries/classic/bem-components/6.0.0/
Other
333 stars 87 forks source link

button_view_link: implement instead of link_pseudo #1635

Closed aristov closed 9 years ago

aristov commented 9 years ago

Link is just link, it shouldn't have button's semantics. We should create semantics from component's behaviour, but not the view. This change can help to reduce logic duplication in the projects codebase. Also this approach more clear form the a11y POV.

This change breaks backward compatibility.

voischev commented 9 years ago

what logic is duplicated? An example?

aristov commented 9 years ago

Any behaviour, that I can implement as button's modifier. When designer draws a pseudo link, which behaviour can be implemented in the same way, I have to duplicate this logic by using link_pseudo. But I wanna use button with already implemented behaviour and just say, that it should be represented as pseudo link by adding _view_link.

For example: not long ago I've noticed, that it's very convenient to learn button to send AJAX requests on click by itself. Simplified code example:

Button.decl({ modName : 'action', modVal : 'request' }, {
    onSetMod : {
        'js' : {
            'inited' : function() {
                this.__base.apply(this, arguments);
                var _this = this;
                this.on('click', function() {
                    $.ajax(this.params)
                        .success(function(result) {
                            _this.emit('success', result);
                        })
                        .error(function(error) {
                            _this.emit('error', error);
                        });
                });
            }
        }
    }
});

Now I can do any request by tuning button_action_request with it's js-params and don't need to write any client-side code, only external block's reaction on success/error events of button. If I have a pseudo link, that should send AJAX request, I have to duplicate this logic by create link_action_request and use it with link_pseudo. I don't wanna to create a third entity, that will implement AJAX request and share it's logic with button and link_pseudo. In my opinion this is redundant entity multiplying. If button can do it by itself, so why should I create something else?

I can imagine more number of useful modifiers for button, example above is just one of them.

awinogradov commented 9 years ago

What about another entity? Ex: request-trigger.

{ block: 'button', mix: { block: `request-trigger`, js: { event: 'click', request: {} } } },
{ block: 'link', mix: { block: `request-trigger`, js: { event: 'hover', request: {} } } },
{ block: 'input', mix: { block: `request-trigger`, js: { event: 'change', request: {} } } }
BEMDOM.decl({ block: 'request-trigger' }, {
    onSetMod : {
        'js' : {
            'inited' : function() {
                var _this = this;
                this.on(js.params.event, function() {
                    $.ajax(this.params.request)
                        .success(function(result) {
                            _this.emit('success', result);
                        })
                        .error(function(error) {
                            _this.emit('error', error);
                        });
                });
            }
        }
    }
});
voischev commented 9 years ago

@awinogradov :fire: :fire_engine:

aristov commented 9 years ago

What about another entity? Ex: request-trigger.

This won't work, because bem-event fires on the instance, not DOM-node of the block. You can not write this.on(event, fn() {}) to subscribe the event of the mixed block. You can parametrize target by js-params and do something like this.findBlockOn(params.target).on(event, fn() {}). But this approach breaks lazy initialization of the target block. Moreover, your request-trigger can not work as lazy block. If you try to make it lazy by using this.liveInitOnBlockEvent in live section, you find out that you can't parametrize target.

awinogradov commented 9 years ago

You can put target block into custom request-trigger param and take block name in the template.

{
    block: 'request-trigger',
    target: {
        block: 'link'
    }
}

this.ctx.js.target = this.ctx.taget.block

aristov commented 9 years ago

js-params are available only for instance of the block. You can not get them from the live section.

aristov commented 9 years ago

Logic duplication example from the codebase:

aristov commented 9 years ago

Discussed and rejected by the core maintainers team.