saralk
saralk

Reputation: 333

Get an Ember Component from the DOM Element

I have an Ember Component as So...

export default Ember.Component.extend({
    didInsertElement: function() {
        this.$().sortable({
            connectWith: '.droppable-box',
            receive: (e, ui) => {

            }
        });
    },
    tagName: 'ul',
    classNames: ['droppable-box', 'list-unstyled']
});

The elements inside the sortable components are also components...

export default Ember.Component.extend({
    tagName: 'li'
});

The receive event is fired whenever a element is moved into a sortable component.

I am given the DOM element, but I want to get access to the instance of that Ember Component. Any ideas?

Upvotes: 1

Views: 1875

Answers (2)

ming_codes
ming_codes

Reputation: 2922

There is a cleaner way to do this, but uses Ember private API.

The root element of the Ember.Component is assigned an id. You can use this id to lookup the component.

// Ember 1.x
Ember.View.views[id]

// Ember 2.x
container.lookup('-view-registry:main')[id]

I do believe there is an instance of the container attached to components.

Upvotes: 1

Dremora
Dremora

Reputation: 167

This is not the cleanest solution, but it should work.

In your child component add the following lifecycle hooks:

//components/child-component.js
...
registerRow: Ember.on('willInsertElement', function () {
  this.attrs.onRegister(this.get('elementId'), this);
}),

unregisterRow: Ember.on('willDestroyElement', function () {
  this.attrs.onUnregister(this.get('elementId'));
}),

In the parent template, pass the action handlers to all child components:

//components/parent-component.hbs
{{#each children as |child|}}
  {{child-component onRegister=(action "registerChild") onUnregister=(action "unregisterChild")}}
{{/each}}

In the parent component, create a dictionary to store child components indexed by their elementId:

//components/parent-component.js
...
children: null,

initChildren: Ember.on('init', function () {
  this.set('children', {});
}),

actions: {
  registerChild(elementId, child) {
    this.children[elementId] = child;
  },

  unregisterChild(elementId) {
    delete this.children[elementId];
  }
}

Now, to access components from your jQuery callback, do:

// Presuming ui is a DOM element
receive: (e, ui) => {
    let component = this.children[ui.id];
}

Upvotes: 4

Related Questions