Can a directive delete itself from a parent scope

10,442

Solution 1

according to New Dev in a previous comment, this is the way:

var app = angular.module('app', [])
  .directive('customDirective', function($log) {
    return {
        restrict: 'EA',
        template: '<a href="" ng-click="onRemove()">remove me {{model.n}}</a>',
        scope: {
            model:"=",
            onRemove:"&"
        }
    }
  })
  .run(function($rootScope) {
    $rootScope.instances = [{n:1},{n:2},{n:3},{n:4}];
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div ng-repeat="i in instances">
    <custom-directive model="i" on-remove="instances.splice($index,1)">
    </custom-directive>
  </div>
</div>

Solution 2

First, don't use ngModel as a DOM attribute. This is an AngularJS directive used to bind form inputs to scope variables.

I've renamed it to model and added an extra attribute called index.

<div ng-app="app" ng-controller="controller">
  <div ng-repeat="instance in instances>
    <customDirective model="instance" index="$index"></customDirective>
  </div>
</div>

Now in your controller you can listen for events (such as a custom event you might title removeCustom) emitted by children using $scope.$on().

app.controller('controller',function($scope) {
    $scope.instances = [.....];
    $scope.$on('removeCustom',function($index) {
        delete $scope.instances[$index];
    });
});

Then in your custom directive you have to use $scope.$emit() to broadcast your removeCustom event up the scope hierarchy to the controller.

app.directive('customDirective', function($log) {
    return {
        restrict: 'E',
        templateUrl: './template.htm',
        scope: {
            model:"=",
            index:"="
        },
        link: function($scope,$el,$attr) {
            // when you need to remove this
            $scope.$emit('removeCustom',$scope.index);
        }
    });

FYI: A directive can always remove itself by calling $el.remove() in the link function, but since your directive is created via a ngRepeat it will just get recreated in the next digest. So you have to tell the controller to remove it from the instances array.

Share:
10,442
Matt
Author by

Matt

Hello

Updated on July 22, 2022

Comments

  • Matt
    Matt almost 2 years

    Let's say I have the following code

    <div ng-app="app" ng-controller="controller">
     <div ng-repeat="instance in instances>
      <customDirective ng-model="instance"></customDirective>
     </div>
    </div>
    

    And my custom directive has an isolated scope, defined as:

     app.directive('customDirective', function($log) {
            return {
                restrict: 'E',
                templateUrl: './template.htm',
                scope: {_instance:"=ngModel"},
                link: function($scope) {
                ....
                }
            });
    

    In this directive, I have to option to delete it. My question is how can I communicate back to the array instances in the parent scope and tell it to destroy this object and in effect remove the deleted instance from my DOM?

    Hope that makes sense.

  • New Dev
    New Dev over 9 years
    $emit seems inappropriate here as it "pollutes" the global scope. I would use "&" - a function call from the directive.
  • Reactgular
    Reactgular over 9 years
    @NewDev yes, I agree. That would be a better approach.
  • charlietfl
    charlietfl over 9 years
    don't use delete on arrays either, it doesn't remove the element , use splice() so you modify length and don't leave an undefined element in the array. In general is better to pass the actual object and not rely on it's view index, which could be different due to filtering, then use indexOf to remove it
  • Michael
    Michael over 9 years
    thanks to @charlietfl bc i was delete-ing the elem from the array in an obj, rather than splicing, d-oh!
  • sg.cc
    sg.cc over 9 years
    Is there seriously no way to make an object delete itself without it seeing its parent array? I feel like putting the array of objects into the root scope (Lautaro's comment below), or pinging an event to some external controller (this answer) are both hacks.
  • Dazag
    Dazag over 8 years
    flawless. Smooth like no other answer I've seen around! thanks!