2016-09-03 178 views
0

我奋力定义一个好方法用于以下情形:嵌套控制器和指令

我有一个AngularJs应用程序,消耗了Laravel内置API。

我的任务索引页列出了任务。列表底部是一个新的输入行,可输入任务的两个基本要求,并创建一个新任务(通过调用我的API的服务),并将该项目推入范围。

并发症来了 - 当用户点击一个现有的任务,一个侧栏打开,显示任务的所有细节。所有细节都是可编辑的,包括添加子任务,附件等。他们需要点击保存来调用API更新方法,但是因为任务在列表中更新,因为他们在边栏中进行更改,所以人们认为它已经保存了。我想以任何方式将任务列表的范围与任务侧栏分开 - 但是当保存任务时明显更新列表。

我的TasksController看起来很不整洁。目前,我有一个ng-click函数,它会创建一个'selectedTask'变量(使用所选任务),然后由侧栏视图使用。

我知道会有更好的办法。我试图用任何指令为任务侧栏创建一个新的控制器 - 但我很努力地看到如何来回传递数据。

一些代码,以帮助明白的地方,我来自哪里:

app.js路线

.state('root.tasks', { 
    url: '/tasks', 
    views: { 
     'con[email protected]': { 
      templateUrl: '../partials/tasks-index.html', 
      controller: 'TasksController as TasksCtrl' 
     }, 
     '[email protected]': { 
      templateUrl: '../partials/task-detail-sidebar.html' 
     } 
    } 
}) 

TasksController显示任务功能

vm.showTask = function(task, added) { 
// if same task is clicked in list again, or close button clicked, close task 
if (vm.selectedTask.id == task.id && vm.clickedShut == false && !added) { 
    vm.clickedShut = true; 
} else { 
    // else open task sidebar and create selectedTask 
    vm.clickedShut = false; 
    task.newSubtask = {'title':'', 'assignees':[task.task_owner]}; 
    vm.selectedTask = task; 

    // need to grab current owner/assignees so we know if they change when saving - if so, notifications are sent 
    vm.currentOwner = task.task_owner.id; 
    vm.currentAssignees = []; 
    if (task.assignees) { 
     for (var i = 0; i < task.assignees.length; i++) { 
      vm.currentAssignees.push(task.assignees[i].id); 
     } 
    } 
} 

};

TasksController updateTask

vm.updateTaskFromSidebar = function() { 
    TasksService.update(vm.selectedTask).then(function(data) { 
     if (data.data.task_owner.id !== vm.currentOwner && data.data.task_owner.id !== $rootScope.currentUser.id) { 
      NotificationsService.updateOwner(data.data, $rootScope.currentUser) 
     } 
     var newAssignees = data.data.assignees; 
     var alertAssignees = []; 
     if (newAssignees) { 
      for (var i = 0; i < newAssignees.length; i++) { 
       if (vm.currentAssignees.indexOf(newAssignees[i].id) === -1 && newAssignees[i].id !== data.data.task_owner.id && newAssignees[i].id !== $rootScope.currentUser.id) { 
        alertAssignees.push(newAssignees[i]); 
       } 
      } 
      if (alertAssignees.length) { 
       NotificationsService.updateAssignees(data.data, alertAssignees, $rootScope.currentUser); 
      } 
     } 
     vm.showSimpleToast('Task Saved'); 
    }).catch(function() { 
     vm.showAlertDialog('Error Updating Task', "We've spotted this and will work to resolve the problem as soon as possible."); 
    }); 
}; 

回答

1

您可以使用JSON.parse(JSON.stringify(任务))工具条复制任务对象,并把克隆对象上的侧边栏的范围。这会在侧边栏控制器中发生一次,并且所有输入都应更新克隆的对象。

当用户单击保存时,您将复制回已更改的实际任务密钥。例如,你可以使用扩展。实际保存可以在侧边栏控制器中完成,也可以在rootScope上发出事件并在任务控制器中侦听事件。

+0

我思考事件听众,但是会有大量的任务 - 这不会导致性能问题不断监视事件吗?我可以克隆任务 - 但我如何恢复? – DJC

+0

您可以在任务控制器中观察一次任务更新事件,或者更好地在任务服务中观察任务更新事件。它与您拥有的任务数量无关。您可以发送更新的任务标识和详细信息作为事件的参数。请记住将属性复制回原始任务(而不是替换任务),以便您的绑定将继续工作。你可以用extend来做这种拷贝。 – Nitzo

+0

谢谢,我会给这个去吧 – DJC

1

我要完成@Nitzo的答案,而不是使用事件,你应该为你的任务创建一个服务。

当用户单击某个任务时,应克隆它(您可以使用用户angular.copy()或JSON方法),并将克隆任务和原始任务保存在服务中。

当用户保存任务时,将获取克隆的任务(用户已更改/更新)并将其与原始对象(您可以用户angular.extend())合并。

由于它是一项服务,您可以在所有控制器之间共享,而不会出现任何问题。您可以使用该片段作为指导=)。 (我仍然有很多在我的角度技能提高,如果你发现很难已了解我用结帐这个真棒angular-styleguide格局,如果我错过用过的东西请指正)

angular.module('main', []) 
 
    .factory('taskService', taskService) 
 
    .controller('TaskListController', TaskListController) 
 
    .controller('TaskFormController', TaskFormController); 
 

 
function taskService() { 
 
\t var service = { 
 
\t \t selectedTask: null, 
 
\t \t editingTask: null, 
 
\t \t tasks: [], 
 
\t \t load: load 
 
\t }; 
 

 
\t function load() { 
 
\t \t service.tasks = [{name: "t1", value: 1}, {name: "t2", value: 1}] 
 
\t } 
 

 
\t return service; 
 
} 
 

 
TaskListController.$inject = ['taskService']; 
 
function TaskListController(taskService) { 
 
\t var vm = this; 
 

 
\t vm.taskService = taskService; 
 
\t vm.editTask = editTask; 
 
    taskService.load(); 
 

 
\t function editTask(task) { 
 
\t \t taskService.selectedTask = task; 
 
\t \t taskService.editingTask = angular.copy(task); 
 
\t } 
 

 
} 
 

 
TaskFormController.$inject = ['taskService']; 
 
function TaskFormController(taskService) { 
 
\t var vm = this; 
 

 
\t vm.taskService = taskService; 
 
\t vm.saveTask = saveTask; 
 

 
\t function saveTask() { 
 
     if (taskService.selectedTask) { 
 
\t \t angular.extend(taskService.selectedTask, taskService.editingTask); 
 
\t \t taskService.selectedTask = null; 
 
     } else { 
 
     taskService.tasks.push(taskService.editingTask); 
 
     } 
 
     
 
     taskService.editingTask = null; 
 
\t } 
 

 
}
.task_item { 
 
    cursor: pointer; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 
<div ng-app="main"> 
 

 
\t <ul ng-controller="TaskListController as listCtrl"> 
 
\t \t <li ng-repeat="task in listCtrl.taskService.tasks" 
 
\t \t \t ng-click="listCtrl.editTask(task)" class="task_item"> 
 
\t \t \t {{task.name}} - {{task.value}} 
 
\t \t </li> 
 
\t </ul> 
 
\t 
 
\t <form ng-controller="TaskFormController as formCtrl" ng-submit="formCtrl.saveTask()"> 
 
\t \t <input type="text" placeholder="name" ng-model="formCtrl.taskService.editingTask.name"></input> 
 
\t \t <input type="number" placeholder="value" ng-model="formCtrl.taskService.editingTask.value"></input> 
 
\t \t <input type="submit"></input> 
 
\t </form> 
 

 
</div>

+0

谢谢这似乎是一个很好的解决方案。为了完整性和其他可能遇到此问题的人可以提供一些代码?那么我很高兴地标记为正确的。 – DJC

+0

为什么不呢?刚刚发布了snippet =),告诉我,这是你在找什么/期待 –