2112
2284
|
Suppose I'm familiar with developing client-side applications in jQuery, but now I'd like to start using AngularJS. Can you describe the paradigm shift that is necessary ? Here are a few questions that might help you frame an answer:
I'm not looking for a detailed comparison between jQuery and AngularJS.
| |||
add comment |
3928
+150
| 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 was designed for augmentation and has grown incredibly from that simple premise.
But in AngularJS, you must start from the ground up with your architecture in mind. Instead of starting by thinking "I have this piece of the DOM and I want to make it do X", you have to start with what you want to accomplish, then go about 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 that jQuery does X, Y, and Z, so I'll just add AngularJS on top of that for models and controllers. This is really tempting when you're just starting out, which is why I always recommend that new AngularJS developers don't use jQuery at all, at least until they get used to doing things the "Angular Way".
I've seen many developers here and on the mailing list create these elaborate solutions with jQuery plugins of 150 or 200 lines of code that they then glue into AngularJS with a collection of callbacks and
$apply s that are confusing and convoluted; but they eventually get it working! The problem is that inmost cases that jQuery plugin could be rewritten in AngularJS in a fraction of the code, where suddenly everything becomes comprehensible and straightforward.
The bottom line is this: when solutioning, first "think in AngularJS"; if you can't think of a solution, ask the community; if after all of that 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 are 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 to think about how to divide our application into individual, extensible, testable components.
So then how do you do that? How do you "think in AngularJS"? Here are some general principles, contrasted with jQuery.
The view is the "official record"
In jQuery, we programmatically change the view. We could have a dropdown menu defined as a
ul like so:
|
$('.main-menu').dropdownMenu();
ul
declaration would look like this instead: class="main-menu" dropdown-menu>
...
dropdownMenu
operating on it; she doesn't need to intuit the right answer or sift through any code. The view told us what was supposed to happen. Much cleaner.Data binding
$.ajax({
url: '/myEndpoint.json',
success: function ( data, status ) {
$('ul#log').append('
Data Received!
');
}
});
class="messages" id="log">
$http( '/myEndpoint.json' ).then( function ( response ) {
$scope.log.push( { msg: 'Data Received!' } );
});
class="messages">
- ng-repeat="entry in log">{{ entry.msg }}
class="messages">
class="alert" ng-repeat="entry in log">
{{ entry.msg }}
. And there was much rejoicing.Distinct model layer
Separation of concerns
Dependency injection
4. Test-driven development - always
href="/hello" when-active>Hello
it( 'should add "active" when the route changes', inject(function() {
var elm = $compile( 'Hello' )( $scope );
$location.path('/not-matching');
expect( elm.hasClass('active') ).toBeFalsey();
$location.path( '/hello' );
expect( elm.hasClass('active') ).toBeTruthy();
}));
.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' );
}
});
}
};
});
5. Conceptually, directives are not packaged jQuery
ngClass
) and therefore sometimes do DOM manipulation straight away and then are basically done. But if a directive is like a "widget" and has a template, it should also respect separation of concerns. That is, the template too should remain largely independent from its implementation in the link and controller functions.ngClass
we can dynamically update the class; ngBind
allows two-way data binding; ngShow
and ngHide
programmatically show or hide an element; and many more - including the ones we write ourselves. In other words, we can do all kinds of awesomeness without DOM manipulation. The less DOM manipulation, the easier directives are to test, the easier they are to style, the easier they are to change in the future, and the more re-usable and distributable they are..directive( 'myDirective', function () {
return {
template: 'Toggle me!',
link: function ( scope, element, attrs ) {
var on = false;
$(element).click( function () {
if ( on ) {
$(element).removeClass( 'active' );
}
else {
$(element).addClass( 'active' );
}
on = !on;
});
}
};
});
angular.element
and our component will still work when dropped into a project that doesn't have jQuery. Third, even assuming jQuery was required for this directive to work, jqLite (angular.element
) will always use jQuery if it was loaded! So we needn't use the $
- we can just use angular.element
. Fourth, closely related to the third, is that jqLite elements needn't be wrapped in $
- the element
that is passed to the link
function would already be a jQuery element! And fifth, which we've mentioned in previous sections, why are we mixing template stuff into our logic?.directive( 'myDirective', function () {
return {
scope: true,
template: 'Toggle me!',
link: function ( scope, element, attrs ) {
scope.on = false;
scope.toggle = function () {
scope.on = !scope.on;
};
}
};
});
ngClick
, ngClass
, et al.Summary
$
, try to think about how to do it within the confines the AngularJS. If you don't know, ask! 19 times out of 20, the best way to do it doesn't need jQuery and to try to solve it with jQuery results in more work for you.
|
Wow, this is absolutely terrific! – Jim Raden Feb 23 '13 at 23:15
| ||
|
+1 Even after so many years, some answers here still surprise you pleasantly. – Icicle Feb 24 '13 at 13:59
| ||
|
I got this on Addy Osmani's feed. Really great answer, a canonical reference I can direct jQuery folk interested in JS towards. This should be an official part of the AngularJS Documentation under 'migrating from' or something similar. – Benjamin Gruenbaum Feb 24 '13 at 21:42
| ||
|
I think incorporating working with JQuery within an angular app is important use-case because of all the existing JQuery plugins that have been written. I'm not rewriting FancyBox in jQuery to keep a pure Angular app. – taudep Feb 26 '13 at 21:53
| ||
|
And there was much rejoicing. – Uri Jun 26 '13 at 8:43
|
166
| Imperative → declarative
In jQuery, selectors are used to find DOM elements and then bind/register event handlers to them. When an event triggers, that (imperative) code executes to update/change the DOM.
In AngularJS, you want to think about views rather than DOM elements. Views are (declarative) HTML that contain AngularJS directives. Directives set up the event handlers behind the scenes for us and give us dynamic databinding. Selectors are rarely used, so the need for IDs (and some types of classes) is greatly diminished. Views are tied to models (via scopes). Views are a projection of the model. Events change models (that is, data, scope properties), and the views that project those models update "automatically."
In AngularJS, think about models, rather than jQuery-selected DOM elements that hold your data. Think about views as projections of those models, rather than registering callbacks to manipulate what the user sees.
Separation of concerns
jQuery employs unobtrusive JavaScript - behavior (JavaScript) is separated from the structure (HTML).
AngularJS uses controllers and directives (each of which can have their own controller, and/or compile and linking functions) to remove behavior from the view/structure (HTML). Angular also has servicesand filters to help separate/organize your application.
Application design
One approach to designing an AngularJS application:
Prototypal inheritance
You can do a lot with jQuery without knowing about how JavaScript prototypal inheritance works. When developing AngularJS applications, you will avoid some common pitfalls if you have a good understanding of JavaScript inheritance. Recommended reading: What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
| ||||||||||||||||||||
|