Angular + Chosen

by rtcherry

HTML

<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<script src="http://code.jquery.com/jquery-1.6.4.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular-resource.min.js"></script>
<script src="http://underscorejs.org/underscore-min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/chosen/0.9.8/chosen.css">
<script src="http://cdn.rawgit.com/harvesthq/chosen/v0.9.1/chosen/chosen.jquery.min.js"></script>
<div ng-controller="TestCntrl">Item: {{item}}
    <br/> <a href="" ng-click="item = undefined">Reset</a>

    <br/>Select:
    <br/>
    <select chosen="list" ng-model="item" ng-options="i for i in list"></select>
</div>

JavaScript

var testApp = angular.module('testApp', []);

testApp.controller('TestCntrl', function ($scope) {
    $scope.list = ['One', 'Two', 'Three'];
    $scope.item = undefined;
});

testApp.directive('chosen', ['$timeout', function ($timeout) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ngModel) {
            var options = scope.$eval(attrs.chosenOptions) || {},
                dataset = attrs.ngOptions.replace(/^.*\sin\s(.*)$/, '$1'),
            refreshFunction = function () {
                var hasNullOption = element.children('*[value = "?"], *[value = ""]').length == 1,
                    numSelectOptions = element.children().length,
                    numChosenOptions = element.next().find('.chzn-results li').length;
                if (numSelectOptions > (hasNullOption ? 1 : 0)) {
                    if (numSelectOptions - (hasNullOption ? 1 : 0) != scope.$eval(dataset).length) {
                        element.trigger("liszt:updated");
                        _.delay(refreshFunction, 50);
                    } else if (numSelectOptions != numChosenOptions) {
                        element.trigger("liszt:updated");
                    }
                } else {
                    _.delay(refreshFunction, 50);
                }
            };

            $timeout(function () {
                element.chosen(options);
                refreshFunction();
            });

            scope.$watch(
            attrs.ngModel,

            function (newValue, oldValue) {
                if (_.isUndefined(oldValue) || _.isUndefined(newValue)) {
                    element.trigger("liszt:updated");
                }
            });

            element.bind('change', function () {
                scope.$apply();
            });

        }
    };
}]);

angular.element(document).ready(function () {
    angular.bootstrap(document, ['testApp']);
});