访问与模型变量对应的子范围

时间:2014-10-31 23:24:55

标签: angularjs model-view-controller angularjs-scope angularjs-ng-repeat

我有一个项目列表,我已通过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,相应的模型是我刚添加的新项目(或scope的{​​{1}},其中包含 item)。

问题:

当我向itemController添加一些项目时,我只能访问items,而不能访问最近创建的项目的范围。所以我无法在新项目的范围内运行某些功能(如grabFocus)。 在我的设计中,它在语义上是错误的吗?这个问题的规范方法是什么?

Plunker链接

Here is the plunker link with related comments

2 个答案:

答案 0 :(得分: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;
  };
});

答案 1 :(得分: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="angular.js@1.3.0" 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>