Description
I'd like to solicit some feedback from the community about routing to ng1 .component()
s.
Backstory
We recently added support for $scope.$resolve
to the master
and legacy
branches. After the next release, you will be able to route to components, and access resolved data using a "component template", similar to ngRoute. Here's a proof of concept: http://plnkr.co/edit/mG9W1q6B4CCHI6QEfKSJ
In angular2, however, we cannot use "component templates", and instead will be routing to a component class. In ui-router-ng2, you will supply the component's class in a state definition, probably something like this:
import {FooComponent} from "./fooComponent.js";
import {UIRouter, StateRegistry} from "ui-router-ng2";
let stateRegistry = uirouter.stateRegistry; // uirouter instance comes from somewhere
stateRegistry.state({
name: 'foo',
component: FooComponent, // Reference to the FooComponent class
url: '/foo/:fooId'
}
I would like both ui-router for ng1 and for ng2 to have a similar look and feel when routing to components. Because of that, I'm considering allowing component:
in a state definition for ui-router 1.0 for ng1.
There are a few mechanisms I've been tossing around as options for declaring a state's view should route to a component, and how to provide resolved data to that component. Note that we can't use constructor injection into a .component()
to provide resolve data like we would for a normal ui-router template/controller combo, because we can not instantiate and manage the component lifecycle ourselves.
Given this angular 1.5 .component()
app.component('myComponent', {
templateUrl: 'myComponent.html',
controller: 'MyController',
bindings: { input1: '<', input2: '<' }
});
Options
Option 1: Keep it as-is. Use a template:
and access data using $resolve
.
$stateProvider.state('foo', {
template: '<my-component input1="$resolve.foo" input2="$resolve.bar"></my-component>',
url: '/foo/:fooId/:barId',
resolve: {
foo: ($stateParams, FooService) => FooService.get($stateParams.fooId),
bar: ($stateParams, BarService) => BarService.get($stateParams.barId)
}
});
Option 2: Route to the component by name.
Require each component bindings
to match a resolve name
$stateProvider.state('foo', {
component: 'myComponent',
url: '/foo/:fooId/:barId',
resolve: {
// input1 and input2 are same names as myComponent `bindings`
input1: ($stateParams, FooService) => FooService.get($stateParams.fooId),
input2: ($stateParams, BarService) => BarService.get($stateParams.barId)
}
});
Option 3: Route to the component by name + bindings mapping string
Allow resolve names to be mapped to component bindings
using a DSL similar to ui-sref
The use case is that resolves may come from parent states, so may need to be mapped to the component bindings
$stateProvider.state('foo', {
component: 'myComponent({ input1: foo, input2: bar })',
url: '/foo/:fooId/:barId',
resolve: {
foo: ($stateParams, FooService) => FooService.get($stateParams.fooId),
bar: ($stateParams, BarService) => BarService.get($stateParams.barId)
}
});
Option 4: Route to the component by name + bindings mapping object
Allow resolve names to be mapped to component bindings
using an object
Again, the use case is that resolves may come from parent states, so may need to be mapped to the component bindings
$stateProvider.state('foo', {
component: 'myComponent',
bindings: { input1: "foo", input2: "bar" },
url: '/foo/:fooId/:barId',
resolve: {
foo: ($stateParams, FooService) => FooService.get($stateParams.fooId),
bar: ($stateParams, BarService) => BarService.get($stateParams.barId)
}
});
Option 5: Route to the component by name; Supply resolves via ui-view controller
For this option, the component has to be aware that it's inside of a ui-view. It require
s the ui-view controller and accesses the resolves from there. The bindings
object is not used.
app.component('myComponent', {
templateUrl: 'myComponent.html',
controller: function() {
this.$onInit = function() {
this.input1 = this.uiView.$resolve.foo;
this.input2 = this.uiView.$resolve.bar;
}
},
require: { uiView: '^uiView' }
});
$stateProvider.state('foo', {
component: 'myComponent',
url: '/foo/:fooId/:barId',
resolve: {
foo: ($stateParams, FooService) => FooService.get($stateParams.fooId),
bar: ($stateParams, BarService) => BarService.get($stateParams.barId)
}
});