Sunday, 1 May 2016

Decorative directives : Advance Beginner III

Hey guys whats up? Till now we have been working mostly on component type directive.As we have seen component type directive can be used to insert new element in DOM.Decorative directive as the name suggest is used for modifying existing element like ng-show ng-disabled ng-click etc.
Lets recreate ng-click directive. Look at the following code.

In my index.html file I am adding my-click directive which will trigger clickHandler function.Also I am adding ng-class (another decorative directive..phewww!) to give some styling to the text to be displayed after the function is triggered.
In my controller I have data object as follows

$scope.data = {
    message: "Click me!",
    selected: false
  };

So we have click me on display.I am passing data object in clickHandler function and if selected value is true then I am showing text with styling or else I am reverting it back to original text. And I am doing this by creating directivemyClick
So what exactly is happening inside directive? I have used link function, then there is $parse service...don't worry all these are pretty simple!
Link function is to register a DOM listener as well as update the DOM.Events like click or focus that are happening in DOM is beyond the scope of angular, so we use link function to register the events.It takes three parameters: scope, element, attrs where
  • scope is an Angular scope object.
  • element is the jqLite-wrapped element that this directive matches.
  • attrs is the arrays of all attributes that are on the element.
link: function(scope, el, attrs) {
      var fn = $parse(attrs['myClick']);
      el.on('click', function () {
        scope.$apply(function() {
          scope.data.selected = !scope.data.selected;
          fn(scope);
        });
      });
    }


Inside link function I am using $parse service.It is used to convert an angular expression to a function which then can be invoked with context and locals where context is the object in scope of controller and locals are just local variables.I am parsing attribute ng-click which triggers clickHandler function.$parse service returns a precompiled expression which I have assigned to variable fn.Then fn is called with parameter scope which has data object inside it.
See its that easy!!!
I know you are too much relaxed now with all these easy going stuff. Lets bring back our old code(I really can't leave Ironman and batman...they are my favourites!) and do some modification in that.Here is the code we are going to modify.

I want to demonstrate state change to user which means suppose when user has clicked on remove icon beside team,the background color of panel body should change.And when user clicks on confirm or cancel button the background should revert back as white.Try yourself first...Go go do some brain storming!!!.
I know you guys are smart enough and already made necessary changes if not at least made some changes.Here is plunker of working code, you can see the output and again try if you want to and I really want you to try and not just read.
Lets review the code, Here I am passing parameter as function in isolated scope.As you can see in <remove-team> element I am adding an attribute method2 and passing a function "state()" to the scope of removeTeam directive. Next I am triggering a function changeState() on click of a remove icon from removeTeam.html. Now changeState will call notifyState which in return will call state method that has some logic to determine the user level based on which I am going to change the background color. When user level is 0, it means no state change and hence no change in color but user level as 1 represents state change.So I have added a new property level inside user object with value 0.When the control goes to state(), it increments the level value from 0 to 1 and then we add modulus 2 on level because we want level value to switch between 0 and 1 only. We don't want level value to go beyond 1.
Next I have created a directive to displayState to add logic to present different state. I could have added the logic in removeTeam directive itself but that would have been a naive implementation because my removeTeam directive is only for removing items and I don't want to use for any other purpose also I want my displayState directive to be reusable and encapsulated.
I have added display-state attribute to the element having panel body and passing value of user level.Inside displayState directive I have used $watch to detect any changes in display-state attribute.So when we click on remove icon it goes to changeState() inside removeTeam directive.It then calls notifyState which in return calls state() which changes the user level.Change in user level is detected by $watch and it then changes the background color.
But notice one problem here.click on remove icon, yes it is now showing warning state.Cool! again click on remove icon. whoo everything breaks! So we have a simple solution to this. As soon as we click on remove icon we will hide it and bring it back again on clicking of confirm or cancel button.Its very simple and needs no explanation at this stage.Here is the final code.
Next we will explore some more advanced things like Transclusion, Structural directive which will take us to intermediate stage and later we will move to expert level.If you have been following this course from start by now you must have been pretty comfortable with directives and I am sure you must be enjoying writing your own directives.For any queries mail me at omitewary@gmail.com

No comments:

Post a Comment