2014-01-15 2 views
0

Я не мог придумать отличный способ назвать этот вопрос, но по существу мне интересно, какое лучшее решение для оценки выражений в Ng-Repeat. Например, если у меня есть код, похожий на этот, который отображает мои проекты (при условии, что у меня есть форма с ng-кликом, связанная с функцией для добавления содержимого в массив проектов, с соответствующим массивом этапов для каждого проекта).Угловая функция оценки в Ng-Repeat

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

Теперь вот где моя проблема. Поскольку каждая веха имеет связанную с этим дату DateAccomplicated, я хочу создать еще один список, который хронологически отображает ВСЕ вехи для всех проектов с их ассоциированным проектом и датой. Моя мысль заключалась в том, чтобы пройти все проекты, получить все их вехи и использовать угловой фильтр по датеAccomplished (что, я думаю, будет работать), но где я могу использовать ng-repeat в этом сценарии?

По существу, я знаю, как решить эту проблему на бумаге, но я не знаю, как ее решить Угловой путь. Я не могу понять, как можно обойти мои проекты (используя ng-repeat) без создания дополнительного HTML, с которым я не хочу иметь дело. Я передумал? Должен ли я вызвать функцию в пределах нг-повтора параметров, что делает некоторую работу для меня, например,

<li ng-repeat="milestone in getAllMilestones()"> 

Спасибо за вашу помощь.

Edit: JSON объект для проекта выглядит следующим образом:

project = { 
    name: "some string", 
    milestones: [{ 
     title: "some string", 
     date: Date.now() 
    ]} 
} 

Edit 2: JS-Fiddle: http://jsfiddle.net/HB7LU/1672/

ПРИМЕЧАНИЕ: скрипка работает, как я хочу его, благодаря комментарию ImCg в ; однако ответ Нана, похоже, указывает, что я должен использовать услугу и внедрять эту услугу, поэтому, возможно, я еще не совсем там.

+2

Да, я бы создал новый массив '$ scope.allMilestones' в контроллере и использовал это в простом ngRepeat – imcg

+0

Итак, вы говорите, что знаете, как это сделать, но хотели бы найти альтернативный метод, чтобы избегать «избыточного» HTML? – jessegavin

+0

Да, по сути, я мог бы просто создать метод в контроллере для решения всех моих проблем, но я чувствовал, что это не так, как это сделал бы опытный разработчик Angular. То, что предложили imcg, было больше того, что я искал. – Chris

ответ

1

После повторного чтения вопроса несколько раз я изменил свой ответ. (Надеюсь, я правильно undestood)

Вот логика:

Итак, если вы хотите построить другой массив, который содержит все этапы, цикл по всем проектам и добавить каждую веху в новый массив.

Перед добавлением его и добавлением дополнительной информации к каждому объекту вехи: имя родительского проекта.

Это приведет к созданию массива «Все этапы с названиями проектов». Затем вы можете сделать ng-repeat и отсортировать его по любому желаемому.

Это можно сделать прямо в контроллере, но рекомендуемым способом является логика «получения» вех в службе и демонстрация функции, чтобы контроллер мог ее выполнить.

$scope.allMilestonesWithProjectNames = InjectedService.getAllMilestones(); 

EDIT:

После предоставления 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.Changed нг-повтора на следующее:

<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

EDIT 2:

Майк Пью прибил его, когда дело дошло до структуры, которую вы должны преследовать в своем приложении.

Теперь добавьте следующие строки в свой код и у вас есть полное решение:

Внутри функции 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» для каждой вехи. Его легко просто иметь строку на каждом объекте.

+1

Это отличный ответ - большое вам спасибо. Следует, однако, отметить, что комментарий Майка Пью о привязке контроллера к инъецируемой услуге абсолютно корректен с точки зрения производительности. – Chris

+0

Спасибо. Я только что отредактировал свой ответ. Береги себя. – Nahn

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> 
+0

Это было мое первоначальное мышление, но я считаю, что это будет означать, что эта веха будет достигнута только в рамках их соответствующего проекта, тогда как я пытался получить вехи, заказанные по дате, независимо от того, с каким проектом они были связаны. – Chris

+0

Можете ли вы собрать плункер или jsFiddle? – SoluableNonagon

1

другие решения с обязательным нг-повтора в allMilestones() работают, но вы должны иметь в виду, что выражение в нг-повтора собирается оценивать каждый раз, когда есть $ переваривать цикл, который может произойти в любой момент изменения модели. Если вы оцениваете текущую версию своего 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).

+0

Эй, Майк, спасибо, что нашли время, чтобы объяснить более чистое решение. Как новичок в Angular, такие ответы идут долгий путь. Один последний вопрос: как вы упомянули, в более надежном приложении, я, вероятно, захочу добавить идентификатор к каждой вехе. Вы рекомендуете обрабатывать эти отношения, например, базу данных? Каждый проект будет иметь идентификатор, и каждая веха будет иметь тот же идентификатор, что и связанный с ним проект? – Chris

+0

@ Крис - это действительно зависит от того, что вы собираетесь делать с данными. Собираетесь ли вы сохранять данные в каком-то фоновом хранилище данных или всегда будете жить в локальном хранилище в браузере пользователя (помните, что локальное хранилище может быть уничтожено)? Могут ли пользователи сотрудничать по проектам/вехам? Вам нужно предоставить отчетность и аналитику? –

Смежные вопросы