• No results found

113Best practices

In document AngularJS in Action (Page 136-140)

4.4 $http interceptors

113Best practices

$rootScope = _$rootScope_;

var directiveMarkup = angular.element('<li userstory></li>');

element = $compile(directiveMarkup)($rootScope);

userStory = element.scope().userStory;

StoriesModel = _StoriesModel_;

spyOn(StoriesModel, 'destroy').and.callFake(function() { var deferred = $q.defer();

deferred.resolve('data');

return deferred.promise;

});

spyOn($rootScope,'$broadcast').and.callThrough();

}));

});

As usual, the actual test is much more straightforward than the rigmarole needed to set it up. We simply call the deleteStory method on the directive’s scope, pass it an argument with value 0, and then test to make sure that the method was indeed called with 0. We then resolve the promise using $rootScope.$digest() and then test to make sure the appropriate event was broadcasted:

client/tests/specs/directives/UserStoryDirective.spec.js it('should delete a story', function() {

userStory.deleteStory('0');

expect(StoriesModel.destroy).toHaveBeenCalledWith('0');

$rootScope.$digest();

expect($rootScope.$broadcast).toHaveBeenCalledWith('storyDeleted');

});

5.6 Best practices

DOM manipulation should be done in the link function and imperative logic in the controller.

One of the advantages of using a JavaScript framework like AngularJS is the separation of concerns, especially the separation of the DOM from our imperative logic. We like to keep this theme rolling by putting all of the DOM manipulation logic in our direc-tives’ link function and all of our business logic in our direcdirec-tives’ controller.

Using bindToController

We’ve already talked about the controller-as syntax and why we use it. It turns out that there’s a small disconnect between controllerAs in a directive DDO and iso-late scope. If you use both of these features, you have to watch $scope for changes inside the controller and then update the this property whenever an attribute on isolate scope is changed. This completely defeats the purpose of controllerAs!

In Angular 1.3, all you need to do is add bindToController: true to your DDO, and this will be updated every time an attribute on isolate scope is updated.

Favor a compartmentalized approach to writing directives. Oftentimes, we’ll start build-ing out a feature usbuild-ing a directive and then, perhaps a couple weeks later, we have a whale of a directive on our hands. It’s not that our code is bad, it’s just that our direc-tive is doing too much at once. At this point, we like to break our direcdirec-tive into inde-pendent logical components and then use them together. This kills two birds with one stone: not only do we have cleaner, more maintainable code, but we can also reuse one or more of our components in other parts of the application.

5.7 Summary

And we have crossed the finish line with three directives we’ve built from the ground up. While we sacrificed covering the entire academic tome of directives in favor of illustrating practical, working examples, we hope that you’ve started to see the immense power of directives and dig deeper. Let’s review:

Directives allow you to extend HTML however you want.

You learned what directives are, why you want them, and why you need them.

There are three main parts to a directive: the Directive Definition Object, the link function, and the controller; you saw the purpose of each and how to use them.

You learned what isolated scope is and how to leverage it in providing the maxi-mum functionality to your directives.

You saw how to include one directive’s controller in the DDO of another direc-tive and how to inject that controller into that direcdirec-tive’s controller.

You built complex features using directives, including a drag-and-drop feature and a third-party integration with a jQuery plugin to give you pretty graphs.

115

Animations

6.1 Intro to animations

AngularJS was originally created as a framework to handle enterprise CRUD applica-tions. With the introduction of the new animations API, AngularJS has broadened the possibilities to offer something for designers and developers alike.

The most powerful aspect of AngularJS is directives, and AngularJS animations are essentially class-based directives that have the power to harness complex anima-tions with the addition of a single class to your markup.

The goal of this chapter is to show you the AngularJS animation events, the naming convention around those events, and the three types of animations you can do in AngularJS, with practical examples for each. We’re not going to examine CSS3 animations or JavaScript animations in depth, but rather endeavor to lay a strong foundation that you can let your creativity run wild on.

This chapter covers

How AngularJS handles animations

Understanding the animation-naming convention

The three types of animations

Concrete examples of each type as it relates to Angello

6.1.1 How AngularJS handles animations

AngularJS animations can be distilled down to five events and a class-based naming convention. Once you’ve grasped the events at play and the naming convention, AngularJS animations fade into the background and the animations themselves take center stage.

There are three types of animations that you can create with AngularJS: CSS transi-tions, CSS animations, and JavaScript animations. Each type of animation is well suited for varying contexts, and we’ll explore each of them later in the chapter.

AngularJS doesn’t actually do any of the animations themselves, but simply pro-vides the hooks for you to apply your own animations as you see fit. These hooks come in the form of events, and there are only five of them.

The five animation events are enter, leave, move, addClass, and removeClass (see table 6.1).

The enter and leave events are fired when a DOM element is added or removed from the DOM tree, respectively. The move event is fired when a DOM element changes posi-tion within the DOM tree. Last but not least, the addClass and removeClass events are fired when a class is added to or removed from an element, respectively.

6.1.2 The animation-naming convention

AngularJS animations are entirely class-based, which is a design decision that makes integration with third-party libraries easier. Even JavaScript animations follow a class-based naming convention for consistency.

Table 6.1 The AngularJS animation furious five

Event Function Description

enter $animate.enter(element, parent,after,callback);

Appends the element object after the after node or within the parent node and then runs the enter animation on the element

leave $animate.leave(element, callback);

Runs the leave animation and then removes the element from the DOM move $animate.move(element,

parent,after,callback);

Moves the element node either after the after node or inside of the v

node and then runs the move anima-tion on the element

addClass $animate.addClass(element, className,callback);

Runs the addClass animation based on the className value and then adds the class to the element removeClass $animate.removeClass(element,

className,callback);

Runs the removeClass animation based on the className value and then removes the class from the element

117

In document AngularJS in Action (Page 136-140)

Related documents