0

I have a parent component that has a child component.

<child-component></child-component>

The child component has a function:

$ctrl.alertMe = function() {
   alert('me');
}

How can I call this from using a binding via the parent component?

i.e. something of the sort...

<child-component alert-child="alertChild"></child-component>
KingKongFrog
  • 13,946
  • 21
  • 75
  • 124
  • Have you considered using $rootScope.$broadcast()? Just send messages from parent to child scopes – kane Feb 01 '19 at 22:37
  • @kane I prefer bindings since that keeps communications in one place and doesn't get lost. – KingKongFrog Feb 01 '19 at 22:38
  • I've never tried this in angular, but what if you created a listener/subscriber pattern. When a child is initiated, it adds itself to the parent's list of subscribers. When user activates parent's function, it iterates over subscribers and calls a predetermined func like execute() in the child/subscriber. – kane Feb 01 '19 at 23:00
  • Hey, check my answer here https://stackoverflow.com/questions/53910880/trigger-an-attribute-as-function-of-angularjs-directive/53911070#53911070 – Majesty Feb 02 '19 at 06:19

2 Answers2

0

I created a jsfiddle based on the subscriber pattern I described in my comment to you. jsfiddle here

Here are the relevant pieces of it in case jsfiddle goes down.

HTML

<div ng-app
     id="parent"
     ng-controller="parentCtrl">
  <button ng-click="alert()">click me</button>

  <div ng-controller="childCtrl">

  </div>
</div>

Javascript

function parentCtrl($scope) {
  $scope.alert = function() {
    for(var i=0; i<subscribers.length; i++) {
      subscribers[i].execute();
    }
  }

  var subscribers = [];

  $scope.subscribe = function(child) {
    console.log('adding child');
    subscribers.push(child);
  }
}

function childCtrl($scope) {
  this.init = function() {
    $scope.$parent.subscribe(this);
  }
  this.init();
  this.execute = function() {
    console.log('i am child. hear me roar');
  }
}
kane
  • 5,465
  • 6
  • 44
  • 72
0

If you don't mind using two-way binding, you can accomplish this by having the child component assign the function you want to invoke from the parent within the $onInit lifecycle hook. Thereafter, you should be able to access that child function through the parent controller.

angular
  .module('app', [])
  .component('parentComponent', {
    controller: function () {
      var $ctrl = this;
      $ctrl.action = function () {
        // Will be set by child component
        $ctrl.alertChild();
      };
    },
    template: `
      <button type="button" ng-click="$ctrl.action()">Action</button>
      <child-component alert-child="$ctrl.alertChild"></child-component>
    `,
  })
  .component('childComponent', {
    bindings: {
      alertChild: '=',
    },
    controller: function () {
      var $ctrl = this;
      $ctrl.$onInit = function () {
        $ctrl.alertChild = alertChild;
      };
      function alertChild() {
        console.log('alert from child');
      }
    },
  });
<script src="https://unpkg.com/angular@1.7.6/angular.min.js"></script>
<div ng-app="app">
  <parent-component></parent-component>
</div>
miqh
  • 3,624
  • 2
  • 28
  • 38
  • This is what I'm looking for. However how do I systematically invoke this from the parent controller? Your example works in the template. But what if I want to execute it from the parent? – KingKongFrog Feb 01 '19 at 23:59
  • @KingKongFrog, I've updated my example snippet with a definition for the parent controller to hopefully clarify the invocation. If instead you're looking for a means to gain access to the child function in the parent controller without providing an explicit binding via the template, you'll have to turn to another approach such as broadcasting events. – miqh Feb 02 '19 at 01:20