Search code examples
angularjsangular-directive

Remove all ng-model variables from $scope when hidden


My problem is similar to the one in this question, This works when we know the scope variable to remove. However I am looking for something generic, like remove the variable for all the elements this directive is attached to, whenever they become hidden. I tried injecting the ngModel and tried setting to null or delete, doesn't seem to work.

This is what I am trying to to: plunk

myModule.directive('destroyY', function(){
         return{
          restrict:'A',
          require: '?ngModel',
          link: function(scope, elem, attrs, ngModel) {

            scope.$on('$destroy', function(){
             console.log(ngModel);

             ngModel=null; // doesn't work
             delete ngModel; // doesn't work

            }) 
          }
         }
        });

Any help is greatly appreciated. Thanks!


Solution

  • Specifically, in your case of a directive that works with ng-if and uses require: "ngModel", you could do:

     scope.$on("$destroy", function(){
        ngModel.$setViewValue(undefined);
     }
    

    Just a one other thing to note here:

    scope.$on("$destroy") works when the scope is destroyed - not always when the element is "destroyed" (or removed from DOM). In you case it works since ng-if creates a child scope, however, it is entirely possible that an element is removed by another directive without the scope that it "lived" it being destroyed. In this case, you might want to use elem.on("$destroy").

    EDIT:

    Indeed, as noted in the comments, this does NOT remove the actual key - just sets the value of that key. If you think about it, this is the right thing to do, because the key could be a setter function (ngModel supports setter/getter functions).

    Although I recommend against that, you could still remove the property from the scope, although it is an ugly approach that is obviously not catered to by Angular.

    You need to get the parent object expression (e.g. form) and its property expression (e.g. y) and then delete the property. Notice that if there is no dot notation ("."), then ngModel would have set the value on the scope being destroyed, and so we would care about it. To do that, you'd need to use $parse:

    var modelExp = attrs.ngModel;
    var idxOfDot = modelExp.lastIndexOf(".");
    var parentExp = modelExp.substring(0, idxOfDot);
    var propExp = modelExp.substring(idxOfDot + 1);
    
    var parsedParentExp = $parse(parentExp);
    
    scope.$on("$destroy", function(){
       var p = parsedParentExp(scope);
       if (p){
          delete p[propExp];
       }
    })