Ng-Repeat中的角度评估函数

时间:2014-01-15 14:50:03

标签: javascript angularjs angularjs-ng-repeat

我想不出一个很好的方法来标题这个问题,但基本上我想知道在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的答案似乎表明我应该使用服务并注入该服务,所以也许我还没有完全存在。

3 个答案:

答案 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>