What is the best way to pass functions between inner components in AngularJS 1.5?
Asked Answered
T

1

13

I was wondering what is the best way to pass functions down through 2 or more levels of components? There's no simple way of skipping the function wrap when using '&' bindings?

Here's an use case:

angular.module('app', []).component('app', {
  controller: class AppController {
    doSomething (data) {}
  },
  template: `
    <sub-component on-do-something="$ctrl.doSomething(data)">
    </sub-component>
  `
})

ps: I'm using ngRedux, so such scenario is very common

EDIT:

The problem is: for the code above to work, each inner component controller would look like this:

.component('subComponent', {
    bindings: {
        doSomething: '&'
    },
    controller: function SubComponentController () {
        this._doSomething = param => this.doSomething({data: param});
    },
    template: `
        <inner-component do-something="$ctrl._doSomething(data)">
        </inner-component>
    `
});

.component('innerComponent', {
    bindings: {
        doSomething: '&'
    },
    controller: function InnerComponentController () {
        this._doSomething = param => this.doSomething({data: param});
    },
    template: `
        <sub-inner-component do-something="$ctrl._doSomething(data)">
        </sub-inner-component>
    `
});

And then I'd have to pass down _doSomething instead of doSomething directly.

ps: I'm not using transclusion here

Translocation answered 23/1, 2016 at 1:47 Comment(6)
@DmitriZaitsev that isn't the ideal solution given that I'm using redux and the concepts of smart & dumb components :(Translocation
Can you explain what you mean by the function wrap?Affair
Also it is not clear from your example whether the inner HTML is transcluded or whether it is part of the inner components' templates.Affair
@PeteBD I am editing the question right now :)Translocation
You can pass data via props or services aka Redux stores.Eba
@PeteBD added more info, please refresh! And thanks for your helpTranslocation
A
34

It is not necessary to provide a wrapper function in the controller of your sub-components. By using bindings a function is automatically attached to the controller, which you can call directly from your template.

The only wrinkle is that this function takes an object, which contains the locals that will be made available to the expression in the outer template.

In this case the data variable in the outer template needs to be provided explicitly when call the the doSomething(locals) method.

angular.module('app', [])

.component('app', {
  controller: class AppController {
    doSomething (data) {
      console.log(data);
    }
  },
  template: `
    <sub-component do-something="$ctrl.doSomething(data)">
    </sub-component>
  `
})

.component('subComponent', {
    bindings: {
        doSomething: '&'
    },
    template: `
        <inner-component do-something="$ctrl.doSomething({data: data})">
        </inner-component>
    `
})

.component('innerComponent', {
    bindings: {
        doSomething: '&'
    },
    template: `
        <sub-inner-component do-something="$ctrl.doSomething({data: data})">
        </sub-inner-component>
    `
})

.component('subInnerComponent', {
  bindings: {
    doSomething: '&'
  },
  template: `
      <button ng-click="$ctrl.doSomething({data: 123})">Do Something</button>
  `
});

Here is a working Plunker : http://plnkr.co/edit/QQF9jDGf6yiewCRs1EDu?p=preview

Affair answered 25/1, 2016 at 10:43 Comment(2)
Wow. It still gets a little bit confusing when I think about how Angular translates the initial {data: 123} to local variables in the parent expression, but it works. I guess I'll be digging a little bit more in Angular source until I fully understand. Thanks @PeteBDTranslocation
Great example. Biiiiiiiiiiiiig like :)Carrero

© 2022 - 2024 — McMap. All rights reserved.