我想不出一个很好的方法来标题这个问题,但基本上我想知道在Ng-Repeat中评估表达式的最佳解决方案是什么。例如,如果我有一些看起来像这样的代码列出我的项目(假设我有一个表单,其中ng-click与一个函数关联,将内容添加到一个项目数组中,每个项目都有一个相关的里程碑数组)。
<h2>List of Projects!</h2>
<ul>
<li ng-repeat="project in projects">
<p>{{project.name}}</p>
<li ng-repeat="milestone in project.milestones">
<p>{{milestone.name}}</p>
<p>{{milestone.dateAccomplished}}</p>
</li>
</li>
<ul>
现在我的问题出在这里。由于每个里程碑都有一个与之关联的dateAccoished,我想创建另一个列表,按时间顺序打印所有项目的所有里程碑,以及它们的相关项目和日期。我的想法是遍历所有项目,获取所有里程碑,并使用dateAccomplished(我认为可行)的角度过滤器,但在这种情况下我可以在哪里利用ng-repeat
?
基本上,我知道如何在纸上解决这个问题,但我不知道如何以Angular方式解决它。我无法找到一种方法来循环我的项目(使用ng-repeat
)而不创建我不想处理的额外HTML。我是在过度思考吗?我应该在ng-repeat参数中调用一个对我有用的函数,例如
<li ng-repeat="milestone in getAllMilestones()">
感谢您的帮助。
编辑:项目的JSON对象如下所示:
project = {
name: "some string",
milestones: [{
title: "some string",
date: Date.now()
]}
}
编辑2:JS-Fiddle:http://jsfiddle.net/HB7LU/1672/
注意:由于imcg的评论,小提琴正在按照我想要的方式工作;然而,Nahn的答案似乎表明我应该使用服务并注入该服务,所以也许我还没有完全存在。
答案 0 :(得分:2)
使用绑定ng-repeat到allMilestones()的其他解决方案确实有效,但是你必须记住,每当有$ digest周期时,ng-repeat中的表达式将被评估,这可能随时发生模型的变化。如果您评估JSFiddle的当前版本,您会注意到您在“项目名称”输入字段中键入的每个字母都会多次调用allMilestones()函数。这本身并没有那么糟糕,但是这个函数有嵌套循环 - 如果你开始拥有大量的项目/里程碑,最终可能会导致性能问题。
即使所有这些都是可以接受的,更简洁的解决方案是将您的逻辑封装到服务中,让服务部门为您维护所有里程碑的列表。这使您的服务和控制器非常可测试和可维护。
请参阅http://jsfiddle.net/HB7LU/1676/
小提琴代码是
myApp.service('ProjSvc', function () {
var projects = [];
var milestones = [];
return {
createProject: function (projectName) {
var proj = {
name: projectName,
milestones: [{
title: "started project",
dateCreated: Date.now()
}]
};
projects.push(proj);
milestones.push(proj.milestones[0]);
},
projects: projects,
allMilestones: milestones
};
});
function MyCtrl($scope, ProjSvc) {
$scope.currentProjects = ProjSvc.projects;
$scope.allMilestones = ProjSvc.allMilestones;
$scope.createProject = function () {
ProjSvc.createProject($scope.newProjectName);
$scope.newProjectName = "";
};
}
您需要针对ProjSvc和MyCtrl设置单元测试,以捕获除了所有项目之外维护所有里程碑列表的要求。
在更强大的版本中,您可能希望在里程碑中添加一些字段,以便跟踪关系(即milestone.projId)。
答案 1 :(得分:1)
几次重读这个问题后,我修改了答案。 (希望我能正确地做坏事)
这是逻辑:
所以,如果你想构建包含所有里程碑的另一个数组, 循环遍历所有项目并将每个里程碑添加到新阵列。
在添加之前,向每个里程碑对象添加额外信息:父项目名称。
这将导致“具有项目名称的所有里程碑”数组。然后,您可以对其执行 ng-repeat ,并根据您的需要对其进行排序。
这可以在控制器中直接完成,但推荐的方法是在服务中“获取”里程碑的逻辑并公开函数,以便控制器可以执行它。
$scope.allMilestonesWithProjectNames = InjectedService.getAllMilestones();
修改强>
提供JFiddle后,这是一个有效的粗略解决方案:
<强> 1。使用以下内容更改$scope.allMilestones
:
$scope.allMilestones = function(){
var milestoneList = [];
$scope.currentProjects.forEach(function(project) {
project.milestones.forEach(function(milestone) {
milestone.parentproject= project;
console.log(milestone);
milestoneList.push(milestone);
});
});
return milestoneList;
};
我在“milestone.parentproject = project
”
milestoneList.push(milestone)
”
2.将ng-repeat更改为以下内容:
<li ng-repeat="milestone in allMilestones() | orderBy: '-dateCreated'">
<p>Milestone: {{milestone.title}}</p>
<p>Date Accomplished: {{milestone.dateCreated}}</p>
<p>{{milestone.parentproject.name}}</p>
</li>
在这里,我添加了要显示的新字段:milestone.parentproject,name
编辑2:
Mike Pugh在你应用程序中应该采用的结构上钉了它。
现在,将以下内容添加到他的代码中,您就拥有了一个完整的解决方案:
在createProject函数中:
projects.push(proj);
proj.milestones[0].projectName = proj.name
milestones.push(proj.milestones[0]);
请注意,为了避免循环引用(如果您愿意),只需将父对象的名称而不是实际对象添加到每个里程碑对象。
每次添加包含里程碑的项目或一次一个里程碑时,都会执行“对象改造”操作,这不会是性能问题。你不会再遍历所有项目了。
当然,您仍需要将| orderBy: '-dateCreated'
和<p>Project Name {{milestone.projectName}}</p>
添加到ng-repeat
。
关于在里程碑中添加project id
的评论:这可能是也可能不是一个好主意。取决于你想要的。这是一个性能开销。当您显示每个里程碑的项目名称时,您必须为每个里程碑执行“getProjectById”查询。很容易在每个对象上都有字符串。
答案 2 :(得分:0)
这种方式的东西?
<ul>
<li ng-repeat="project in projects | orderBy: 'dateAccomplished'">
<li ng-repeat="milestone in project.milestones">
<p>{{milestone.name}} - {{project.name}}</p>
<p>{{milestone.dateAccomplished}}</p>
</li>
</li>
<ul>