Angularjs Custom select2 directive

后端 未结 5 1874
温柔的废话
温柔的废话 2021-02-04 04:36

I have created simple custom AngularJs directive for this awesome jquery plugin jQuery-Select2 as follows:

Directive

app.directive(\"sel         


        
5条回答
  •  情书的邮戳
    2021-02-04 05:32

    Angular is not going to like have model data modified by a third party plugin. My guess based on the fact that your using $timeout is there is a race condition between Angular updating the options or the model and the select2 plugin. The solution I came up with is to take the updating mostly out of Angular's hands and do it manually from the directive, that way you can ensure everything is matching no matter who is modifying. Here's the directive I came up with:

    app.directive("select2",function($timeout,$parse){
        return {
            restrict: 'AC',
            link: function(scope, element, attrs) {
                var options = [],
                    el = $(element),
                    angularTriggeredChange = false,
                    selectOptions = attrs["selectOptions"].split(" in "),
                    property = selectOptions[0],
                    optionsObject = selectOptions[1];
                // watch for changes to the defining data model
                scope.$watch(optionsObject, function(n, o){
                    var data = [];
                    // format the options for select2 data interface
                    for(var i in n) {
                        var obj = {id: i, text: n[i][property]};
                        data.push(obj);
                    }
                    el.select2({data: data});
                    // keep local copy of given options
                    options = n;
                }, true);
                // watch for changes to the selection data model
                scope.$watch(attrs["selectSelection"], function(n, o) {
                    // select2 is indexed by the array position,
                    // so we iterate to find the right index
                    for(var i in options) {
                        if(options[i][property] === n) {
                            angularTriggeredChange = true;
                            el.val(i).trigger("change");
                        }
                    }
                }, true);
                // Watch for changes to the select UI
                el.select2().on("change", function(e){
                    // if the user triggered the change, let angular know
                    if(!angularTriggeredChange) { 
                        scope.$eval(attrs["selectSelection"]+"='"+options[e.target.value][property]+"'");
                        scope.$digest();
                    }
                    // if angular triggered the change, then nothing to update
                    angularTriggeredChange = false;
                });
    
            }
        };
    });
    

    I've added to attributes select-options and select-model. These will be used to populate and update the data using select2's interface. Here is a sample html:

    
    
    Selected: {{client.primary_address.country}}

    Please note there's still some cleanup that could be done to the directive and there are any things at assumes about the input, such as the "in" in the select-options attribute. It also doesn't enforce the attributes but just fails if they don't exist.

    Also please note that I've used Select2 version 4, as evidenced by the el.val(i).trigger("change"). You may have to revert some things if using an older version.

    Here is the jsfiddle demo of directive in action.

提交回复
热议问题