Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS chosen plugin, chosen:updated not working, works in browser

I have integrated the chosen plugin into my angularjs app. My app.js looks like this.

myApp.directive('chosen', function() {

    var linker = function (scope, element, attr) {
        scope.$watch('countriesList', function() {
            $('#countries').trigger('chosen:updated');
            console.log('I acctuallty get in here');
        })
        element.chosen();
    };

    return {
        restrict: 'A',
        link: linker
    };
})

my select looks like this

<div class="control-group">
  <label for ="countries" class="control-label">Countries: </label>
  <div class="controls">
    <select chosen ng-model="countries" id="countries" ng-options="country.name for country in countriesList"  data-placeholder="Select Countries" multiple class="span chzn-select"></select>  
  </div>
</div>

The problem is when the page first loads nothing is displayed in the select. The options are there when you inspect element.

The chosen:updated just doesn't seem to work. I put the console.log() in the watch and it is firing. If I run the .trigger('chosen:updated') in the browser it works perfectly. I did try element.trigger but that did not work either. So Frustrating!

like image 316
Alex Turnbull Avatar asked Jan 18 '15 20:01

Alex Turnbull


1 Answers

You need to let Angular (well the browser actually) render the select properly before calling chosen. You can do this by using setTimeout or Angular's $timeout.

app.directive('chosen', function($timeout) {

  var linker = function(scope, element, attr) {

    $timeout(function () {
      element.chosen();
    }, 0, false);
  };

  return {
    restrict: 'A',
    link: linker
  };
});

The third argument false prevents an unnecessary digest loop.

Demo: http://plnkr.co/edit/9Afq65uatTjnb4J6ICcB?p=preview

If you need to add or remove items dynamically this will work:

app.directive('chosen', function($timeout) {

  var linker = function(scope, element, attr) {

    scope.$watch('countriesList', function() {
      $timeout(function() {
        element.trigger('chosen:updated');
      }, 0, false);
    }, true);

    $timeout(function() {
      element.chosen();
    }, 0, false);
  };

  return {
    restrict: 'A',
    link: linker
  };
});

Demo: http://plnkr.co/edit/rEBu6d3HtaNhThWidB5h?p=preview

Note that by default $watch uses reference equality to determine if to execute the listener or not. If you add an item to the array the variable countriesList will still refer to the same array, so the listener will not execute.

The third argument true passed to $watch makes it use angular.equals instead of reference equality.

like image 183
tasseKATT Avatar answered Sep 21 '22 02:09

tasseKATT