为什么我需要在ngRepeat中指定$ parent,但不要在与ngRepeat相同的元素上指定$ parent

时间:2016-05-06 05:04:43

标签: angularjs angularjs-scope

<div class="btn-group" role="group" aria-label="...">
  <label ng-repeat="year in years" ng-class="{'btn-primary': year === selectedYear}" class="btn btn-default">
    <input type="radio" ng-model="$parent.selectedYear" name="year" ng-value="year" />
    {{year}}
  </label>
</div>

在这段代码中,我理解我需要使用$parent绑定到$scope.selectedYear,因为ngRepeat创建了自己的范围,而selectedYear是属于父范围的原语。 / p>

我不明白ng-class="{'btn-primary': year === selectedYear}的工作原理。

ngRepeat范围内的ngClass是什么?如果是这样,为什么selectedYear不需要$parent,如果不是,它如何使用ngRepeat范围内的year

&#13;
&#13;
angular.module("app", [])
  .controller("controller", function($scope) {
    $scope.currentYear = new Date().getFullYear();
    $scope.selectedYear = $scope.currentYear;
    $scope.years = [$scope.currentYear - 1, $scope.currentYear, $scope.currentYear + 1];
  });
&#13;
body > div {
  padding: 15px;
}

.btn-group > label > input[type="radio"] {
  display: none;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />

<div ng-app="app" ng-controller="controller">

  <div class="btn-group" role="group" aria-label="...">
    <label ng-repeat="year in years" class="btn btn-default" ng-class="{'btn-primary': year === selectedYear}">
      <input type="radio" ng-model="$parent.selectedYear" name="year" ng-value="year" />
      {{year}}
    </label>
  </div>
  
  <br/>
  <br/>
  
  Selected year: {{selectedYear}}

</div>
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:2)

您也可以在没有$ parent引用的情况下执行此操作。问题在于范围继承。创建子作用域时,所有变量(对象和基本变量)都在子作用域中,其名称与父作用域中的名称相同。但是当您更改子范围内的原始变量时,它们仅在子范围内更改 互联网上有很多关于范围继承的信息。例如,有一个很好的解释:https://github.com/angular/angular.js/wiki/Understanding-Scopes
你可以做些什么来避免这种情况 - 总是把你想要绑定的原始变量放在对象中(比如我下面的代码片段)

关于您的问题 -

  

ngRepeat范围内的ngClass是

我认为,ngClass创建了自己的范围。此范围继承父范围的变量(ngRepeat的范围和控制器的范围)。因此,原始变量selectedYear在ng-repeat的范围和ng-class范围内是不一样的。不正确,请参阅注释

&#13;
&#13;
angular.module("app", [])
  .controller("controller", function($scope) {
     $scope.settings = {currentYear: new Date().getFullYear()};
     $scope.settings.selectedYear = $scope.settings.currentYear;
     $scope.settings.years = [$scope.settings.currentYear - 1, $scope.settings.currentYear, $scope.settings.currentYear + 1];
  });
&#13;
body > div {
  padding: 15px;
}

.btn-group > label > input[type="radio"] {
  display: none;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />

<div ng-app="app" ng-controller="controller">

  <div class="btn-group" role="group" aria-label="...">
    <label ng-repeat="year in settings.years" class="btn btn-default" ng-class="{'btn-primary': year === settings.selectedYear}">
    <input type="radio" ng-model="settings.selectedYear" name="year" ng-value="year" />
    {{year}}
</label>
  </div>
  
  <br/>
  <br/>
  
  Selected year: {{settings.selectedYear}}

</div>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

回答第一个问题

Is the ngClass inside the ngRepeat's scope?

由于ng-repeat和ng-class存在于同一元素上,因此执行顺序由每个指令的priority决定。 ng-repeat的优先级为1000,ng-class的优先级为0,这意味着理想的执行顺序应为

1) Compile of ng-repeat
2) compile of ng-class 
3) link of ng-repeat 
4) link of ng-class  

根据我的理解,因为ng-class首先被链接(附加范围),所以你不必使用$parent.selectedYear

我可能错了,但这是我的理解。希望它可能会有所帮助。

修改

阅读ng-class和ng-repeat代码后。需要添加一些更正/更改

首先,ng-class和ng-repeat都不会创建孤立的范围。

其次,我提到的执行顺序并不准确。订单应该是

1) compile of ng-repeat
2) link of ng-repeat
3) link of ng-class (ng-class doesn't have compile)

这是因为ng-repeat在其链接函数中使用$ watchCollection,它使用setTimeout更新范围异步。

现在在ng-repeat的链接阶段,它循环遍历数组并使用transclude函数将范围附加到模板(在这种情况下,这是整个div与ng-repeat。) 这意味着,所有重复的元素都将具有遵循原型层次结构的新范围。这意味着您可以在子范围内(ng-repeat的范围)访问附加到范围的属性(在本例中,是控制器中作用域的属性)。

由于ng-class再次没有隔离范围且内部没有创建新范围,因此ng-class中的范围应与ng-repeat中使用的范围相同。

非常感谢任何建议/修改,因为我不是专业人士。

如果你能安装一个工作的掠夺者,那就太棒了。

回答如何在ng-class中使用年份?。如果year表示用户在文本框中输入的值,则可以按照您使用它的方式使用它,它应该可以正常工作。

答案 2 :(得分:1)

由于范围原型继承,您可以从父范围读取没有$ parent的值。

对于ng-model,您必须使用$parent直接引用父作用域,因为ng-model使用双向绑定 - 否则新值将设置为子作用域而不是父作用域,因为selectedYear是原始的。