AngularJS Directives with jQuery Plugins
AngularJS directives are very powerful, but first time it looks quite tricky on how to set them up with jQuery plugins. Let's say we want to add the spectrum jQuery color picker on our form using a directive. Here's how we could make that with an isolate scope and two way data binding:
var app = angular.module('app', []);
app.directive('colorPicker', function() {
return {
scope: {
color: "="
},
link: function(scope, elm, attrs) {
elm.spectrum({
color: scope.color,
change: function(color) {
scope.$apply(function() {
scope.color = color.toHexString();
});
}
});
scope.$watch('color', function(newColor) {
elm.spectrum('set', newColor);
});
}
};
});
Here we're listening for the color picker change event to update the data
when user chooses a new one. Note that you have to use
$apply
here
because event is being triggered from outside of angular framework.
On the other hand we're watching for
external data changes with angular
$watch
to update the color picker value.
Usually in such cases it's better to use ngModel
with NgModelController
instead of isolate scope and two way data binding,
since it also provides a validation behavior for our input:
var app = angular.module('app', []);
app.directive('colorPicker', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ngModel) {
elm.spectrum({
color: ngModel.$viewValue,
change: function(color) {
scope.$apply(function() {
ngModel.$setViewValue(color.toHexString());
});
}
});
ngModel.$render = function() {
elm.spectrum('set', ngModel.$viewValue || '');
};
}
};
});
Now we can check if the form is valid and show a proper validation error etc. In this example
the text input value won't be updated and submit button will be disabled
until we select the white color. Note that we
cannot use
isolate scope with ngModel
directive.
Finally imagine we want to reuse this directive somewhere else, but it needs a different options for jQuery plugin:
var app = angular.module('app', []);
app.directive('colorPicker', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ngModel) {
var options = angular.extend({
color: ngModel.$viewValue,
change: function(color) {
scope.$apply(function() {
ngModel.$setViewValue(color.toHexString());
});
}
}, scope.$eval(attrs.colorPicker));
ngModel.$render = function() {
elm.spectrum('set', ngModel.$viewValue || '');
};
elm.spectrum(options);
}
};
});
Now we can set an additional plugin
options in the colorPicker
attribute like this:
<input color-picker="{showInput: true}">
. Notice how they are getting extended
with angular.extend
.