使用包含多个绑定的组件配置 ui-router
Configure ui-router with components containing multiple bindings
我正在尝试找到一个更好的解决方案来将 ui-router
与 angular components
一起使用。
考虑两个简单的组件:
app.component('componentOne', {
template: '<h1>My name is {{$ctrl.name}}, I am {{$ctrl.age}} years old.</h1>',
bindings : {
name : '@',
age : '@'
}
}
);
app.component('componentTwo', {
template: '<h1>I am component 2</h1>'
});
现在,我正在使用 template
属性:
指定组件及其参数
app.config(function($stateProvider, $urlRouterProvider ){
$stateProvider
.state('component1', {
url: "/component1",
template: "<component-one name=\"foo\" age=\"40\"></component-one>"
})
.state('component2', {
url: "/component2",
template: "<component-two></component-two>"
})
});
虽然这工作正常,但我有大约十个绑定的组件,这使得 ui-router
的配置非常尴尬 。
我尝试使用 component
属性 但这对我根本不起作用。我找到的唯一其他解决方案是使用 require
属性 指定父级并省略绑定 - 但这对我来说不合适......有没有更好的方法来做到这一点?
这里是plnkr.
或者,您可以将绑定向下移动一个级别并创建一个将成为唯一绑定的对象。如果 10 个绑定是困扰您的问题。
您可以尝试的一种替代方法是通过 $stateChangeStart
事件中状态的自定义属性覆盖模板。
运行 像这样阻止以实现这种行为。
app.run(function($rootScope){
//listen to $stateChangeStart
$rootScope.$on("$stateChangeStart",function(event, toState, toParams, fromState, fromParams, options){
//if the component attribute is set, override the template
if(toState.component){
//create element based on the component name
var ele = angular.element(document.createElement(camelCaseToDash(toState.component)));
//if there is any binding, add them to the element's attributes.
if(toState.componentBindings){
angular.forEach(toState.componentBindings,function(value,key){
ele.attr(key,value)
})
}
//you may also do something like getting bindings from toParams here
//override the template of state
toState.template = ele[0].outerHTML;
}
})
//convert camel case string to dash case
function camelCaseToDash(name) {
return name.replace(/([a-z])([A-Z])/g, '-').toLowerCase();
}
})
有了这个,现在您可以在您的状态配置中拥有 component
属性。
app.config(function($stateProvider, $urlRouterProvider ){
$stateProvider
.state('component1', {
url: "/component1",
component:"componentOne",
componentBindings:{
name:"foo",
age:"40",
}
})
.state('component2', {
url: "/component2",
component:"componentTwo",
})
});
这是工作 plunker。
你的配置函数可能还是比较大,但看起来不会那么突兀。
UI-路由器 component:
路由存在于 UI-路由器 1.0+(当前为 1.0.0-beta.1)
这是一个更新的插件:https://plnkr.co/edit/VwhnAvE7uNnvCkrrZ72z?p=preview
绑定静态值
要将静态数据绑定到组件,请使用 component
和 returns 静态数据的解析块。
$stateProvider.state('component1', {
url: "/component1",
component: 'componentOne',
resolve: { name: () => 'foo', age: () => 40 }
})
绑定异步值
要绑定异步值,请使用 returns 承诺的数据解析。请注意,一个解决方案可能取决于不同的解决方案:
$stateProvider.state('component1Async', {
url: "/component1Async",
component: "componentOne",
resolve: {
data: ($http) => $http.get('asyncFooData.json').then(resp => resp.data),
name: (data) => data.name,
age: (data) => data.age
}
});
绑定很多值
您提到您在一个组件上有 10 个绑定。根据您绑定的数据结构,您可以使用 JavaScript 构建 resolve
块(毕竟是 "just javascript")
var component2State = {
name: 'component2',
url: '/component2',
component: 'componentTwo',
resolve: {
data: ($http) => $http.get('asyncBarData.json').then(resp => resp.data)
}
}
function addResolve(key) {
component2State.resolve[key] = ((data) => data[key]);
}
['foo', 'bar', 'baz', 'qux', 'quux'].forEach(addResolve);
$stateProvider.state(component2State);
我正在尝试找到一个更好的解决方案来将 ui-router
与 angular components
一起使用。
考虑两个简单的组件:
app.component('componentOne', {
template: '<h1>My name is {{$ctrl.name}}, I am {{$ctrl.age}} years old.</h1>',
bindings : {
name : '@',
age : '@'
}
}
);
app.component('componentTwo', {
template: '<h1>I am component 2</h1>'
});
现在,我正在使用 template
属性:
app.config(function($stateProvider, $urlRouterProvider ){
$stateProvider
.state('component1', {
url: "/component1",
template: "<component-one name=\"foo\" age=\"40\"></component-one>"
})
.state('component2', {
url: "/component2",
template: "<component-two></component-two>"
})
});
虽然这工作正常,但我有大约十个绑定的组件,这使得 ui-router
的配置非常尴尬 。
我尝试使用 component
属性 但这对我根本不起作用。我找到的唯一其他解决方案是使用 require
属性 指定父级并省略绑定 - 但这对我来说不合适......有没有更好的方法来做到这一点?
这里是plnkr.
或者,您可以将绑定向下移动一个级别并创建一个将成为唯一绑定的对象。如果 10 个绑定是困扰您的问题。
您可以尝试的一种替代方法是通过 $stateChangeStart
事件中状态的自定义属性覆盖模板。
运行 像这样阻止以实现这种行为。
app.run(function($rootScope){
//listen to $stateChangeStart
$rootScope.$on("$stateChangeStart",function(event, toState, toParams, fromState, fromParams, options){
//if the component attribute is set, override the template
if(toState.component){
//create element based on the component name
var ele = angular.element(document.createElement(camelCaseToDash(toState.component)));
//if there is any binding, add them to the element's attributes.
if(toState.componentBindings){
angular.forEach(toState.componentBindings,function(value,key){
ele.attr(key,value)
})
}
//you may also do something like getting bindings from toParams here
//override the template of state
toState.template = ele[0].outerHTML;
}
})
//convert camel case string to dash case
function camelCaseToDash(name) {
return name.replace(/([a-z])([A-Z])/g, '-').toLowerCase();
}
})
有了这个,现在您可以在您的状态配置中拥有 component
属性。
app.config(function($stateProvider, $urlRouterProvider ){
$stateProvider
.state('component1', {
url: "/component1",
component:"componentOne",
componentBindings:{
name:"foo",
age:"40",
}
})
.state('component2', {
url: "/component2",
component:"componentTwo",
})
});
这是工作 plunker。
你的配置函数可能还是比较大,但看起来不会那么突兀。
UI-路由器 component:
路由存在于 UI-路由器 1.0+(当前为 1.0.0-beta.1)
这是一个更新的插件:https://plnkr.co/edit/VwhnAvE7uNnvCkrrZ72z?p=preview
绑定静态值
要将静态数据绑定到组件,请使用 component
和 returns 静态数据的解析块。
$stateProvider.state('component1', {
url: "/component1",
component: 'componentOne',
resolve: { name: () => 'foo', age: () => 40 }
})
绑定异步值
要绑定异步值,请使用 returns 承诺的数据解析。请注意,一个解决方案可能取决于不同的解决方案:
$stateProvider.state('component1Async', {
url: "/component1Async",
component: "componentOne",
resolve: {
data: ($http) => $http.get('asyncFooData.json').then(resp => resp.data),
name: (data) => data.name,
age: (data) => data.age
}
});
绑定很多值
您提到您在一个组件上有 10 个绑定。根据您绑定的数据结构,您可以使用 JavaScript 构建 resolve
块(毕竟是 "just javascript")
var component2State = {
name: 'component2',
url: '/component2',
component: 'componentTwo',
resolve: {
data: ($http) => $http.get('asyncBarData.json').then(resp => resp.data)
}
}
function addResolve(key) {
component2State.resolve[key] = ((data) => data[key]);
}
['foo', 'bar', 'baz', 'qux', 'quux'].forEach(addResolve);
$stateProvider.state(component2State);