1
votes

I have a problem with action helper in my ember application. I have a list of items LI in one UL list. List could have various number if items. Items should response on mouse over. The first solution was to add on every item (LI) in the list one mouse enter action like:

<ul>
 {{#each data key="id" as |item|}}
   <li {{action "mouseOverLi" on="mouseEnter"}}>  {{item.description}}</li>
{{/each}}
</ul>

This solution is working but now for every LI tag I have one action, and that is not good solution . So is there any other solution for this. The best will be to add action helper in UL tag with filter on LI children tags.

In other words how one can transform this jQuery code snippet in action helper for Ember:

$("ul").on("mouseover","li",function(){
    // some code.
});
1
"that is not a good solution." Why? Does your code have a performance issue? Premature optimization is the root of all evil. - Gaurav

1 Answers

2
votes

Binding an action to each element is a perfectly fine solution and the standard way of handling that in Ember:

<ul>
   {{#each data key="id" as |item|}}
     <li {{action "mouseOverLi" on="mouseEnter"}}>
       {{item.description}}
     </li>
   {{/each}}
</ul>

It also gives you the added benefit of being able to pass around ember objects as opposed to passing around DOM nodes. For instance:

<ul>
   {{#each data key="id" as |item|}}
     <li {{action "mouseOverLi" on="mouseEnter" item}}>
       {{item.description}}
     </li>
   {{/each}}
</ul>

Then wherever you handle that:

mouseOverLi: function(item){
  item.set("description", "Changed to something different!");
}

I suspect your objection is that we're attaching a lot of event handlers, but it's an old concern that shouldn't be a concern unless you really have a bizarre amount of list items. In which case your performance issue is that you have that many list items in the first place.

Also as far as performance is concerned jQuery doesn't actually reacting to mouseenter, it simply can't because mouseenter only gets triggered once on the ul and not when moving across the sub-elements. So how come https://jsfiddle.net/c8hk6ydn/ works? In jQuery mouseenter is a synthetic event from mouseover, See: https://github.com/jquery/jquery/blob/2792845534e36c39dbb9c8369ed96aaefa560081/src/event.js#L779.

So now if you insist you must have, you'll basically use jQuery like you would otherwise. Since we're doing something non-standard anyways:

App.HoverListComponent = Ember.Component.extend({
  tagName: "ul",
  didInsertElement: function(){
    this.$().on("mouseenter", "li", function(){
      console.log("Whatever you want to do");
    });
  }
});

Then in the template:

{{#hover-list}}
  {{#each data key="id" as |item|}}
    <li>
      {{item.description}}
    </li>
  {{/each}}
{{/hover-list}}

JSBin: http://emberjs.jsbin.com/xiwoqubumo/5/edit?html,css,js,output Or you could try to be more natively ember-like and handle it with mouseOver:

App.HoverListComponent = Ember.Component.extend({
  tagName: "ul",
  mouseMove: function(e){
    // @todo Find the closest 'li' if the LI has 
    // other elements in it.
    // @todo Only fire once per element.
    if(e.toElement.tagName !== 'LI'){
      return;
    }
    $(e.toElement).css("color", "red");
  }
});

But basically my original point stands, when doing Ember.js use the Ember.js way, don't do it like jQuery or you'll end up with really awkward code.