1

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

3
  • please update your code into a working snippet and i'll be happy to take a look. Commented Jan 9, 2017 at 19:25
  • @PhilPoore incoming, much appreciated Commented Jan 9, 2017 at 19:27
  • @PhilPoore if your offer still stands - plnkr.co/edit/UG20EtI4KxnVnTe8zzz4?p=preview Commented Jan 9, 2017 at 20:16

2 Answers 2

1

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

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

5 Comments

Thanks - edited. Still not getting the stuff from the parent
You don't have parent scopes, they are always isolated scopes. See the link. You can require the parent controller and inject it.
Yeah I understand but I thought that via bindings I should be able to make scope from the parent element (ie the div with the ng-repeat) available to the item-component within the ng-repeat. Surely that is possible somehow without doing the hacky stuff accessing $scope.$parent.item (which does work but defeats the isolated scope idea)
in reference to the doc what I am talking about is the "Intercomponent Communication" in a "Component Tree"
When yu look at the table in the link, you have two options, either by using bindings or require. It seems you now found the first way, which is the better one.
0

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

1 Comment

You can bind a function the same way by using the & binding. onDelete and onUpdate are just examples.

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.