Q: "Thinking in AngularJS" if I had a jQuery background?
A:
1. Don ' t design your page, and then change it with Dommanipulations
In JQuery, you design a page, and then you make it dynamic. This is because jQuery were designed for augmentation and have grown incredibly from, simple premise.
But in AngularJS, you must start from the ground to the your architecture in mind. Instead of starting by thinking "I has this piece of the DOM and I want to make it does X Want to accomplish, then go on designing your application, and then finally go about designing your view.
2. Don ' t augment JQuery with AngularJS
Similarly, don ' t start with the idea of this jQuery does X, Y, and Z, so I'll just add AngularJS on top of this for models an D controllers. This is really tempting if you ' re just starting out, which is what I always recommend that new AngularJS develop ERs don ' t use JQuery @ all, at least until they get used to doing things the ' Angular '.
I ' ve seen many developers here and on the mailing list create these elaborate solutions with jQuery plugins of 200 Lines of code that they then glue to AngularJS with a collection of callbacks and $apply
s that is confusing and convolute D But they eventually get it working! The problem is and the most cases that JQuery plugin could being rewritten in AngularJS in a fraction of the code, WH Ere suddenly everything becomes comprehensible and straightforward.
The bottom line was This:when solutioning, first "think in AngularJS"; If you can ' t think of a solution, ask the community; If after all of this there is no easy solution, then feel free to reach for the jQuery. But don't let jQuery become a crutch or you ll never master AngularJS.
3. Always think in terms of architecture
First know that single-page applications is applications. They ' re not webpages. So we need to think like a server-side developer in addition to thinking like a client-side developer. We have the think to the divide our application into individual, extensible and testable components.
So and How does the do? How does "think in AngularJS"? Here is some general principles, contrasted with jQuery.
The view is the "official record"
In JQuery, we programmatically change the view. We could has a dropdown menu defined as a like so ul
:
<ul class="main-menu"> <li class="active"> <a href="#/home">Home</a> </li> <li> <a href="#/menu1">Menu 1</a> <ul> <li><a href="#/sm1">Submenu 1</a></li> <li><a href="#/sm2">Submenu 2</a></li> <li><a href="#/sm3">Submenu 3</a></li> </ul> </li> <li> <a href="#/home">Menu 2</a> </li></ul>
In JQuery, in our application logic, we would activate it with something like:
$(‘.main-menu‘).dropdownMenu();
When we just look at the view, it's not immediately obvious that there are any functionality here. For small applications, that ' s fine. Non-trivial applications, things quickly get confusing and hard to maintain.
In AngularJS, though, the view is the official record of view-based functionality. Our ul
declaration would look like this instead:
<ul class="main-menu" dropdown-menu> ...</ul>
These the same thing, but the AngularJS version anyone looking at the template knows what's supposed to Happe N. Whenever a new member of the development team comes on board, she can look at this and then know tha T there is a directive called , Dropdownmenu
operating on it; She doesn ' t need to intuit the right answer or sift through any code. The view told us what is supposed to happen. Much Cleaner.
Developers new to AngularJS often ask a question like:how does I find all links of a specific kind and add a directive onto them. The developer is always flabbergasted when we reply:you don ' t. But the reason you don ' t does that's that's the IS-like Half-jquery, Half-angularjs, and no good. The problem here is, the developer is trying to "do jQuery" in the context of AngularJS. That's never going to work well. The view is the official record. Outside of a directive (more in this below), your never, ever, neverchange the DOM. and directives is applied in the view, so intent is clear.
Remember:don ' t design, and then mark up. You must architect, and then design.
Data binding
This was by far one of the awesome features of AngularJS and cuts out a lot of the need to do the kinds of DOM Manipul Ations I mentioned in the previous section. AngularJS'll automatically update your view so you don ' t have to! In JQuery, we respond to events and then update content. Something like:
$.ajax({ url: ‘/myEndpoint.json‘, success: function ( data, status ) { $(‘ul#log‘).append(‘<li>Data Received!</li>‘); }});
For a view it looks like this:
<ul class="messages" id="log"></ul>
Apart from mixing concerns, we also has the same problems of signifying intent that I mentioned before. But more importantly, we had to manually reference and update a DOM node. And if we want to delete a log entry, we had to code against the DOM for that too. How does we test the logic apart from the DOM? And what if we want to the presentation?
This a little messy and a trifle frail. But in AngularJS, we can does this:
$http( ‘/myEndpoint.json‘ ).then( function ( response ) { $scope.log.push( { msg: ‘Data Received!‘ } );});
And our view can look like this:
<ul class="messages"> <li ng-repeat="entry in log">{{ entry.msg }}</li></ul>
But to that matter, we view could look like this:
<div class="messages"> <div class="alert" ng-repeat="entry in log"> {{ entry.msg }} </div></div>
And now instead of the using an unordered list, we ' re using Bootstrap alert boxes. And we never had to change the controller code! But more importantly, no matter where or how the log gets updated, the view would change too. automatically. neat!
Though I didn ' t show it here, the data binding is two-way. So those log messages could also is editable in the view just by doing this: <input ng-model="entry.msg" />
. And there was much rejoicing.
DISTINCT model Layer
In JQuery, the DOM is kind of the model. But in AngularJS, we had a separate model layer that we can manage on any we want, completely independently from the View. This helps is the above data binding, maintains separation of concerns, and introduces far greater testability. Other answers mentioned this point, so I'll just leave it at that.
Separation of concerns
And all of the above tie to this over-arching theme:keep your concerns separate. Your View acts as the official record of what's supposed to happen (for the more part); Your model represents your data; You had a service layer to perform reusable tasks; You do DOM manipulation and augment your view with directives; And you glue it all together with controllers. This is also mentioned in other answers, and the only thing I would add pertains to testability, which I discuss in Anoth ER section below.
Dependency Injection
To help us out with separation of concerns is dependency injection (DI). If you come from a Server-side language (from Java to PHP) you ' re probably familiar with this concept already Re a client-side guy coming from jQuery, this concept can seem anything from silly to superfluous to hipster. But it's not. :-)
From a broad perspective, DI means so can declare components very freely and then from any other component, just ask For an instance of it and it'll be granted. You don ' t has to know about loading order, or file locations, or anything. The power may not immediately is visible, but I ll provide just one (common) example:testing.
Let's say in our application, we require a service this implements Server-side storage through a restapi and, depending on Application state, local storage as well. When running tests in our controllers, we don ' t want to has to communicate with the Server-we ' re testing the contro Ller, after all. We can just add a mock service of the same name as our original component, and the injector would ensure that our Controlle R gets the fake one automatically-our controller doesn ' t and Needn ' t know the difference.
Speaking of testing ...
4. Test-driven Development-
always
This was really part of the section 3 on architecture, but it's so important that I ' m putting it's own top-level section.
Out of any of the many jQuery plugins you ' ve seen, used, or written, what many of them had an accompanying test suite? Not very many because jQuery isn ' t very amenable to that. But AngularJS is.
In JQuery, the only-to-test is often-to-create the component independently with a Sample/demo page against which our T ESTs can perform DOM manipulation. So and we had to develop a component separately and then integrate it into our application. How inconvenient! So much of the time, when developing with jQuery, we opt for iterative instead of test-driven development. And who could blame us?
But because we had separation of concerns, we can do Test-driven development iteratively in angularjs! For example, let's say we want a super-simple directive to indicate in our menu what's our current route is. We can declare what we want in the view of our application:
<a href="/hello" when-active>Hello</a>
Okay, now we can write a test for the non-existent when-active
directive:
it( ‘should add "active" when the route changes‘, inject(function() { var elm = $compile( ‘<a href="/hello" when-active>Hello</a>‘ )( $scope ); $location.path(‘/not-matching‘); expect( elm.hasClass(‘active‘) ).toBeFalsey(); $location.path( ‘/hello‘ ); expect( elm.hasClass(‘active‘) ).toBeTruthy();}));
And when we run our test, we can confirm that it fails. Should we create our directive:
.directive( ‘whenActive‘, function ( $location ) { return { scope: true, link: function ( scope, element, attrs ) { scope.$on( ‘$routeChangeSuccess‘, function () { if ( $location.path() == element.attr( ‘href‘ ) ) { element.addClass( ‘active‘ ); } else { element.removeClass( ‘active‘ ); } }); } };});
Our test now passes and our menu performs as requested. Our development is both iterative and Test-driven. Wicked-cool.
5. Conceptually, directives is
notPackaged JQuery
You'll often hear "only does DOM manipulation in a directive". This is a necessity. Treat it with due deference!
But let ' s dive a little deeper ...
Some directives just decorate what's already in the view (think ngClass
) and therefore sometimes do DOM manipulation straigh T away and then is basically done. But if a directive are like a "widget" and have a template, it should also respect separation of concerns. That's, the template too should remain largely independent from it implementation in the link and controller fu Nctions.
AngularJS comes with a entire set of tools to make this very easy; With ngClass
we can dynamically update the class; ngModel
allows two-way data binding; ngShow
and ngHide
programmatically show or Hide an element; And many more-including the ones we write ourselves. In the other words, we can do all kinds of awesomeness without DOM manipulation. The less DOM manipulation, the easier directives is to test, the easier they is to style, the easier they is to change The future, with the more re-usable and distributable they is.
I See lots of developers new to AngularJS using directives as the place to throw a bunch of jQuery. In other words, they think "since I can ' t does DOM manipulation in the controller, I'll take this code put it in a directive ". While this certainly is much better, it ' s often still wrong.
Think of the logger we programmed in section 3. Even if we put that in a directive, we still want to do it the "Angular". It still doesn ' t take any DOM manipulation! There was lots of times when DOM manipulation was necessary, but it's a lot rarer than you think! Before doing DOM manipulationanywhere in your application, ask yourself if you really need to. There might be a better.
Here's a quick example that shows the pattern I see most frequently. We want a toggleable button. (note:this example is a little contrived and a skosh verbose to represent more complicated cases that's solved in exact Ly the same.)
.directive( ‘myDirective‘, function () { return { template: ‘<a class="btn">Toggle me!</a>‘, link: function ( scope, element, attrs ) { var on = false; $(element).click( function () { on = !on; $(element).toggleClass(‘active‘, on); }); } };});
There is a few things wrong with this:
- First, JQuery was never necessary. There's nothing we do here this needed jQuery at all!
- Second, even if we already has jQuery on our page, there's no reason to use it here; We can simply use and our component would still work when
angular.element
dropped to a project that doesn ' t has jQuery.
- Third, even assuming JQuery was required for the directive to work, Jqlite (
angular.element
) would always use Jque ry if it was loaded! So we Needn ' t use the $
-we can just use angular.element
.
- Fourth, closely related to the third, was that jqlite elements needn ' t being wrapped in-the that's passed to the
$
element
link
function would already be a jQuery element!
- and fifth, which we ' ve mentioned in previous sections, why is we mixing template stuff into our logic?
This directive can is rewritten (even for very complicated cases!) much more simply like so:
.directive( ‘myDirective‘, function () { return { scope: true, template: ‘<a class="btn" ng-class="{active: on}" ng-click="toggle()">Toggle me!</a>‘, link: function ( scope, element, attrs ) { scope.on = false; scope.toggle = function () { scope.on = !scope.on; }; } };});
Again, the template stuff is in the template, so you (or your users) can easily swap it out for one that meets any style n Ecessary, and the logic never had to be touched. reusability-boom!
And there is still all those other benefits, like testing-it ' s easy! No matter what's in the template, the directive's internal API is never touched, so refactoring are easy. You can change the template as much as you want without touching the directive. And no matter, your tests still pass.
w00t!
So if directives aren ' t just collections of jquery-like functions, what is they? Directives is actuallyextensions of HTML. If HTML doesn ' t do something your need it to do, you write a directive to does it for your, and then use it just as if it is Part of HTML.
Put another, if AngularJS doesn ' t do something out of the box, think how the team would accomplish it-fit right in With ngClick
, ngClass
et al.
Summary
Don ' t even use jQuery. Don ' t even include it. It'll hold your back. And when are you come to a problem so think you know how to solve in jQuery already, before your reach for $
the, try To think the within the confines the AngularJS. If you don ' t know, ask! Times out of a, the best-by-doing it doesn ' t need jQuery and to-try to solve it with jQuery results in + work for You.
This is a question from StackOverflow, three elder brother directly to the best answer moved over.
All said Angularjs learning curve Strange, I was also groping.
' Thinking in AngularJS ' if you have a jQuery background