Mike Miller
Mike Miller

Reputation: 3129

Angular JS Component Bindings

I am having trouble making the item looped from an ng-repeat from a parent component available to the scope of a nested component. The parent component is a carousel which contains many item components. The carousel is populated by the ng-repeat. I want to be able to access the "item" and a method of the carousel controller ("cr") in the item controller ("it"). I guess I am going about this in the totally wrong way. Appreciate if anyone can give me a steer.

carousel.component.html

<slick <!--slick attributes--> >
     <div ng-repeat="item in cr.items">
            <item-component></item-component>
     </div>
</slick>

carousel.component.js

class CarouselController{
  constructor(/*stuff*/){
    'ngInject';    

     this.items =[
       {"something":"The thing 1","otherthing":"The other thing 1"},
       {"something":"The thing 2","otherthing":"The other thing 2"},
       {"something":"The thing 3","otherthing":"The other thing 3"}
     ];
  }

  parentFunctionToCall(item){
    console.log('I called a function on the parent!',item)
  }

  /*other stuff*/
}

export const CarouselComponent = {
  templateUrl: './views/app/components/carousel/carousel.component.html',
  controller: CarouselController,
  controllerAs: 'cr',
  bindings: {
  }
}

item.component.html

<div data-something="{{item.something}}">
  Yo,{{item.otherthing}}!
</div>

<a href="#" ng-click="cr.parentFunctionToCall(item)">
   Trying to call a function on the parent component
</a>

item.component.js

class ItemController{
  constructor($scope,/*stuff*/){
    'ngInject';

     //$scope.it.item & $scope.it.cr are both undefined
     console.log(this);

     //I understand this is the incorrect way but it works
     this.$scope.item = this.$scope.$parent.item;
     console.log(this);
  }

  /*other stuff*/
}

export const ItemComponent = {
  templateUrl: './views/app/components/carousel/item.component.html',
  controller: ItemController,
  controllerAs: 'it',
  bindings: {
    "item":"=",//i can see this as undefined $scope in ItemController
    "cr":"=" //i want to access a method on the parent controller
  }
}

This shows whats up... https://plnkr.co/edit/UG20EtI4KxnVnTe8zzz4?p=preview

Upvotes: 1

Views: 372

Answers (2)

Mike Miller
Mike Miller

Reputation: 3129

Frustratingly simple in the end.. I am not sure why this isnt made clearer in the documentation but its as easy as setting an attribute on the child component:

<slick <!--slick attributes--> >
  <div ng-repeat="item in cr.items">
        <!--new item="item" attr-->
        <item-component item="item" call-parent="cr.parentFunctionToCall(item)"></item-component>
  </div>
</slick>

Then the binding works as expected. Accessing a function on the parent behaves a similar way. Some event name needs to be added as an attribute (call-parent but this can be anything). The binding needs to be added to the child component (as in @kuhnroyals comment):

...
bindings: {
  item:"=",
  callParent: '&'
}

And some interaction event on the child component eg ng-click="it.callParent()"

Working example here: https://plnkr.co/edit/RIOPs6?p=preview

Upvotes: 0

kuhnroyal
kuhnroyal

Reputation: 7563

Using controllerAs you don't have a $scope, you need to use this. Especially with components.

this.items =[
   {"something":"The thing 1","otherthing","The other thing 1"},
   {"something":"The thing 2","otherthing","The other thing 2"},
   {"something":"The thing 3","otherthing","The other thing 3"}
 ];

See https://docs.angularjs.org/guide/component

Upvotes: 1

Related Questions