0

How can I get the last state of a directive after it has been re-rendered (the link function was executed again)? By the state I mean some data that are set by the directive itself, not passed in via attributes.

I created a simple example here on jsFiddle. What I want to accomplish is to see the same values on tab1 when clicking to tab2 and back to tab1.

HTML

<div ng-app="myApp">
    <nav ng-init=" selected = 'tab1' ">
        <a href="" ng-click=" selected = 'tab1' ">tab1</a> | 
        <a href="" ng-click=" selected = 'tab2' ">tab2</a>
    </nav>
    {{selected}} is selected
    <div ng-if="selected == 'tab1' ">
        remember the values and go to tab2
        <div my-directive></div>
        <div my-directive></div>
    </div>
    <div ng-if="selected == 'tab2' ">
        go back to tab1 and see how data changed
    </div>
</div>

JS

(function() {
    var myApp = angular.module('myApp', ['myDirectiveModule']);
})();


(function(angular) {
    angular.module('myDirectiveModule', [])

    .directive('myDirective', 
        function() {

            return {
                restrict: 'A',
                scope: true,
                template: 'this is directive, data is {{directiveData}}',
                link: function($scope, iElm, iAttrs, controller) {
                    console.log('link function is executing');
                    $scope.directiveData = $scope.directiveData || Math.floor((Math.random() * 100) + 1);
                }
            };
        }
    );

})(angular);

Different solutions came to my mind, but none seems to work, like:

  • use a service to store the data (in array as there can be more instances of myDirective), but how would the directive know which index of the array to ask for?
  • use controller inside directive but the problem as in previous case. Also controller would be probably lost when no directive is displayed on the page
  • use some parent scope or parent controller to keep track of the data, but I can not force users to create controller everywhere where they want to use the directive, not a good solution from architecture perspective. The myDirective or myDirectiveModule should handle all its stuff alone
przno
  • 3,476
  • 4
  • 31
  • 45

1 Answers1

0

The easiest solution, I think, would be to simply use ngShow instead of ngIf. This will render the elements shown or hidden using CSS rather than recompile a new element in the DOM.

Here is an example of how a service might work:

.service('data', function() {
    this.data = {};
    this.generateData = function(id){ 
        if (this.data[id] !== undefined)
            return this.data[id];
        else     
            return this.data[id] = Math.floor((Math.random() * 100) + 1);
    };
})

And in the linking function:

$scope.directiveData = data.generateData(iAttrs.id);

FIDDLE

EDIT:

Here's something you could do to get a unique ID for an element without assigning it explicitly:

function getIndex (node) {
      var parent=node.parentElement||node.parentNode, i=-1, child;
      while (parent && (child=parent.childNodes[++i])) if (child==node) return i;
      return -1;
}

function getPath (node) {
      var parent, path=[], index=getIndex(node);
      (parent=node.parentElement||node.parentNode) && (path=getPath(parent));
      index > -1 && path.push(index);
      return path;
}

I got this from here. Using the same service, but changing:

$scope.directiveData = data.generateData(getPath(iElm[0]));

Should work. There may be a pitfall to this approach, but I can't think what it might be. Using explicit id is what I would do.

Community
  • 1
  • 1
Mosho
  • 7,099
  • 3
  • 34
  • 51
  • Exactly what I was thinking of, but: 1) the `nhShow` vs `ngIf` - imagine I post myDirective to the internet for anybody to use in their angular apps, in their code they can use whatever (causing the directive to recompile). 2) passing the id to directive - again imagine I post it to net for common use and a statement for usage "you must provide a unique ID each time you use this directive". That just does not seem correct from the architecture/design view to me. That should be handled by `myDirectiveModule` itself and not passing some unique IDs from "outside". Dont know if thats possible ... – przno Jul 11 '14 at 09:58
  • the `getIndex` looks dangerous in case of DOM changes. Will probably use the _explicit id_ and service. I just wish Angular has some way to telling "this is the very same directive as it was the last time". Will wait if anyone else come with different idea, if no then accept your answer – przno Jul 11 '14 at 10:38
  • @przno I'll try to think of something else. You could use the `getPath` method (or a variation) as a fallback in case no id is provided. – Mosho Jul 11 '14 at 10:46