ege*_*ari 35 javascript breadcrumbs angularjs angular-ui
Web应用程序的一个关键组件是面包屑/导航.使用Angular UI路由器,将breadcrumb元数据与各个状态放在一起是有意义的,而不是在控制器中.手动为每个需要它的控制器创建面包屑对象是一项直接的任务,但它也是一个非常混乱的任务.
我已经看到了一些使用Angular的自动面包屑的解决方案,但说实话,它们相当原始.某些状态,如对话框或侧面板不应更新面包屑,但使用角度的当前插件,无法表达.
另一个问题是面包屑的标题不是静态的.例如,如果您转到"用户详细信息"页面,则面包屑标题应该是用户的全名,而不是通用的"用户详细信息".
需要解决的最后一个问题是使用父链接的所有正确的状态参数值.例如,如果您正在查看公司的用户详细信息页面,显然您会想知道父状态需要一个:companyId.
是否有角度的插件可以提供这种级别的面包屑支持?如果没有,最好的方法是什么?我不想让我的控制器混乱 - 我会有很多 - 我希望尽可能自动化和无痛.
谢谢!
ege*_*ari 41
我曾经自己解决了这个问题,因为没有任何东西可用.我决定不使用该data对象,因为我们实际上并不希望我们的breadcrumb标题被子项继承.有时会出现模式对话框和右侧面板,这些对话框在技术上是"儿童视图",但它们不应影响面包屑.通过使用breadcrumb对象,我们可以避免自动继承.
对于实际的title财产,我正在使用$interpolate.我们可以将面包屑数据与解析范围结合起来,而无需在不同的地方进行解析.在我所有的情况下,我只想使用解析范围,所以这非常有效.
我的解决方案也处理i18n.
$stateProvider
.state('courses', {
url: '/courses',
template: Templates.viewsContainer(),
controller: function(Translation) {
Translation.load('courses');
},
breadcrumb: {
title: 'COURSES.TITLE'
}
})
.state('courses.list', {
url: "/list",
templateUrl: 'app/courses/courses.list.html',
resolve: {
coursesData: function(Model) {
return Model.getAll('/courses');
}
},
controller: 'CoursesController'
})
// this child is just a slide-out view to add/edit the selected course.
// It should not add to the breadcrumb - it's technically the same screen.
.state('courses.list.edit', {
url: "/:courseId/edit",
templateUrl: 'app/courses/courses.list.edit.html',
resolve: {
course: function(Model, $stateParams) {
return Model.getOne("/courses", $stateParams.courseId);
}
},
controller: 'CourseFormController'
})
// this is a brand new screen, so it should change the breadcrumb
.state('courses.detail', {
url: '/:courseId',
templateUrl: 'app/courses/courses.detail.html',
controller: 'CourseDetailController',
resolve: {
course: function(Model, $stateParams) {
return Model.getOne('/courses', $stateParams.courseId);
}
},
breadcrumb: {
title: '{{course.name}}'
}
})
// lots more screens.
Run Code Online (Sandbox Code Playgroud)
我不想将面包屑绑定到指令,因为我认为在我的应用程序中可能有多种方式可视化地显示面包屑.所以,我把它放到一个服务中:
.factory("Breadcrumbs", function($state, $translate, $interpolate) {
var list = [], title;
function getProperty(object, path) {
function index(obj, i) {
return obj[i];
}
return path.split('.').reduce(index, object);
}
function addBreadcrumb(title, state) {
list.push({
title: title,
state: state
});
}
function generateBreadcrumbs(state) {
if(angular.isDefined(state.parent)) {
generateBreadcrumbs(state.parent);
}
if(angular.isDefined(state.breadcrumb)) {
if(angular.isDefined(state.breadcrumb.title)) {
addBreadcrumb($interpolate(state.breadcrumb.title)(state.locals.globals), state.name);
}
}
}
function appendTitle(translation, index) {
var title = translation;
if(index < list.length - 1) {
title += ' > ';
}
return title;
}
function generateTitle() {
title = '';
angular.forEach(list, function(breadcrumb, index) {
$translate(breadcrumb.title).then(
function(translation) {
title += appendTitle(translation, index);
}, function(translation) {
title += appendTitle(translation, index);
}
);
});
}
return {
generate: function() {
list = [];
generateBreadcrumbs($state.$current);
generateTitle();
},
title: function() {
return title;
},
list: function() {
return list;
}
};
})
Run Code Online (Sandbox Code Playgroud)
实际的breadcrumb指令变得非常简单:
.directive("breadcrumbs", function() {
return {
restrict: 'E',
replace: true,
priority: 100,
templateUrl: 'common/directives/breadcrumbs/breadcrumbs.html'
};
});
Run Code Online (Sandbox Code Playgroud)
和模板:
<h2 translate-cloak>
<ul class="breadcrumbs">
<li ng-repeat="breadcrumb in Breadcrumbs.list()">
<a ng-if="breadcrumb.state && !$last" ui-sref="{{breadcrumb.state}}">{{breadcrumb.title | translate}}</a>
<span class="active" ng-show="$last">{{breadcrumb.title | translate}}</span>
<span ng-hide="$last" class="divider"></span>
</li>
</ul>
</h2>
Run Code Online (Sandbox Code Playgroud)
从这里的屏幕截图中,您可以看到它在导航中都能很好地工作:

以及html <title>标签:

PS到Angular UI团队:请开箱即用!
Mic*_*ley 24
我想与大家分享我的解决方案.它的优点是不需要将任何东西注入控制器,并支持命名的痕迹痕迹标签,以及使用resolve:函数来命名面包屑.
示例状态配置:
$stateProvider
.state('home', {
url: '/',
...
data: {
displayName: 'Home'
}
})
.state('home.usersList', {
url: 'users/',
...
data: {
displayName: 'Users'
}
})
.state('home.userList.detail', {
url: ':id',
...
data: {
displayName: '{{ user.name | uppercase }}'
}
resolve: {
user : function($stateParams, userService) {
return userService.getUser($stateParams.id);
}
}
})
Run Code Online (Sandbox Code Playgroud)
然后,您需要在指令的属性中指定面包屑标签(displayname)的位置:
<ui-breadcrumbs displayname-property="data.displayName"></ui-breadcrumbs>
Run Code Online (Sandbox Code Playgroud)
通过这种方式,指令将知道查看$state.$current.data.displayName要查找要使用的文本的值.
请注意,在最后一个state(home.userList.detail)中,displayName使用通常的Angular插值语法{{ value }}.这允许您引用resolve状态配置中对象中定义的任何值.通常,这将用于从服务器获取数据,如上面的用户名示例所示.请注意,由于这只是一个常规的Angular字符串,因此您可以在displayName字段中包含任何类型的有效Angular表达式 - 如上例中我们对其应用过滤器的情况.
这是关于Plunker的工作演示:http://plnkr.co/edit/bBgdxgB91Z6323HLWCzF?p = preview
我认为将所有代码放在这里有点多,所以这里是GitHub:https://github.com/michaelbromley/angularUtils/tree/master/src/directives/uiBreadcrumbs
| 归档时间: |
|
| 查看次数: |
54618 次 |
| 最近记录: |