Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route to component: Support '&' bindings to callback functions #3111

Closed
marksq opened this issue Oct 26, 2016 · 5 comments
Closed

Route to component: Support '&' bindings to callback functions #3111

marksq opened this issue Oct 26, 2016 · 5 comments

Comments

@marksq
Copy link

marksq commented Oct 26, 2016

It looks like 1.0.0-beta3 is only working with '<' or '=' bindings with the state.component() syntax.

Do you plan to support '&' bindings like this:

.state('page', {
    url: '/page', 
    component: 'myPage', 
    resolve: {
        onUpdate: // Some method in Service, that call when user update a data 
    }
})

where the component is:

.component('child', {
    bindings: {
        onUpdate: '&'
    },
    ...
})

and in component's template

<form ng-submit="$ctrl.onUpdate(value)">...

?

@marksq marksq changed the title Support '&' bindings to update functions Support '&' bindings to callback functions Oct 26, 2016
@christopherthielen
Copy link
Contributor

christopherthielen commented Oct 26, 2016

the short answer is that you can use '<' binding for that

@christopherthielen
Copy link
Contributor

Reopening, since I agree that wiring a component's output (& binding) to a function returned by a resolve could be useful.

I propose that given this component:

.component('foo', {
  bindings: { onEvent: "&" },
  template: "<a ng-click='$ctrl.onEvent({ data: 123 })'>save 123</a>"
});

these examples should work:

example 1

(only works when unminified)

.state('foo', {
  component: 'foo',
  resolve: {
    onEvent: (ServiceAPI) => (data) => ServiceAPI.saveData(data)
  },
});

example 2

.state('foo', {
  component: 'foo',
  resolve: {
    onEvent: (ServiceAPI) => [ 'data', (data) => ServiceAPI.saveData(data) ]
  },
});

example 3

resolveFn.$inject = ['ServiceApi'];
function resolveFn(ServiceApi) {
  saveData.$inject = ['data'];
  function saveData(data) {
    ServiceAPI.saveData(data);
  }
  return saveData;
}
.state('foo', {
  component: 'foo',
  resolve: {
    onEvent: resolveFn
  },
});

The resolve is still invoked as usual when the state is entered. For this to work, the resolve must return a function. The "&" binding in the component will pass through to the returned function.

When the template is being created, the resolve function arguments are introspected. The function is faux injected using the locals passed by the component.


Generated templates:

Example 1 and 2:

<foo on-event="$resolve.onEvent(data)"></foo>

Example 3 (finds the last element of the array, which should be the fn)

<foo on-event="$resolve.onEvent[1](data)"></foo>

@christopherthielen christopherthielen added this to the 1.0.0-beta.4 milestone Jan 3, 2017
@christopherthielen christopherthielen changed the title Support '&' bindings to callback functions Route to component: Support '&' bindings to callback functions Jan 3, 2017
@orneryd
Copy link

orneryd commented Jan 9, 2017

IMO the usage of returning a function that takes event arguments is strange.
I would almost rather declare events separately from resolve and the usage be different rather than declaring a resolve and returning a function. It feels like we are overloading the intent of resolve.

If you think of it from the Ember perspective of the model resolver, the intent of model is to either return a promise or an object as the data model which is available on the related controller/component. Events are declared differently.

I feel like we should be able to create events that "require" a service on the route definition rather than injecting a service to a function that returns a function.
example:

EDIT:

$stateProvider.state('foo', {
  require: ['service1', 'service2'], //<-- requirable services available on resolve and event 'this' context. also inherited by child states. example, could be something like a redux service.
  events: {
    // not injectable, but requireable
    // this event would be available to bindings.
    onEvent: (eventData) => this.service2.handleEvent(data)
  },
  resolve: {
    dataModel: (service3) => this.service1.get(service3.result) //<-- returns data or a promise like today
  }
});

@christopherthielen
Copy link
Contributor

IMO the usage of returning a function that takes event arguments is strange.
I would almost rather declare events separately from resolve and the usage be different rather than declaring a resolve and returning a function. It feels like we are overloading the intent of resolve.

That's a good argument, and I mostly agree. I'm hesitant to increase the API surface area further, however.

@orneryd
Copy link

orneryd commented Jan 9, 2017

That's a good argument, and I mostly agree. I'm hesitant to increase the API surface area further, however.

I understand the hesitation. I do think however, a wider API surface that is more concise is easier to understand than an overloaded API surface that is more complex.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants