How to get a component's instance from within an eventManager object


#1

When I have a component with an eventManager how can I get the instance of the component from within a handler?

The handler’s second parameter contains only the component clicked on, which can be a nested component. When I define the handler directly on the component ‘this’ points to the component. In the eventManager it points to the eventManger.

I’d like to use the eventManager because it puts all handlers neatly in one place and passes the component from which the event originated. Is there a good solution to this problem?


#2

Someone correct me if I’m wrong, but I believe this explicitly goes against the principles of Ember. Normally, components are responsible for handling their events, and encapsulation implies no code outside of the component should be aware of the component’s DOM, including the events it generates.

I think the fact that eventManager is called with the component as second argument is a historical oddity, from when controller+view were the thing, and I would not be surprised it gets removed at some point (though there are no plans to do so I am aware of atm).

Question: why don’t you use the normal workflow of actions instead? Do you have some more details on what you are trying to accomplish? There might be a better way than fiddling with eventManager.


#3

I’m not sure we are talking about the same thing. I’m looking for a way to access the component from within the handler function that is defined the component’s eventManager. By your own words this doesn’t break encapsulation.

What I’m trying to do is to handle certain events originating from the component’s DOM and then call some method on the component. This works with event handlers defined directly on the component by accessing this.

By the way, I just cross-posted this to stackoverflow.


#4

Oh, you mean, accessing the very component in which you put you eventManager? I had misunderstood then, I thought you wanted to access the sub-components.

Question then: why do you want to use an eventManager? Usually you just put your event handlers on the component itself.


#5

Exactly!

A (very) clunky workaround I thought about would be to set the eventManager object in the willInsertElement hook where we do have access to the component instance through this. We could then simply pass it to the eventManager.

But I’m thinking there must be a better solution.


#6

A bit less clunky would be to do it in the init method. But, the whole thing seems a bit ugly anyway. The thing is, if you define your eventManager in the normal way, it will be shared by all instances of your component. So setting the component on it will not work.

That means you would need to create a new eventManager manually.

export default Ember.Component.extend({
    init: function () {
        set(this, 'eventManager', Ember.Object.create({
            component: this,
            click: function (evt) { }
        }));
        this._super();
    }
});

Or maybe put it outside the component:

var Manager = Ember.Object.extend({
    click: function (evt) {}
});

export default Ember.Component.extend({
    init: function () {
        set(this, 'eventManager', Manager.create({component: this}));
        this._super();
    }
});

I doubt the result ends up being as neat as you expected it to be. And if you opt for that last approach, you might as well just use a mixin instead.

var Events = Ember.Mixin.create({
    click: function (evt) {}
});

export default Ember.Component.extend(Events, {
});

#7

I also noticed that the eventManager would be part of the prototype. Ember would have to pass the component as an additional parameter to the handlers for this to work.

But I really like your solutions, especially the one with the mixin! Good way to structure the code. Thanks for your help!