An approach to use jQuery Plugins with AngularJS


Lets face it, we can not completely get rid of jQuery and its plugins ecosystem, even though Angular has a built-in subset of jQuery under the name jQLite. At one point or another, we often need some sort of jQuery plugins in our application and we can/should not port entire plugin into Angular world in order to use it but we can avoid the plugin initialization code to be scattered across.

How?

Simply by writing a directive for it.

I would like to give you a small demo of Toolbar.js which is a jquery plugin I found recently on geekli.st. This is how we create a tooltip style toolbar in jQuery:

<!-- Click this to see a toolbar -->
<div id="format-toolbar" class="settings-button">
    <img src="http://paulkinzett.github.com/toolbar/img/icon-cog-small.png">
</div>

<!-- Our tooltip style toolbar -->
<div id="format-toolbar-options">
	<a href="#"><i class="icon-align-left"></i></a>
	<a href="#"><i class="icon-align-center"></i></a>
	<a href="#"><i class="icon-align-right"></i></a>
</div>
<!-- Typical jQuery plugin invocation -->
$('#format-toolbar').toolbar({
	content: '#format-toolbar-options', 
	position: 'left'
});

Enter the dragon a.k.a Angular

We’ll keep our markup intact by just adding a custom attribute named `toolbar-tip` – which will be an angular directive we’ll going to write soon. So our markup will change to:

<div id="format-toolbar1" class="settings-button" toolbar-tip="{content: '#format-toolbar-options', position: 'top'}">
	<img src="http://paulkinzett.github.com/toolbar/img/icon-cog-small.png">
</div>

One thing to notice here is that I’ve moved all the options of a toolbar into an HTML so that we can use the same directiv anywhere else with different options/settings.

Finally,

<script>
var App = angular.module('Toolbar', []);

App.directive('toolbarTip', function() {
	return {
		// Restrict it to be an attribute in this case
		restrict: 'A',
		// responsible for registering DOM listeners as well as updating the DOM
		link: function(scope, element, attrs) {
		    $(element).toolbar(scope.$eval(attrs.toolbarTip));
		}
	};
});
</script>

Woohoo! Is not that awesome?? Everything is simple, maintainable and testable!!!

Demo

http://jsfiddle.net/codef0rmer/TH87t/

About these ads

44 thoughts on “An approach to use jQuery Plugins with AngularJS

  1. This is exactly what I’m looking for! Coz I have a navbar that I want to initialize with Twitter Bootstrap’s jquery affix plugin and I have no idea where to enter the initialization code. Initially I thought I’d have to mess with angular config run function.

    This is great stuff.

  2. Pingback: Migration guide for jQuery Developers | codef0rmer

  3. I’ve been using an identical approach myself. I prefer to add the braces for the options in the directive though -> scope.$eval(“{” + attrs.toolbarTip + “}”). The HTML looks a bit tidier that way.

    Also, if you’re already referencing jQuery in your solution, make sure you’re loading it before AngularJS. This way Angular will pick up that jQuery is present. So now instead of “$(element).toolbar(scope.$eval(attrs.toolbarTip));” you can write “element.toolbar(scope.$eval(attrs.toolbarTip));” as element will already be a jQuery object.

    Also, your JSFiddle is currently broken. Here is a working one:
    http://jsfiddle.net/gavinfoley/TH87t/57/

  4. This is an interesting example. I did not previously realize that the camel case directive name (in this case toolbarTip, is mapped to the dashed attribute toolbar-tip in the HTML. Took me a while to figure out that was happening. Kind of makes sense but not very obvious.

    • Yeah that was intentionally done by Angular Team because in javascript we can not use hyphenated function name whereas in html we can use camelcase tag/attribute name but is not valid html.

      • Sorry again, but for me it’s extremely surprising that the author of a book about Angular JS, writes something so wrong like that. “was intentionally done by Angular Team because in javascript we can not use hyphenated function name”. It is wrong and to test it is sufficient to open the browser console and try. JavaScript does support function names with hyphens and even spaces, they just need to be called by name! o[“some_crazy Name”] = function () { console.log(“Hello”); }. I know already that most probably my comments won’t pass moderation. Kind Regards, Roberto

      • Hi Roberto, thanks for your comments. Your assumption is correct that we can use hyphenated name for functions but only being object properties. That means you can not define function foo-bar() {} in JavaScript. What I meant by those statements in the post is that angular expects directive definition as a constructor which supposed to be newed.

  5. App.directive(‘toolbarTip’

    and

    <div toolbar-tip…

    Should not it be the exactly same string?

    I am a newbie on angular, i need to understand everything.

    Thanks

    • No because thats how angular works! As per HTML spec, the attribute should be hyphenated but javascript does not support hyphenated variable/function name and hence angular team has decided to use hyphens while declaring and camelcase while defining a directive.

    • Hi, thanks for the reply and not taking bad my comments. But still, when you define in an HTML template for Angular to call a given function, that function must be defined in the scope. Nothing would disallow to define a function in the scope “with-hyphens” in its name. It is Angular JS that doesn’t support this – and not JavaScript -, because during its expression parsing, it tries to perform a mathematical operation when finding a “-” sign. Angular makes the assumption that if it finds a “-“, then some maths is involved. I just verified this by debugging inside Angular.

  6. Pingback: Using a jQuery Plugin (flipclock) in an angular.js application | Technology & Programming

  7. Pingback: Correct way to integrate Jquery plugins in Angular.js | Technology & Programming

  8. Pingback: Création de la directive "scrollable" | Angular-js.fr

  9. Pingback: future of Jquery | DiscVentionsTech

  10. How would you handle the toolbar item´s click events? Seems that the plugin replace/move the html whenever its called so you cannot use ngcllicks on em.

    • @insane, It’s very rare that you need angular event handlers in jQuery plugins. In this particular example, the toolbar’s click event is handled by the jQuery plugin itself – angular directive just creating a wrapper around it to help us use it declaratively in angular.

  11. Hi,
    I have some problem with angularJs + Jquery Steps Plugin.
    The problem is after implementing Jquery steps as directive , ng-model seems to be not working. Can any one tell me what I am missing? Do I need to do some extra stuff to make data binding work again??

  12. Hi , thanks for the article. I am not able to figure out how to create a directive to initialize a jQuery iviewer – the jQuery code is as follows

    $(“#viewer2″).iviewer(
    {
    src: “test_image2.jpg”,
    zoom_min:’100′,
    zoom_max:’400′
    });

    and i have just made a angular skeleton but don’t know what to do next

    var vm = angular.module(‘vModule’,[]);
    vm.directive(‘vModuleConfig’,function(){
    return {
    restrict:’A’,
    link:function(scope,element,attrs){
    }

    }
    });

    Can you please help. Thanks

    • Hi Gaurav,

      I’m not sure about your requirement but by looking at your code, you are almost there. Just move $('#viewer2')... code into the link method, replace $('#viewer2') with element, and apply the directive on <div id="viewer2" v-module-config></div>

  13. Pingback: Convert jquery plugin into directive angular | FYTRO SPORTS

  14. Pingback: Correct way to integrate Jquery plugins in Angular.js - TecHub

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s