Migration guide for jQuery Developers


There are couple of links explaining AngularJS to jQuery developers and my effort also goes to do the same. This post is dedicated to all the jQuery developers who wish to know AngularJS before they dive in. I myself worked on jQuery since a very long time and literally its hard to switch to something which is radically different and way cooler than jQuery (sorry, darling!).

Document is Ready?

We all know about $(document).ready() or $(window).load() methods to setup a safe wrapper around the code to make sure that everything runs after the DOM is loaded.
Also, you might have used literal styled javascript with jQuery:

var App = {
  run: function() {
    var bootstrapper = 'You have successfully bootstrapped jQuery';
    $('div.alert').html(bootstrapper);
  }
};

// Finally I'll call the main method
$(document).ready(function() {
  App.run();
});

Do not panick! Angular itself provides the manual bootstrapping the same way. Angular advocates modularity so that every piece of an application should have its own module and there is a main module that holds rest of the modules together. The subsequent code defines the main module (similar to jQuery example above) and run() block is the built-in (sort of) main method in Angular which runs once the application is bootstrapped.

  // Define a module, App
  var App = angular.module('App', []);

  // Built-in run method
  App.run(function($rootScope) {
    $rootScope.bootstrapper = 'You have successfully bootstrapped AngularJS';        
  });

  // Finally bootstrap angular manually
  angular.element(document).ready(function() {
    angular.bootstrap(document, ['App']);

    // Target an element instead
    // angular.bootstrap(jQuery('body'), ['App']);
  });

The one thing to notice here is $rootScope – which is a global variable you can bind properties to that can be injected in other modules for further use.

Finally we’ll use angular’s templating syntax {{ }} to declaratively place data into the markup instead of grabbing the element explicitly like jQuery. Can you see?

<div class="alert alert-success">{{bootstrapper}}</div>

In case you are not a fan (like me) of manual bootstrapping, you can make it automatic as well by setting ng-app directive on any element such as html, body etc. Angular looks for an element having ng-app on it and uses it as a target during bootstrapping. Now you do not need angular.element(document).ready() block as defined above.

<html ng-app="App">

XHR

AJAX is the second most important thing people use jQuery for. jQuery provides different methods to fire up an XHR call.

In angular, there is $http service which is a wrapper around the browser’s XMLHttpRequest object that returns promises .then(), .success(), and .error() based on the request was successful or failed.

The only difference is that you have to manually inject it into the module definition. Suppose I want it inside the run() block we’d seen before:

  App.run(function($rootScope, $http) {
    $http.get('foobar.php').success(function(data, status) {
      // I succedded
    }).error(function(data, status) {
      // I failed
    });
  });

Do not touch the DOM

jQuery was made to do so, Angular is not!

In AngularJS, try to avoid touching DOM implicitly as much as possible so that you can fully leverage the 2-way data binding between your data and the DOM. We are going on journey to build a process order page using following directives.

ng-model

In jQuery, .val() is a setter/getter method to interact with form controls which was quite amazing but it gets worst when you want to show the value elsewhere instantly, means we had to bind keypress events on the input control that will update the DOM as expected. But its too much effort as well as code for such a small task.

Angular provides a neat directive to rule them all. Always use ng-model in order to read values out of form controls. You do not have to manually select an element to set/get its value – Just play with plain old javascript object/array.

<input type="text" ng-model="name">
App.run(function($rootScope) {
  // setting the default value for the input
  $rootScope.name = 'AngularJS';

  // this will return the existing value of the input
  // console.log($rootScope.name);
});

ng-options

Use to lay out options based on model for select element. Know more about it.

App.run(function($rootScope) {
  $rootScope.cities = [
    {id: 'NM', name: 'Navi Mumbai'},
    {id: 'PN', name: 'Pune'}
  ];
});
<select ng-model="city" ng-options="c.name for c in cities"></select>

ng-class

Toggle CSS classes based on expression. This is a very common thing in jQuery:

if (same) {
  $('small').removeClass('strike');  
} else {
  $('small').addClass('strike');
}

In angular, you can use ng-class directive to apply CSS classes conditionally. If same is boolean true then apply strike class. Otherwise remove it.

<small ng-class="{'strike': !same}">same as billing</small>

ng-disabled

Similar to ng-class, you can disable/enable form controls using ng-disabled directive.
In jQuery,

$('[ng-model="shipping_name"]').prop('disabled', same);

In angular,

<input ng-disabled="same" 
       type="text" 
       ng-model="shipping_name" 
       placeholder="Full Name">

ng-change

You may want to reflect your billing address as shipping address instantly.
In jQuery,

<input onkeypress="$('[ng-model="shipping_name"]').val($('[ng-model="billing_name"]').val());" 
       type="text" 
       ng-model="billing_name"> 

In Angular,

<input ng-change="reflect()" type="text" ng-model="billing_name">
$rootScope.reflect = function() {
  $rootScope.shipping_name = $rootScope.billing_name;
  $rootScope.shipping_address = $rootScope.billing_address;
  $rootScope.shipping_city = $rootScope.billing_city;
};

ng-click

In jQuery,

$('div.btn-primary').click(function() {
  processed = true;
});

In Angular,

<button class='btn btn-primary' ng-click="processed = true">Process Order</button>

ng-show/ng-hide

This is again very common thing in jQuery to show/hide elements based on conditions.
In jQuery,

if (processed) {
  $('div.alert').show();
} else {
  $('div.alert').hide();
}

In Angular,

<div class="alert alert-success" ng-hide='!processed'>
  <b>Well done!</b> We've successfully processed the order.
</div>

Here is the Final Demo of our Process Order form using all above directives.

Loading partials

Many of us often create a separate header and footer partials to be injected into many pages instead of repeating all over again.
In jQuery,

<body>
    <div id='header'></div>
    <script type="text/javascript">
      $('#header').load('header.html');
    </script>

    <!-- Body -->

    <div id='footer'></div>
    <script type="text/javascript">
      $('#footer').load('footer.html');
    </script>    
</body>

In Angular, ng-include works similar to jquery.load but also allows to compile and include an external HTML fragment. Do not forget to wrap your html fragment in single quotes as I’ve already wasted an hour to figure that out šŸ˜¦

<body>
    <div ng-include="'header.html'"></div>

    <!-- Body -->

    <div ng-include="'footer.html'"></div>
</body>

History – page navigation

Take an example of a simple addressbook application that contains 3 links shown below and div.abPanel is the place where you would wish to load the appropriate template.

<div class='cell abLinks'>
    <a href='javascript:void(0);' id='addNewContact'>Add New Contact</a><br />
    <a href='javascript:void(0);' id='listContacts'>List all Contact</a><br />
    <a href='javascript:void(0);' id='searchContacts'>Search any Contact</a><br />
</div>
<div class='cell abPanel'>Loading... Please Wait.</div>

In jQuery, you would probably do this.

$('#addNewContact').click(function () {
  $('div.abPanel').load('add_new_contact.html', function () {
    // do all DOM manipulations or event bindings here
  });
});

In Angular, we’ll use awesome $routeProvider service without writing much boilerplate code. This simply loads a template based on hash.

App.config(function ($routeProvider) {
  $routeProvider
    .when('/add', { templateUrl: 'partials/add.html' })
    .when('/list', { templateUrl: 'partials/list.html' })
    .when('/search', { templateUrl: 'partials/search.html' })
    .otherwise({
      redirectTo: '/add'
    });
});

And finally change above links a little bit to:

<div class='cell abLinks'>
    <a href='#/add'>Add New Contact</a><br />
    <a href='#/list'>List all Contact</a><br />
    <a href='#/search'>Search any Contact</a><br />
</div>
<div ng-view>Loading... Please Wait.</div>

The one thing to notice here is ng-view directive that lets your render the template of the current route automagically.

Animation

The .animate() method allows us to create animation effects in jQuery. In order to fade out the process order page while hiding, we can write something like this:

$('div.row').animate({opacity: 0}, 1000);

In angular(version 1.1.4+), ng-animate allows us to control the animation either using CSS or JS. This directive can gel up with other directives like ng-show/ng-hide, ng-view, ng-include, ng-switch, etc.
We’ll simply add it to our div.alert which takes processed CSS class as an option.

<div class="alert alert-success" ng-show='processed' ng-animate="'processed'">
  <b>Well done!</b> We've successfully processed the order.
</div>

Then we’ll define necessary CSS classes. What happens here is when div.alert is about to be shown (means processed becomes boolean true), both processed-show and processed-show-active classes will be applied which will help fade in the element for 0.5 seconds and later be removed. And display property sets to block.

.processed-show {
  -webkit-transition:all linear 0.5s;
  -moz-transition:all linear 0.5s;
  -ms-transition:all linear 0.5s;
  -o-transition:all linear 0.5s;
  transition:all linear 0.5s;
  opacity:0;
}
.processed-show-active {
  opacity:1;
}

We can use similar css while hiding the element but opacity will change from 100% to 0%.

.processed-hide {
  -webkit-transition:all linear 0.5s;
  -moz-transition:all linear 0.5s;
  -ms-transition:all linear 0.5s;
  -o-transition:all linear 0.5s;
  transition:all linear 0.5s;
  opacity:1;
}
.processed-hide-active {
  opacity:0;
}

Check out the demo. There are more in-depth articles on yearofmoo.com and nganimate.org.

jQuery plugins

We can not live without it. A few weeks ago, I’d written an article on how to use jQuery plugin the angular way.

Custom Directives

AngularJS really shines where it lets you write custom directives also. There are hell lot of articles to get you started.

Wrap ups

I’d seen many of my colleagues struggled to get going with AngularJS and hence I’d decided to write this post. Time has come to expand the horizon. All the best.

11 thoughts on “Migration guide for jQuery Developers

  1. I’ve spent the past few days learning angular and figuring out how to move myself from jquery to angular. This is one of the most useful posts, thank you so much for writing it!

  2. A question still remains… I use jQuery plugins like select2 in my website. How can I still use them without jQuery?

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