Saturday, February 2, 2013

JQuery: the Angular way - Selectmenu


Yesterday I was presented with a challenge: how to use the selectmenu plugin by Felix Nagel in an angularjs application.
The angular way with jQuery plugins is to create an angular directive wrapping this plugin and then apply this directive to the tag this plugin should be applied to. Something to the effect of:


<select select-menu>
   <option value="...">...</option>
</select>

for the HTML and

.directive(

  "selectMenu"
  [ '$log',
    (console) ->
      {
        link: (scope, element, attrs, ctrl) ->
            $(element).selectmenu()
      }
    ])


for the directive definition in CoffeScript. For plugins relaying just on the HTML tag they are attached to, this approach works just fine. It will work fine for the selectmenu plugin as well as long as the html, including the nested option tags is static.

But as soon as you try to the list of option dynamic, like:

<select select-menu>
   <option ng-repeat="option in options" value="...">...</option>
</select>

it no longer works, the list of options will show up empty. The reason is that the selectmenu method is called too early. The ng-repeat is yet to do its magic and the real list of options object does not exist yet. 

The solution to this problem is simple: invite the Option tag to the party. Create another directive and apply it to every option. When this directive is linked it should modify the parent select to reflect that a new option just has been added: 

.directive(
  "selectOption"
  [ '$log'
    (console) ->
      {
        link: (scope, element, attrs, ctrl) ->
          $(scope.select).selectmenu() 
      }
    ])

The way it works is that right after the new option tag is added to the DOM, the link method is called and the selectmenu plugin documentation recoomends calling selectmenu method again as a way to update the list of options.

This would be the end of the story, but there was one more thing. It turns out that it is still too early. The option tag has been added but the value of the text is not evaluated yet. I had to do it myself using the $interpolate function. This was the last touch. You can see the result here

No comments:

Post a Comment