How Do I target a components childView?


#1

I want to be able to properly target a nested component from its parent component. I can do this using jquery, but it is fragile. using Jquery I would something like this

define([“ember”], function(Ember) { return Ember.Component.extend({ … updateSectionDislpay: function() { var element, currentSectionId, currentSectionNavElement; element = this.get(‘element’); currentSectionId = this.get(‘currentSectionId’); currentSectionNavElement = $(element).find(’.section-navigation-item’).eq(currentSectionId);

  $(element).find('.section-navigation-item').removeClass('selected');
  $(currentSectionNavElement).addClass('selected');
}.observes('currentPageId')

}); });

Is there a proper Ember way to target the child components element from the parent component?


#2

What I’ve done, since the parent component is constructed first, is add a listener to the parent via jQuery for an event the child components will raise (or separate events raised by the child components’ didInsertElement and willDestroyElement hooks), and manually manage a collection of the desired child components.

For example, in the parent hook:

didInsertElement: function() {
	this._super();
	// Listen for child panes via jQuery.
	this.$().on('childPaneAdded', function(event, child) {
		event.stopPropagation();
		child.set('parentPane', this);
		this.get('childPanes').addObject(child);
	}.bind(this));
}

And in the child hook:

didInsertElement: function() {
	this._super();
	run.scheduleOnce('afterRender', this, function() {
		// Notify enclosing layout pane.
		this.$().parent().trigger('childPaneAdded', this);
	});
},

Similar idea for removing items.


#4

This solution seems like it could work, the only question remaining is, how do I how when all of the child views are done rendering?


#5

In the example above, the child schedules “afterRender” to register with its parent, and this is in the didInsertElement hook, so the child should certainly be built and added to the DOM by the time the parent hears about it. If there is additional set-up in the child that may take further time to finish, you could either defer raising the childAdded event until then, or (if the parent should know it has children pending) raise childAdded immediately, and add a property like fullyLoaded to the child, so the parent can wait for all children to become fully ready.

Unfortunately the Ember API doesn’t give computed.everyBy which would be perfect here, but you can accomplish a computed property in a few lines that waits for all children to be ready.