6. Directive Debugging
When you use directives inside the template, what you see on the page is the compiled version of the directive. Sometimes, you want to see the actual directive usage for debugging purposes. In order to see the uncompiled version of the current section, you can use
ng-non-bindable
. For example, let's say you have a widget that prints the most popular books, and here is the code for that:
1
2
3
| < ul > < li ng-repeat = "book in books" >{{book}}</ li > </ ul > |
The book's scope variable comes from the controller, and the output of this is as follows:
If you want to know the directive usage behind this compiled output, you can use this version of the code:
1
2
3
| < ul ng-non-bindable = "" > < li ng-repeat = "book in books" >{{book}}</ li > </ ul > |
This time the output will be like below:
It is cool up to now, but what if we want to see both the uncompiled and compiled versions of the widget? It is time to write a custom directive that will do an advanced debugging operation.
01
02
03
04
05
06
07
08
09
10
11
12
| app.directive( 'customDebug' , function ($compile) { return { terminal: true , link: function (scope, element) { var currentElement = element.clone(); currentElement.removeAttr( "custom-debug" ); var newElement = $compile(currentElement)(scope); element.attr( "style" , "border: 1px solid red" ); element.after(newElement); } } }) |
In this directive, we are cloning the element that's in debug mode so that it's not changed after some set of operations. After cloning, remove the
custom-debug
directive in order not to act as debug mode, and then compile it with$complile
, which is already injected in the directive. We have given a style to the debug mode element to emphasize the debugged one. The final result will be as below:
You can save your development time by using this kind of debugging directive to detect the root cause of any error in your project.
7. Directive Unit Testing
As you already know, unit testing is a very important part of development to totally control the code you have written and prevent potential bugs. I will not dive deep into unit testing but will give you a clue about how to test directives in a couple of ways.
I will use Jasmine for unit testing and Karma for the unit test runner. In order to use Karma, simply install it globally by running
npm install -g karma karma-cli
(you need to have Node.js and npm installed on your computer). After installation, open the command line, go to your project root folder, and typekarma init
. It will ask you a couple of questions like below in order to set up your test requirements.
I am using Webstorm for development, and if you are also using Webstorm, just right click on karma.conf.js and select Run karma.conf.js. This will execute all the tests that are configured in the karma conf. You can also run tests with the
karma start
command line in the project root folder. That's all about the environment setup, so let's switch to the test part.
Let's say that we want to test the book directive. When we pass a title to the directive, it should be compiled into a book detail view. So, let's get started.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
| describe( "Book Tests" , function () { var element; var scope; beforeEach(module( "masteringAngularJsDirectives" )) beforeEach(inject( function ($compile, $rootScope) { scope = $rootScope; element = angular.element( "<booktest title='test'></booktest>" ); $compile(element)($rootScope) scope.$digest() })); it( "directive should be successfully compiled" , function () { expect(element.html()).toBe( "test" ) }) }); |
In the above test, we are testing a new directive called
booktest
. This directive takes the argument title
and creates a div by using this title. In the test, before each test section, we are calling our module masteringAngularJsDirectives
first. Then, we are generating a directive called booktest
. In each test step, the directive output will be tested. This test is just for a value check.8. Directive Scope Testing
In this section, we will test the scope of the directive
booktest
. This directive generates a book detail view on the page, and when you click this detail section, a scope variable called viewed
will be set as true
. In our test, we will check if viewed
is set to true when the click event is triggered. The directive is:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
| .directive( 'booktest' , function () { return { restrict: 'E' , scope: { title: '@' }, replace: true , template: '<div>{{title}}</div>' , link: function (scope, element, attrs) { element.bind( "click" , function () { console.log( "book viewed!" ); scope.viewed = true ; }); } } }) |
In order to set an event to an element in AngularJS inside the directive, you can use the
link
attribute. Inside this attribute, you have the current element, directly bound to a click event. In order to test this directive, you can use the following:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
| describe( "Book Tests" , function () { var element; var scope; beforeEach(module( "masteringAngularJsDirectives" )) beforeEach(inject( function ($compile, $rootScope) { scope = $rootScope; element = angular.element( "<booktest title='test'></booktest>" ); $compile(element)($rootScope) scope.$digest() })); it( "scope liked should be true when book liked" , function () { element.triggerHandler( "click" ); expect(element.isolateScope().viewed).toBe( true ); }); }); |
In the test section, a click event is triggered by using
element.triggerHandler("click")
. When a click event is triggered, the viewed variable needs to be set as true
. That value is asserted by using expect(element.isolateScope().viewed).toBe(true)
.9. Conclusion
In order to develop modular and testable web projects, AngularJS is the best one in common. Directives are one of the best components of AngularJS, and this means the more you know about AngularJS directives, the more modular and testable projects you can develop.
In this tutorial, I have tried to show you the real-life best practices about directives, and keep in mind that you need to do lots of practice in order to understand the logic behind the directives. I hope this article helps you understand AngularJS directives well.
Không có nhận xét nào:
Đăng nhận xét