kalpesh patel kalpesh patel - 25 days ago 9
AngularJS Question

Angularjs Custom select2 directive

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

Directive

app.directive("select2",function($timeout,$parse){
return {
restrict: 'AC',
link: function(scope, element, attrs) {
$timeout(function() {
$(element).select2();
},200);
}
};
});


Usage in HTML templates:

<select class="form-control" select2 name="country"
data-ng-model="client.primary_address.country"
ng-options="c.name as c.name for c in client.countries">
<option value="">Select Country</option>
</select>


It is working as expected and my normal
select
element is replaced by
select2
plugins.

However there is one issue though, sometimes it is showing default value i.e
Select Country
here although in dropdown proper model value is auto selected.

Now if I increase
$timeout
interval from
200
to some high value say
1500
, it is working but delays the the rendering of directive. Also I think this is not proper solution for it, as my data is getting loaded via ajax.

I have also tried to update directive as follows, but no luck in that either:

app.directive("select2",function($timeout,$parse){
return {
restrict: 'AC',
require: 'ngModel',
link: function(scope, element, attrs) {
var modelAccessor = $parse(attrs.ngModel);
$timeout(function() {
$(element).select2();
});
scope.$watch(modelAccessor, function (val) {
if(val) {
$(element).select2("val",val);
}
});
}
};
});


PS: I know that there is similar module present ui-select, but it requires some different markup in form of
<ui-select></ui-select>
, and my App is already fully developed and I just want to replace normal select box with select2.

So can you please guide me how can I resolve this issue and make sure that directive keeps in sync with latest behaviour?

Answer

It might be simpler than you expected!

Please have a look at this Plunker

Basically, all plugins, Angularjs $watch need to be based on something. I'm not 100% sure for jQuery-select2; but I think that's just the control's normal DOM events. (And in the case of Angular $watch, it is a "dirty checking loop")

My idea is that let's trust jquery-Select2 and AngularJS for handling those change events.

We just need to watch for change in Angular's ways and update the select in Select2's ways

var refreshSelect = function() {
    if (!element.select2Initialized) return;
    $timeout(function() {
        element.trigger('change');
    });
};

//...

scope.$watch(attrs.ngModel, refreshSelect);

Notice: I have added in 2 new watch which I think you would like to have!

Comments