从AngularJS视图中调用控制器函数

问题描述:

自从我开始学习AngularJS以来,我已经看到了从视图调用控制器函数的不同方法。从AngularJS视图中调用控制器函数

假设我们在AngularJS待办事项列表应用程序,你可以添加和删除待办事项列表项:

function TodoListCtrl() { 
    var vm = this; 
    vm.addItem = addItem; 
    vm.removeItem = removeItem; 

    activate(); 

    function activate() { 
     vm.list = [];  
    } 

    function addItem() { 
     vm.list.push(vm.newItem); 
     // reset the form 
     vm.newItem = null; 
    } 

    function removeItem(item) { 
     vm.list.splice(vm.list.indexOf(item, 1)); 
    } 
    } 

和HTML:

<h3>Todo List</h3> 

<ul> 
    <li ng-repeat="item in vm.list"> 
    {{ item }} <a ng-click="vm.removeItem(item)">Remove</a> 
    </li> 
</ul> 


<h4>Add Item</h4> 

<input type="text" ng-model="vm.newItem" /> <button ng-click="vm.addItem()">Add</button> 

在这个例子中addItem功能取决于vm.newItem被设置为添加新的列表项目。然而,它也可以重新写为:

function addItem(item) { 
    vm.list.push(item); 
    // reset the form 
    vm.newItem = null; 
} 

随着我们的HTML更新,所以:

<button ng-click="vm.addItem(vm.newItem)">Add</button> 

我可以看到,这使得功能更易于测试,因为我们不依赖于控制器的状态,但我们不完全避免,因为我们在添加项目后重置vm.newItem

当我们应该从我们的视图传递参数,并且我们只能依赖控制器的内部状态时,是否有最佳实践?

+0

我认为这是一个每个案件的情况,在你的情况下应该不重要。在你的情况下,我会在按钮上做一个'ng-disabled =“!vm.newItem”',也许在控制器函数中包含一个'if(item){}'。 – 2015-02-11 15:13:00

+0

我不认为这真的很重要......这与问你是否应该在java/c#类中使用字段值或将其他参数添加到方法中一样。你可以在控制器中使用或不使用vm.newItem - 它仍然存在。 – 2015-02-11 15:18:31

+0

谢谢,我已经更新了示例。 – 2015-02-11 16:10:10

在上述两种情况下,函数addItem都会对控制器的内部状态(使用vm.newItem = null;)产生副作用,因此无法孤立地进行测试。

然而,在第二种情况下,传递不同的变量甚至没有意义,因为它会使语句vm.newItem = null;可能有错误。

为了使功能完全无状态:

vm.addItem(item){ 
    vm.list.push(item); 
} 

你需要重置从形式来看:

<input type="text" ng-model="vm.newItem"> 
<button ng-click="vm.addItem(); vm.newItem = null">Add</button> 

可能是可以接受的,如果重置形式一个仅查看的问题。如果不是,那么这种方法将不会完全工作,因为它可能会使控制器处于错误状态(其中vm.newItem仍然指向列表中新增的项目)

在一天结束时,它取决于您的特别的用例。如果你总是只有一个你可以“添加”的项目,那么传递一个显式参数就是多余的。

但是,如果可以在视图中调用任何新创建的项目,然而addItem,则明确传递参考可能是唯一的方法。

在测试方面,您应该始终测试控制器在操作后处于一致状态。

通过vm.newItem意味着您在视图中有2个位置。虽然可能很清楚,但它也在重复着你自己,让你打开可能会失去同步。而在什么额外的价值?我认为很明显,没有像这样。

<input type="text" ng-model="vm.newItem" /> 
<button ng-click="vm.addItem()">Add</button> 

否则你有这种重复。

<input type="text" ng-model="vm.newItem" /> 
<button ng-click="vm.addItem(vm.newItem)">Add</button> 

你说测试比较容易,但是为什么?您正在测试控制器上的一个功能,所以期望该功能在同一个控制器上使用属性是完全正确的。你可以依赖于控制器,但不是它的成员。