A few months back I received a design that used the iCheck plugin to implement radio button lists with customised styles. The controls look really nice! Now to use it in our Angular application...
I hooked up the radio buttons as per the normal AngularJS way, added the iCheck init function call into my controller, and promptly ran into trouble. When the checking the checkbox, the scope variable no longer changed.
Here is a fiddle that demonstrates the problem: http://jsfiddle.net/BerzerkNinja/84Lpjd8w/
As you can see from the fiddle, setting the radio’s ng-model has no effect on the iCheck control, but it works as we would expect on the regular radio buttons. So what’s going on?
The problem is that iCheck has its own check/uncheck events, and in order to check a radio button you have to call $('input').iCheck('check'). Angular relies on setting a scope variable in the ng-model of the radio input. Some questions come to mind. Do I really have to call $(“.my-radio”).iCheck(‘check’)? Do I really have to instantiate the jQuery plugin from within my controller?
The answers are no and no - the solution to our problem is to wrap the jQuery control up in an Angular directive. We use the directive to encapsulate the initialisation of the iCheck control and to provide a mechanism to bridge the gap between iCheck’s check/uncheck events and the updating of the AngularJS scope.
Here is an example fiddle of the solution: http://jsfiddle.net/BerzerkNinja/pjcnx58n/
As in the fiddle, the directive instantiates the iCheck control. This means we have shifted the instantiation and configuration out of our controller and into the new directive.
We then use the directive to bridge the gap between Angular and iCheck. We set a watch on the radio’s ng-model, and update iCheck when the model changes. We also subscribe to iCheck’s ‘ifChanged’ event and update the model when iCheck’s radio changes. This ensures both libraries work together.
By putting the jQuery related code within a directive, we now have a clean controller (no jQuery within it, as is recommended at https://docs.angularjs.org/misc/faq#faq_common-pitfalls). We have also bridged the gap between iCheck’s checked/unchecked status and AngularJS scope variable and have a working solution.