0

我有一个项目列表,我已经通过ng-repeat将它们呈现在模板中。它们中的每一个都受itemController的控制,其暴露项目的一些行为(例如,抓取焦点)。下面是HTML:访问对应于模型变量的子范围

<body ng-controller="mainController"> 
    <button ng-click="addItem()">add</button> 
    <ul> 
    <li ng-repeat="item in items" ng-controller="itemController"> 
     <div ng-if="item.isEditing"> 
     <input ng-model="item.name"/> 
     <button ng-click="item.isEditing=false">done</button> 
     </div> 
     <span ng-if="!item.isEditing">{{item.name}}</span> 
    </li> 
    </ul> 
    </body> 

mainController,我有加入新的项目,以项目一个功能。下面是mainController的代码:

app.controller('mainController', function($scope){ 
    $scope.items = [ 
    { 
     name: "alireza" 
    }, 
    { 
     name: "ali" 
    } 
    ]; 
    $scope.addItem = function(){ 
    $scope.items.push({isEditing: true}); 
    } 
}); 

每当我将项目添加到items阵列,对应li元素被添加到视图通过itemController一个实例控制,以及相应的模型是我刚刚添加的新项目(或者可能是itemControllerscope,其中包含项目)。

问题:

当我加入一些项目items,我只能访问item和最近创建的项目不是范围。所以我不能在新项目的范围上运行一些函数(如grabFocus)。 在我的设计中,它在语义上是错的吗?这个问题的典型方法是什么?

Plunker链接

Here is the plunker link with related comments

回答

0

我通过建立每输入一个唯一的ID,根据其指数改变你的方法一点点。看到下面的代码,希望它有帮助。

// Code goes here 
 

 

 
var app = angular.module("app",[]); 
 
app.controller('mainController', function($scope,$timeout){ 
 
    $scope.items = [ 
 
    { 
 
     name: "alireza" 
 
    }, 
 
    { 
 
     name: "ali" 
 
    } 
 
    ]; 
 
    $scope.addItem = function(){ 
 
    $scope.items.push({isEditing: true}); 
 
    $timeout(function(){ 
 
     document.getElementById("newItem"+($scope.items.length-1)).focus(); 
 
    },0) 
 
    } 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<!DOCTYPE html> 
 
<html ng-app="app"> 
 

 
    <head> 
 
    <script data-require="[email protected]" data-semver="1.3.0" src="//code.angularjs.org/1.3.0/angular.js"></script> 
 
    <link href="style.css" rel="stylesheet" /> 
 
    <script src="script.js"></script> 
 
    </head> 
 

 
    <body ng-controller="mainController"> 
 
    <button ng-click="addItem()">add</button> 
 
    <ul> 
 
    <li ng-repeat="item in items"> 
 
     <div ng-if="item.isEditing"> 
 
     <input ng-model="item.name" id="newItem{{$index}}"/> 
 
     <button ng-click="item.isEditing=false">done</button> 
 
     </div> 
 
     <span ng-if="!item.isEditing">{{item.name}}</span> 
 
    </li> 
 
    </ul> 
 
    </body> 
 

 
</html>

+0

谢谢你,但我认为这是一种解决方法,而不是针对这些情况一个干净的解决方案。假设有一个更复杂的工作,而不是抓住焦点。我认为这是'项目'的问题,不应该在外部控制器中处理。 – 2014-11-01 01:58:44

1

您可以使用$broadcast从父范围,与$on从子范围一起,通知新添加的项目的子作用域。通过传递(作为参数)与新增项目相对应的子作用域的$id,每个捕捉事件的孩子都可以知道它是否需要调用grabFocus()

下面是使用该方法的fork of your Plunker。我不知道你试图用你原来Plunker $element.find(":text").focus();来完成,所以我调整了它切换一个$scope属性,进而控制视图中的风格。新添加的项目将是红色的(通过调用自身的grabFocus功能的标志切换到true),和其他人会变黑(通过调用自己的loseFocus功能的标志切换到false)。

修改HTML(只是重复li):

<li ng-repeat="item in items" ng-controller="itemController"> 
    <div ng-if="item.isEditing"> 
    <input ng-model="item.name"/> 
    <button ng-click="item.isEditing=false;handleItemAdded($index);">done</button> 
    </div> 
    <span ng-if="!item.isEditing" ng-style="{ color: isFocused ? 'red' : 'black' }">{{item.name}}</span> 
</li> 

完整的JavaScript:

var app = angular.module("app",[]); 
app.controller('mainController', function($rootScope, $scope){ 
    $scope.items = [ { name: "alireza" }, { name: "ali" } ]; 
    $scope.addItem = function(){ 
    $scope.items.push({isEditing: true}); 
    }; 
    $scope.handleItemAdded = function (index) { 
    // $rootScope.$broadcast('item-added', { index: index }); 
    for(var cs = $scope.$$childHead; cs; cs = cs.$$nextSibling) { 
     if (cs.$index === index) { 
     $rootScope.$broadcast('item-added', { id: cs.$id }); 
     break; 
     } 
    } 
    }; 
}); 
app.controller('itemController', function($scope, $element){ 
    $scope.$on('item-added', function (event, args) { 
    if ($scope.$id === args.id + 1) { 
     $scope.grabFocus(); 
    } else { 
     $scope.loseFocus(); 
    } 
    }); 
    $scope.grabFocus = function() { 
    $scope.isFocused = true; 
    }; 
    $scope.loseFocus = function() { 
    $scope.isFocused = false; 
    }; 
}); 
+0

...或者,如果您想要避免可能会被弃用的$$前缀属性,请使用更清晰的方法来更新Plunker,以避免这些问题:http://plnkr.co/edit/DjJBADTuAJ5GBSxXEqYg?p =预览 – 2014-11-01 01:19:28

+0

谢谢。其实,我已经做了这样的事情,但我想知道这是不是最好的做法。我认为向所有人广播似乎并不合理。我想知道是否我想要做的事情是错误的,并针对MVC,这**广播**解决方案只是一个解决方法,做这个坏事!如果是这样,那么达到我想要的标准解决方案是什么? – 2014-11-01 02:19:18