TkNeo
TkNeo

Reputation: 523

Angular 1.5, Calling a function in a component from Parent controller

Angular 1.5 components easily allow creating a call back to the parent from the component. Is there a way i can call a function in a component from a function in parent's controller ?

Lets say my component is called task-runner and below is the HTML for it in the parent container.

<task-runner taskcategogyid=5></task-runner>

 <button type="button" ng-click="doSomethingInParent()">ParentToChildButton</button>

The plunkr is here. I want that when ParentToChildButton is clicked, the function doSomethingInParent() calls the remotefunc in component.

Upvotes: 29

Views: 29745

Answers (2)

rdrw
rdrw

Reputation: 793

I needed something like this previously so I thought I would share how I solved this problem.

Similar to the OP, I needed to freely trigger methods in child components from a parent component. I wanted to be able to trigger this method in the parent freely/separately without the use of the $onChanges lifecycle hook.

Instead I created a notification-registration mechanism to allow a child component to 'register' a method with the parent when it is loaded. This method can then be freely triggered by the parent outside of the $onChanges cycle.

I created a codepen to demonstrate this. It can be easily extended to handle different types of notifications from the parent that aren't related to the data changes.

Index.html

<div ng-app="tester">
  <parent></parent>
</div>

Script.js

angular.module('tester', []);

angular.module('tester').component('parent', {
  controller: parentController,
  template: `
    <div class="tester-style">
      <button ng-click="$ctrl.notifyChild()">Notify child</button>
      <child parent-to-child-notification-registration="$ctrl.childComponentNotificationRegistration(handler)">
    </div>
  `
});

function parentController() {
  let childComponentEventHandler = null;

  this.$onInit = function() {
    this.value = 0;
  };

  this.childComponentNotificationRegistration = function(handler) {
    childComponentEventHandler = handler;
    console.log('Child component registered.');
  };

  this.notifyChild = function() {
    if (childComponentEventHandler) {
      childComponentEventHandler(this.value++);
    }
  };
}

angular.module('tester').component('child', {
  bindings: {
    parentToChildNotificationRegistration: '&',
  },
  controller: childController,
  template: `
    <div class="tester-style">
      <h4>Child Component</h4>
    </div>
  `
});

function childController() {
  this.$onInit = function() {
    this.parentToChildNotificationRegistration({
      handler: this.processParentNotification
    });
  };

  this.processParentNotification= function(parentValue) {
    console.log('Parent triggered child notification handler!!!');
    console.log('Value passed to handler:', parentValue);
  };
};

}

Also for something similar to @adam0101's #3 answer see codepen.

Upvotes: 19

adam0101
adam0101

Reputation: 30995

A few different ways:

  1. Pass an object as an attribute with two-way binding (scope:{myattr:'='}) to the task-item-header directive which the directive could then add a function to for the parent controller to call.
  2. Set an attribute that has either one-way binding (scope:{myattr:'@'}) on it and then attrs.$observe changes to it to trigger the action, or two-way binding (scope:{myattr:'='}) and then $scope.$watch changes to it to trigger the action.
  3. Have the directive raise an event (scope:{raiseLoaded:'&onLoaded'}) that passes an object that represents a remote control object with a method on it that triggers the action you want. To raise the event, you'd call something like raiseLoaded({remoteControl: remoteControlObj}) within the directive, and then to listen to the event, you'd use <task-item-header on-loaded="setRemote(remoteControl)"> assuming you have a setRemote() method on your parent controller.

Update I just realized your question was for a newer version of AngularJS, so I'm not sure if my answer still applies. I'll leave it here for now, but if you find it is not helpful I can delete it.

Upvotes: 21

Related Questions