AngularJS two-way data-binding on jQuery Select2
Edit this page on GitHub
As we all know, the <select> and <option> tag can provide dropdown for selecting. However, no one would call that user-friendly and you probably won’t see those dropdown on any website nowadays. A way to do better is to use jQuery select2, it will provide a more user-friendly dropdown.
If we want to use jQuery select2 dropdown in a AngularJS directive to do more complicated stuffs, there seems to be some problems. It seems the two-way data-binding is not working properly. Please take a look at my JSFiddle on a simple example.
By the way, it is sarcastic that the IFrame from JSFiddle is using the dumb dropdown.
As you can see from the code above, the simple angularJS application has a fancy dropdown (thanks to jQuery and Erick Mendoza), and the option selected is binding to ng-model of the app. However, there is another button that yells “click me” that will change the ng-model programmatically to option 4.
Problem and Solution
As first I thought since they are two-way-binded, if I click on the “click me” button, the jQuery dropdown should also reflect the change and switch to option 4. It turned out I’m wrong. You can even check the code in a debugger mode, that the ng-model has changed to ‘key 4’, which is the key of ‘option 4’ after I click the button. The problem is that jQuery select2 don’t know it and won’t re-render the UI, which means the two-way-data-binding failed in this situation.
So, instead, I choose to add a watcher inside the directive on ng-model. If the ng-model change, I set the jQuery dropdown to select the new value. Please take a look at the new JSFiddle example, which works perfectly fine. If you click the ‘click me’ button, the dropdown will be set to option 4.
Amazing tut.
For some reason, I had to add the following shim in my requirejs config to get this to work, as I kept on getting select2 is undefined even though I’ve required it in my app …
angular: { deps: [‘select2’], exports: ‘angular’ },
Error was occuring here:
element.select2({ width: scope.selectWidth, });
element.select2({ width: scope.selectWidth }).select(‘val’, newValue);