我很难找到任何关于通过数据库动态使用ui-router的文档。对于课程而言,一切都是硬编码的。
我的Json:
[
{
"name": "root",
"url": "/",
"parent": "",
"abstract": true,
"views": [
{"name": "header", "templateUrl": "/app/views/header.html"},
{"name" :"footer", "templateUrl": "/app/views/footer.html" }
]
},
{
"name": "home",
"url": "",
"abstract" : false,
"parent": "root",
"views": [
{"name": "container@", "templateUrl": "/app/views/content1.html"},
{"name" :"left@", "templateUrl": "/app/views/left1.html" }
]
},
{
"name": "about",
"url": "/about",
"abstract": false,
"parent": "root",
"views": [
{"name": "container@", "templateUrl": "/app/views/content2.html"},
{"name" :"left@", "templateUrl": "/app/views/left2.html" }
]
}
]
我的应用:
'use strict';
var $stateProviderRef = null;
var $urlRouterProviderRef = null;
var app = angular.module('app', ['ngRoute', 'ui.router']);
app.factory('menuItems', function ($http) {
return {
all: function () {
return $http({
url: '/app/jsonData/efstates.js',
method: 'GET'
});
}
};
});
app.config(function ($locationProvider, $urlRouterProvider, $stateProvider) {
$urlRouterProviderRef = $urlRouterProvider;
$stateProviderRef = $stateProvider;
$locationProvider.html5Mode(false);
$urlRouterProviderRef.otherwise("/");
});
app.run(['$q', '$rootScope', '$state', 'menuItems',
function ($q, $rootScope, $state, menuItems) {
menuItems.all().success(function (data) {
angular.forEach(data, function (value, key) {
$stateProviderRef.state(name = value.name, {
"url": value.url,
"parent" : value.parent,
"abstract": value.abstract,
"views": {
// do not want the below hard coded, I want to loop
// through the respective json array objects and populate state & views
// I can do this with everything but views.
// first loop
'header': { 'templateUrl': '/app/views/header.html' },
'footer': { 'templateUrl': '/app/views/footer.html' },
// second loop
'left@': { 'templateUrl': '/app/views/left1.html' },
'container@': { 'templateUrl': '/app/views/container1.html' },
// third loop
'left@': { 'templateUrl': '/app/views/left2.html' },
'container@': { 'templateUrl': '/app/views/container2.html' },
}
});
});
$state.go("home");
});
}]);
我正在动态配置我的视图。有什么想法吗?
更新
我根据RadimKöhler的答案为所有感兴趣的人做了Plunker。我很感激帮助。
我认为ui-router是角度的事实路由器,并且通过动态,它将使大型应用程序更容易管理。
答案 0 :(得分:23)
有plunker显示我们如何动态配置视图。 .run()
的更新版本如下:
app.run(['$q', '$rootScope', '$state', '$http',
function ($q, $rootScope, $state, $http)
{
$http.get("myJson.json")
.success(function(data)
{
angular.forEach(data, function (value, key)
{
var state = {
"url": value.url,
"parent" : value.parent,
"abstract": value.abstract,
"views": {}
};
// here we configure the views
angular.forEach(value.views, function (view)
{
state.views[view.name] = {
templateUrl : view.templateUrl,
};
});
$stateProviderRef.state(value.name, state);
});
$state.go("home");
});
}]);
检查所有操作here
答案 1 :(得分:19)
我必须附加一个改进的版本,即可以做更多的版本。
所以,现在我们仍然会动态加载状态 - 使用$http
,json
并定义.run()
中的状态
但是现在我们可以使用url 导航到任何动态状态(只需将其放在地址栏中)。
魔术内置于UI-Router中 - 请参阅doc:
的这一部分
deferIntercept(defer)
禁用(或启用)延迟位置更改拦截。
如果您希望自定义同步URL 的行为(例如,如果您希望延迟转换但保留当前URL),请在配置时调用此方法。然后,在运行时,在配置了自己的$ locationChangeSuccess事件处理程序后调用
$urlRouter.listen()
。
Cited片段:
var app = angular.module('app', ['ui.router.router']);
app.config(function($urlRouterProvider) {
// Prevent $urlRouter from automatically intercepting URL changes;
// this allows you to configure custom behavior in between
// location changes and route synchronization:
$urlRouterProvider.deferIntercept();
}).run(function($rootScope, $urlRouter, UserService) {
$rootScope.$on('$locationChangeSuccess', function(e) {
// UserService is an example service for managing user state
if (UserService.isLoggedIn()) return;
// Prevent $urlRouter's default handler from firing
e.preventDefault();
UserService.handleLogin().then(function() {
// Once the user has logged in, sync the current URL
// to the router:
$urlRouter.sync();
});
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.listen();
});
所以updated plunker is here。我们现在甚至可以使用.otherwise()
导航到最近定义的状态,或者通过url去那里:
.config()
阶段
app.config(function ($locationProvider, $urlRouterProvider, $stateProvider) {
// Prevent $urlRouter from automatically intercepting URL changes;
// this allows you to configure custom behavior in between
// location changes and route synchronization:
$urlRouterProvider.deferIntercept();
$urlRouterProvider.otherwise('/other');
$locationProvider.html5Mode({enabled: false});
$stateProviderRef = $stateProvider;
});
.run()
阶段
app.run(['$q', '$rootScope','$http', '$urlRouter',
function ($q, $rootScope, $http, $urlRouter)
{
$http
.get("myJson.json")
.success(function(data)
{
angular.forEach(data, function (value, key)
{
var state = {
"url": value.url,
"parent" : value.parent,
"abstract": value.abstract,
"views": {}
};
angular.forEach(value.views, function (view)
{
state.views[view.name] = {
templateUrl : view.templateUrl,
};
});
$stateProviderRef.state(value.name, state);
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.sync();
$urlRouter.listen();
});
}]);
答案 2 :(得分:4)
我研究了动态添加路由到ui.router
的不同方法。
首先,我发现了ngRouteProvider的repositori及其主要思想,正在解析$stateProvider
并将其保存在.config
阶段的闭包中,然后在任何其他时间使用此参考即时添加新的路径。这是个好主意,可能会有所改进。我认为更好的解决方案是将保存提供者参考的责任分开,并在任何时间和地点操纵它们。查看refsProvider
:
angular
.module('app.common', [])
.provider('refs', ReferencesProvider);
const refs = {};
function ReferencesProvider() {
this.$get = function () {
return {
get: function (name) {
return refs[name];
}
};
};
this.injectRef = function (name, ref) {
refs[name] = ref;
};
}
使用refsProvider
:
angular.module('app', [
'ui.router',
'app.common',
'app.side-menu',
])
.config(AppRouts)
.run(AppRun);
AppRouts.$inject = ['$stateProvider', '$urlRouterProvider', 'refsProvider'];
function AppRouts($stateProvider, $urlRouterProvider, refsProvider) {
$urlRouterProvider.otherwise('/sign-in');
$stateProvider
.state('login', {
url: '/sign-in',
templateUrl: 'tpl/auth/sign-in.html',
controller: 'AuthCtrl as vm'
})
.state('register', {
url: '/register',
templateUrl: 'tpl/auth/register.html',
controller: 'AuthCtrl as vm'
});
refsProvider.injectRef('$urlRouterProvider', $urlRouterProvider);
refsProvider.injectRef('$stateProvider', $stateProvider);
}
AppRun.$inject = ['SectionsFactory', 'MenuFactory', 'refs'];
function AppRun(sectionsFactory, menuFactory, refs) {
let $stateProvider = refs.get('$stateProvider');
// adding new states from different places
sectionsFactory.extendStates($stateProvider);
menuFactory.extendStates($stateProvider);
}
SectionsFactory
和MenuFactory
是声明/加载所有州的常见位置。
其他想法只是使用现有的角度应用程序阶段,并通过其他提供程序扩展应用程序状态,如:
angular.module('app.side-menu', []);
.provider('SideMenu', SideMenuProvider);
let menuItems = [
{
label: 'Home',
active: false,
icon: 'svg-side-menu-home',
url: '/app',
state: 'app',
templateUrl: 'tpl/home/dasboard.html',
controller: 'HomeCtrl'
}, {
label: 'Charts',
active: false,
icon: 'svg-side-menu-chart-pie',
url: '/charts',
state: 'charts',
templateUrl: 'tpl/charts/main-charts.html'
}, {
label: 'Settings',
active: false,
icon: 'svg-side-menu-settings',
url: '/'
}
];
const defaultExistState = menuItems[0].state;
function SideMenuProvider() {
this.$get = function () {
return {
get items() {
return menuItems;
}
};
};
this.extendStates = ExtendStates;
}
function ExtendStates($stateProvider) {
menuItems.forEach(function (item) {
if (item.state) {
let stateObj = {
url: item.url,
templateUrl: item.templateUrl,
controllerAs: 'vm'
};
if (item.controller) {
stateObj.controller = `${item.controller} as vm`;
}
$stateProvider.state(item.state, stateObj);
} else {
item.state = defaultExistState;
}
});
}
在这种情况下,我们无需使用.run
阶段来扩展状态,而上述示例中的AppRouts
将更改为:
AppRouts.$inject = ['$stateProvider', '$urlRouterProvider', 'SideMenuProvider'];
function AppRouts($stateProvider, $urlRouterProvider, SideMenuProvider) {
$urlRouterProvider.otherwise('/sign-in');
$stateProvider
.state('login', {
url: '/sign-in',
templateUrl: 'tpl/auth/sign-in.html',
controller: 'AuthCtrl as vm'
})
.state('register', {
url: '/register',
templateUrl: 'tpl/auth/register.html',
controller: 'AuthCtrl as vm'
})
SideMenuProvider.extendStates($stateProvider);
}
此外,我们仍然可以访问任何地方的所有菜单项:SideMenu.items