29

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.

3
  • Please add component definition. Commented May 13, 2016 at 16:59
  • Components = docs.angularjs.org/guide/component Commented May 13, 2016 at 17:20
  • No I meant your code, for your component. Not the definition of what a component is. The actual JS part. Commented May 13, 2016 at 17:22

2 Answers 2

21

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Can you please elaborate on #3 ? Its not clear to me which property is set in the parent (component container) and which property is set in the component ? I have added a plunkr to my original post. I want that when i click parenttochildbutton the remotefunc() in component is called with alert(5)
You can delete it as it can cause people to think its already answered.
@TkNeo, I modified your plunkr to do as I describe in #3: plnkr.co/edit/vRVZB9EhhZd4sYTGoPvC?p=info
19

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.

1 Comment

Regarding this answer, one may simplify by claiming ctrl.onXxEvt = {} in the parent controller; then claiming onXxEvt="$ctrl.onXxEvt" at the child-component anchor in the parent template; and then claiming in the child's controller's $onInit that ctrl.onXxEvt.handler = xxEvtHander. Now you can call ctrl.onXxEvt.handler in the parent controller, which will invoke xxEvtHander in the child controller. This avoides the explicit registration method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.