Anton Rand
Anton Rand

Reputation: 342

Sharing Data between Child Directives

I have three directives defined:

For some reason this does not work, if I set the length of the Array to 0 and push the value I will see the view update in Child Two (I have commented out the code which achieves this), but I want to understand why setting the array value doesn't work.

I understand that a service would be suitable here, but this directive may be re-used multiple times on the same page so I don't want the scope to clash between each item on the page.

Why doesn't the view get updated with the code I currently use?

var app = angular
  .module('SampleApplication', [])
  .directive('parent', function() {
    return {
      restrict: 'E',
      transclude: true,
      template: "<div ng-transclude></div>",
      controller: function($scope) {
        this.searchTerm = "";
        this.arrayContainingSearchTerm = [{value: ''}];
      
        this.updateSearchTerm = function(searchTerm) {
          this.searchTerm = searchTerm;
          
          //When this array is assigned - it doesn't get updated in the view
          this.arrayContainingSearchTerm = [{value: searchTerm}];
          
          //This will update the view.
          //this.arrayContainingSearchTerm.length = 0;
          //this.arrayContainingSearchTerm.push([{value: searchTerm}]);
        };
        
      }
    }
  })
  .directive('childOne', function() {
    return {
      restrict: 'E',
      require: '^^parent',
      template: "<div><h1>Child One</h1><input ng-model='searchTerm'></input></div>",
      link: function(scope, element, attrs, parentController) {
        scope.$watch('searchTerm', function(newValue, oldValue) {
          parentController.updateSearchTerm(newValue);
        });
      }
    }
  })
  .directive('childTwo', function() {
    return {
      restrict: 'E',
      require: '^^parent',
      template: "<div><h1>Child Two</h1><h2>Value below should be: {{searchTerm}}</h2><h2>{{arrayContainingSearchTerm}}</h2></div>",
      link: function(scope, element, attrs, parentController) {
        scope.searchTerm = parentController.searchTerm;
        scope.arrayContainingSearchTerm = parentController.arrayContainingSearchTerm;
      }
    }
  })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>


<div ng-app="SampleApplication">
  <parent>
    <child-one></child-one>
    <child-two></child-two>
  </parent>
</div>

Upvotes: 0

Views: 169

Answers (2)

digit
digit

Reputation: 4565

Children scope automatically inherit the parent's scope and can specifically access the parent's scope with $parent / requiring the parent controller but take note that siblings cannot [easily] access each others scope. So, the solution is to update the parent scope and reflect the parent scope changes back to the targeted child.

You don't need to update the child scope since the child scope is automatically inherit from parent scope. Also rather than watch the searchTerm ngModel, just use attrs.ngModel in the childOne directive.

var app = angular
.module('SampleApplication', [])
.directive('parent', function() {
  return {
    restrict: 'E',
    transclude: true,
    template: "<div ng-transclude></div>",
    controller: function($scope) {
      this.searchTerm = "";
      this.arrayContainingSearchTerm = [{value: ''}];

      this.updateSearchTerm = function(searchTerm) {
        this.searchTerm = searchTerm;

        //When this array is assigned - it doesn't get updated in the view
        this.arrayContainingSearchTerm = [{value: searchTerm}];

        //This will update the view.
        //this.arrayContainingSearchTerm.length = 0;
        //this.arrayContainingSearchTerm.push([{value: searchTerm}]);
      };

    }
  }
})
.directive('childOne', function() {
  return {
    restrict: 'E',
    require: '^^parent',
    template: "<div><h1>Child One</h1><input ng-model='searchTerm'></input></div>",
    link: function(scope, element, attrs, parentController) {
        // Just use attrs.ngModel
        parentController.updateSearchTerm(attrs.ngModel);
    }
  }
})
.directive('childTwo', function() {
  return {
    restrict: 'E',
    require: '^^parent',
    template: "<div><h1>Child Two</h1><h2>Value below should be: {{searchTerm}}</h2><h2>{{arrayContainingSearchTerm}}</h2></div>",
    link: function(scope, element, attrs, parentController) {
       // Comment/remove this since the scope is automatically inherit from parent scope
      //scope.arrayContainingSearchTerm = parentController.arrayContainingSearchTerm;
      //scope.searchTerm = parentController.searchTerm;
       // scope.arrayContainingSearchTerm = parentController.arrayContainingSearchTerm;

    }
  }
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>


<div ng-app="SampleApplication">
  <parent>
    <child-one></child-one>
    <child-two></child-two>
  </parent>
</div>

Upvotes: 1

Zoltan Toth
Zoltan Toth

Reputation: 47685

Your second directive is not aware of changes you're making afterwards - you need to $watch them:

var app = angular
.module('SampleApplication', [])
.directive('parent', function() {
  return {
    restrict: 'E',
    transclude: true,
    template: "<div ng-transclude></div>",
    controller: function($scope) {
      this.searchTerm = "";
      this.arrayContainingSearchTerm = [{value: ''}];

      this.updateSearchTerm = function(searchTerm) {
        this.searchTerm = searchTerm;

        //When this array is assigned - it doesn't get updated in the view
        this.arrayContainingSearchTerm = [{value: searchTerm}];

        //This will update the view.
        //this.arrayContainingSearchTerm.length = 0;
        //this.arrayContainingSearchTerm.push([{value: searchTerm}]);
      };

    }
  }
})
.directive('childOne', function() {
  return {
    restrict: 'E',
    require: '^^parent',
    template: "<div><h1>Child One</h1><input ng-model='searchTerm'></input></div>",
    link: function(scope, element, attrs, parentController) {
      scope.$watch('searchTerm', function(newValue, oldValue) {
        parentController.updateSearchTerm(newValue);
      });
    }
  }
})
.directive('childTwo', function() {
  return {
    restrict: 'E',
    require: '^^parent',
    template: "<div><h1>Child Two</h1><h2>Value below should be: {{searchTerm}}</h2><h2>{{arrayContainingSearchTerm}}</h2></div>",
    link: function(scope, element, attrs, parentController) {
      scope.arrayContainingSearchTerm = parentController.arrayContainingSearchTerm;
      scope.searchTerm = parentController.searchTerm;
      scope.$watch(function() {
        scope.arrayContainingSearchTerm = parentController.arrayContainingSearchTerm;
      });

    }
  }
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>


<div ng-app="SampleApplication">
  <parent>
    <child-one></child-one>
    <child-two></child-two>
  </parent>
</div>

Upvotes: 1

Related Questions