<!DOCTYPE html>
<html>

  <head>
    <script data-require="jquery@2.0.3" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
    <link data-require="select2@3.4.5" data-semver="3.4.5" rel="stylesheet" href="//cdn.jsdelivr.net/select2/3.4.5/select2.css" />
    <script data-require="select2@3.4.5" data-semver="3.4.5" src="//cdn.jsdelivr.net/select2/3.4.5/select2.min.js"></script>
    <script data-require="lodash.js@2.4.1" data-semver="2.4.1" src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
    <script data-require="angular.js@1.1.5" data-semver="1.1.5" src="http://code.angularjs.org/1.1.5/angular.js"></script>
    <script data-semver="0.0.5" src="ui-select2.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app="myApp" ng-controller="AppController">
      <pre>{{eEntity.tags|json}}</pre>
  
    <select-multiple ng-model="eEntity.tags" transform-to-model="transformToModel" transform-to-view="transformToView"/>
    <small>hint: start to type with  a</small>

    
  </body>

</html>
// Code goes here

angular.module('myApp', ['ui.select2'])

.directive('selectMultiple', function() {
    return {
        restrict: 'E',
        require: ['ngModel'],
        replace: true,
        scope: true,
        template: '<input type="hidden" ui-select2="select2Options" class="form-element" style="width: 200px" />',
        controller: ['$scope', '$attrs',
            function($scope, $attrs) {
                var options = [{
                    text: '案件名1',
                    id: 1
                }, {
                    text: '案件名2',
                    id: 2
                }, {
                    text: '案件名2',
                    id: 3
                }, ];
                
                $scope.enums = {};
                angular.forEach(options, function(option, key){
                     $scope.enums[option.id] = option.text;
                });

                $scope.select2Options = {
                    data: options,
                    multiple: true,
                    minimumInputLength: 1,
                    formatResult: function(item) {
                        
                        return item.text;
                    },
                    formatSelection: function(item) {
                        return item.text;
                    },
                };
                
                $scope.transformToModel = $scope.$eval($attrs.transformToModel);
                $scope.transformToView = $scope.$eval($attrs.transformToView);
            }
        ],
        link: function(scope, element, attrs, ctrl) {

            ctrl[0].$formatters.push(function(modelValue){
                console.log('modelValue',modelValue);
                if(modelValue){
                    var viewValue = [];
                    angular.forEach(modelValue, function(value, key){
                        var viewItemValue = value;
                        if(scope.transformToView){
                            viewItemValue = scope.transformToView(value, scope.enums);
                        }
                        if(viewItemValue){
                            viewValue.push(viewItemValue);    
                        }
                    });
                    return viewValue;
                }
                return [];
            });
            ctrl[0].$parsers.push(function(viewValue) {
                //console.log('viewValue', viewValue);
                if (viewValue) {
                    var modelValue = [];
                    angular.forEach(viewValue, function(value, key) {
                        var modelItemValue = value;
                        if(scope.transformToModel){
                            modelItemValue = scope.transformToModel(value);
                        }
                        console.log('modelItemValue',modelItemValue);
                        if(modelItemValue){
                            modelValue.push(modelItemValue);    
                        }
                    });
                    return modelValue;
                }
                return [];
            });
        }
    }
})

.controller('AppController', function($scope) {
    $scope.eEntity = {
        tags: [
            { "code": 1}
            ]
    };
   
   $scope.transformToModel = function(viewItem){
       if(viewItem && viewItem.id){
           console.log('viewItem',viewItem);
           return { code: viewItem.id };    
       }
       return undefined;
   };
   
   $scope.transformToView = function(modelItem, enums){
       console.log('modelItem',modelItem);
       if(modelItem){
           return { id: modelItem.code, text: enums[modelItem.code] }  
       }
       return undefined;
   };
   
});
/* Styles go here */

/**
 * Enhanced Select2 Dropmenus
 *
 * @AJAX Mode - When in this mode, your value will be an object (or array of objects) of the data used by Select2
 *     This change is so that you do not have to do an additional query yourself on top of Select2's own query
 * @params [options] {object} The configuration options passed to $.fn.select2(). Refer to the documentation
 */
angular.module('ui.select2', []).value('uiSelect2Config', {}).directive('uiSelect2', ['uiSelect2Config', '$timeout', function (uiSelect2Config, $timeout) {
  var options = {};
  if (uiSelect2Config) {
    angular.extend(options, uiSelect2Config);
  }
  return {
    require: 'ngModel',
    priority: 1,
    compile: function (tElm, tAttrs) {
      var watch,
        repeatOption,
        repeatAttr,
        isSelect = tElm.is('select'),
        isMultiple = angular.isDefined(tAttrs.multiple);

      // Enable watching of the options dataset if in use
      if (tElm.is('select')) {
        repeatOption = tElm.find('option[ng-repeat], option[data-ng-repeat]');

        if (repeatOption.length) {
          repeatAttr = repeatOption.attr('ng-repeat') || repeatOption.attr('data-ng-repeat');
          watch = jQuery.trim(repeatAttr.split('|')[0]).split(' ').pop();
        }
      }

      return function (scope, elm, attrs, controller) {
        // instance-specific options
        var opts = angular.extend({}, options, scope.$eval(attrs.uiSelect2));

        /*
        Convert from Select2 view-model to Angular view-model.
        */
        var convertToAngularModel = function(select2_data) {
          var model;
          if (opts.simple_tags) {
            model = [];
            angular.forEach(select2_data, function(value, index) {
              model.push(value.id);
            });
          } else {
            model = select2_data;
          }
          return model;
        };

        /*
        Convert from Angular view-model to Select2 view-model.
        */
        var convertToSelect2Model = function(angular_data) {
          var model = [];
          if (!angular_data) {
            return model;
          }

          if (opts.simple_tags) {
            model = [];
            angular.forEach(
              angular_data,
              function(value, index) {
                model.push({'id': value, 'text': value});
              });
          } else {
            model = angular_data;
          }
          return model;
        };

        if (isSelect) {
          // Use <select multiple> instead
          delete opts.multiple;
          delete opts.initSelection;
        } else if (isMultiple) {
          opts.multiple = true;
        }

        if (controller) {
          // Watch the model for programmatic changes
           scope.$watch(tAttrs.ngModel, function(current, old) {
            if (!current) {
              return;
            }
            if (current === old) {
              return;
            }
            controller.$render();
          }, true);
          controller.$render = function () {
            if (isSelect) {
              elm.select2('val', controller.$viewValue);
            } else {
              if (opts.multiple) {
                var viewValue = controller.$viewValue;
                if (angular.isString(viewValue)) {
                  viewValue = viewValue.split(',');
                }
                elm.select2(
                  'data', convertToSelect2Model(viewValue));
              } else {
                if (angular.isObject(controller.$viewValue)) {
                  elm.select2('data', controller.$viewValue);
                } else if (!controller.$viewValue) {
                  elm.select2('data', null);
                } else {
                  elm.select2('val', controller.$viewValue);
                }
              }
            }
          };

          // Watch the options dataset for changes
          if (watch) {
            scope.$watch(watch, function (newVal, oldVal, scope) {
              if (angular.equals(newVal, oldVal)) {
                return;
              }
              // Delayed so that the options have time to be rendered
              $timeout(function () {
                elm.select2('val', controller.$viewValue);
                // Refresh angular to remove the superfluous option
                elm.trigger('change');
                if(newVal && !oldVal && controller.$setPristine) {
                  controller.$setPristine(true);
                }
              });
            });
          }

          // Update valid and dirty statuses
          controller.$parsers.push(function (value) {
            var div = elm.prev();
            div
              .toggleClass('ng-invalid', !controller.$valid)
              .toggleClass('ng-valid', controller.$valid)
              .toggleClass('ng-invalid-required', !controller.$valid)
              .toggleClass('ng-valid-required', controller.$valid)
              .toggleClass('ng-dirty', controller.$dirty)
              .toggleClass('ng-pristine', controller.$pristine);
            return value;
          });

          if (!isSelect) {
            // Set the view and model value and update the angular template manually for the ajax/multiple select2.
            elm.bind("change", function (e) {
              e.stopImmediatePropagation();
              
              if (scope.$$phase || scope.$root.$$phase) {
                return;
              }
              scope.$apply(function () {
                controller.$setViewValue(
                  convertToAngularModel(elm.select2('data')));
              });
            });

            if (opts.initSelection) {
              var initSelection = opts.initSelection;
              opts.initSelection = function (element, callback) {
                initSelection(element, function (value) {
                  var isPristine = controller.$pristine;
                  controller.$setViewValue(convertToAngularModel(value));
                  callback(value);
                  if (isPristine) {
                    controller.$setPristine();
                  }
                  elm.prev().toggleClass('ng-pristine', controller.$pristine);
                });
              };
            }
          }
        }

        elm.bind("$destroy", function() {
          elm.select2("destroy");
        });

        attrs.$observe('disabled', function (value) {
          elm.select2('enable', !value);
        });

        attrs.$observe('readonly', function (value) {
          elm.select2('readonly', !!value);
        });

        if (attrs.ngMultiple) {
          scope.$watch(attrs.ngMultiple, function(newVal) {
            attrs.$set('multiple', !!newVal);
            elm.select2(opts);
          });
        }

        // Initialize the plugin late so that the injected DOM does not disrupt the template compiler
        $timeout(function () {
          elm.select2(opts);

          // Set initial value - I'm not sure about this but it seems to need to be there
          elm.val(controller.$viewValue);
          // important!
          controller.$render();

          // Not sure if I should just check for !isSelect OR if I should check for 'tags' key
          if (!opts.initSelection && !isSelect) {
            controller.$setViewValue(
              convertToAngularModel(elm.select2('data'))
            );
          }
        });
      };
    }
  };
}]);