jmls
jmls

Reputation: 2969

Angular '&' Binding and parameters

I am trying to write a component called "foo" - this component takes a label, and says "hello {{$ctrl.label}}". It also invokes a callback function on click

<foo label="'bar'" callback="$ctrl.myCallback()"</foo>

All well and good so far. My controller does indeed get the callback

So now I put this element into a ng-repeat: <foo ng-repeat="item in $ctrl.items" label="item.label" callback="$ctrl.myCallback(item)></foo>

How do I define in the component what to pass back into the controller on a click ? The component does not have item passed to it, only the "label".

From what I've read, I need to say something like this.callback({item: SomeObject});

I have 2 questions here: 1) how does the component know that it needs to supply the "item" key and 2) how does the component know what SomeObject is ?

I could easily reuse the component in another ng-repeat: <foo ng-repeat="order in $ctrl.orders" label="order.orderNum" callback="$ctrl.myCallback(order)></foo>

and in this case, how does the component know to send the order object as a parameter to the click callback function ?

Upvotes: 1

Views: 3783

Answers (1)

lenilsondc
lenilsondc

Reputation: 9800

The component doesn't know much about it, you know, your unit test know and your e2e tests knows (may be), but the component only know that it has a callback (with named arguments) and a property and their way-binding, that's what is needed to do the bindings. Also, you don't have to pass anything from the component side, unless you are sending the item object from the component, otherwise, just use a simple $ctr.callback() that the bind will call the $parent.myControllerFunction(item) from the ng-repeat scope.

When using & you create a delegate method to be called from the component according to the mask that you've created on the template. For example:

<ANY ng-repeat="item in items" callback="myCallBack(item)">
...
bindings: {
    callback: '&'
}
...

If from the component you call it like $ctrl.callback() it will use the item from ng-repeat scope. But if you want to send it from the component, then you have to pass an object with the name of the argument your were using on the template like $ctrl.callback({ item: { name: 'foo'}}) to fill the parameter declared on callback="myCallBack(item)".

angular
  .module('mBoard', [])
  .component('widget', {
    bindings: {
      item: '=',
      callback: '&'
    },
    controller: function() {

      var $ctrl = this;

      $ctrl.save = function() {
        //$ctrl.callback();
        $ctrl.callback({ item: { name : $ctrl.item.name + '%%%%' }});

      }
    },
    templateUrl: 'template.html'
  })
  .controller('mBoardCtrl', function mBoardCtrl($interval, $scope) {
    $scope.items = [{name: 'uno'}, {name: 'dos'}, {name: 'tres'}];
    $scope.setItem = function(item) {

      console.log(item)
    }
  });

/* https://docs.angularjs.org/guide/bootstrap */
angular.bootstrap(document, ['mBoard']);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.js"></script>
<div ng-controller="mBoardCtrl ">
  <widget ng-repeat="item in items" item="item" callback="setItem(item)"></widget>
  <hr>
  <widget ng-repeat="item in items" item="item" callback="setItem('quatorze')"></widget>


  <!-- https://docs.angularjs.org/api/ng/service/$templateCache -->
  <script type="text/ng-template" id="template.html">
    <button type="button" ng-click="$ctrl.save()">{{ $ctrl.item.name }}</button>
  </script>
</div>

Upvotes: 4

Related Questions