【问题标题】:Proper method to handle Angular scope instead of $parent.$parent处理 Angular 范围而不是 $parent.$parent 的正确方法
【发布时间】:2016-05-03 14:35:30
【问题描述】:

我已经阅读了几篇文章,但没有找到解决我问题的示例。

我的理解是:

  1. ng-if 和 ng-repeat 创建隔离范围。
  2. 使用$parent.someProperty 不好。
  3. 使用$parent.$parent.someProperty 将是可憎的。

那么,使用给定的模板标记,我怎样才能正确绑定控制器以便控制器属性更新?

标记:
(注意嵌套的ng-if 和ng-repeat,创造了一种$parent.$parent 的情况)

<div ng-app="MyApp" ng-controller="MyCtrl">
  <div ng-if="showOnCondition">
    <label ng-repeat="item in repeatingItems">
      {{item}}
      <setting item="item" />
    </label>
  </div>
  {{checkSetting()}}
</div>

JavaScript

var myApp = angular.module('MyApp', []);

myApp.controller('MyCtrl', function($scope) {
  $scope.settings = {
    someProperty: '',
    anotherProperty: 'Hello'
  }

  $scope.repeatingItems = [
    'One',
    'Two',
    'Three'
  ];

  $scope.showOnCondition = true;

  $scope.checkSetting = function() {
    // When calling checkSettings(), I would like to access the value of someProperty here
    return $scope.settings;
  }
});

myApp.directive('setting', function() {
  return {
    restrict: 'E',
    require: '^myCtrl',
    // HOW DO I SOLVE THIS?
    // $parent.$parent is bad.
    template: '<input type="radio" ng-model="$parent.$parent.settings.someProperty" name="mySetting" value="{{item}}" />',
    scope: {
      settings: '=',
      item: '='
    }
  };
});

鉴于上面的例子,我如何正确地构造指令和/或标记以访问控制器中的settings.someProperty?还是我需要做一些完全不同的事情?

澄清
我正在尝试做的事情似乎有些混乱。 someProperty 在指令中可用 - 工作正常。请注意,我正在尝试将值分配给控制器的 someProperty 属性,从 in 指令(使用 ng-model)

更新
我已将上面的代码修改为已知的工作代码,并添加了jsFiddle。 请注意,它有效,但它在模板中使用$parent.$parent。这是我需要了解如何解决的问题。

【问题讨论】:

  • 看看这个example这是你想做的吗?
  • 不,这是一个不包含嵌套隔离范围的简单示例。
  • 首先,作用域不是孤立的,所以你可以在这里使用作用域继承。那么 controllerAs 方法在这种情况下总是有效的。
  • @dfsq - 子作用域/指令不与控制器“交谈”。至于“controllerAs”方法,谢谢,但我不知道这意味着什么!感谢您的帮助,但您说的是相当笼统的内容,我正在寻找一些具体的内容来帮助我解决这个问题。

标签: javascript angularjs


【解决方案1】:

您可以将设置传递给指令,我认为这是最简单/最直接/最干净的方式。

Angular 正确地将 settings 评估为 MyCtrl.settings,然后将其传递给 setting 指令的隔离范围。在指令内部,您对 settings 进行了双向绑定,因此您可以从那里更新设置。

修改您的示例,将settings 传递到标记中的指令中:

&lt;setting settings="settings" item="item" /&gt;

然后在 JavaScript 中,将其替换为模板:

template: '&lt;input type="radio" ng-model="settings.someProperty" ng-value="item" name="mySetting" /&gt;',

这是working fiddle。

【讨论】:

  • 好点,@cale_b,添加了相关代码位,感谢您的提示。
【解决方案2】:

编辑

我正在根据您的小提琴和更简单的双向数据绑定方法完全重写我的答案。请注意未来的读者,前几个 cmets 不再与此更新的答案相关。

HTML

<div ng-app="MyApp" ng-controller="MyCtrl">
  <div ng-if="showOnCondition">
    <label ng-repeat="item in repeatingItems">
      {{item}}
      <setting test="settings.someProperty" item="item" />
    </label>
  </div>
  {{checkSetting()}}
</div>

JS

var myApp = angular.module('MyApp', []);

myApp.controller('MyCtrl', function($scope) {
  $scope.settings = {
    someProperty: true,
    anotherProperty: 'Hello'
  }

  $scope.repeatingItems = [
    'One',
    'Two',
    'Three'
  ];

  $scope.showOnCondition = true;

  $scope.checkSetting = function() {
    // When calling checkSettings(), I would like to access the value of someProperty here
    return $scope.settings;
  }
});

myApp.directive('setting', function() {
  return {
    restrict: 'E',
        replace: true,
    template: '<input type="radio" ng-model="test" name="mySetting" value="{{item}}" />',
    scope: {
      test: '=',
      item: '='
    }
  };
});

这提供了父控制器属性和指令之间的双向数据绑定。使用这种方法,您可以将每个单独的父范围属性传递给一个属性,并将其绑定到您的隔离范围中。

【讨论】:

  • @cale_b - 您是否像在小提琴中使用的那样专门限于 Angular 1.1.5?
  • 不,这是一个疏忽。我实际上使用的是 Angular 1.4.7
  • @cale_b - 现在看看这个。
【解决方案3】:

当层次关系和数据传递变得复杂时,一个选择是解耦父/子关系,只使用一个服务来共享数据。

我已经看到了一些很好的解释,例如passing state via services,sample code。您还可以将此想法用于通用缓存服务,例如 Angular 的 $cacheFactory 或更复杂的库:angular-cache。

【讨论】:

  • 我听说过这个概念,但是将模板上的输入值导入父控制器似乎需要很多开销。我一直在想一定有更简单的方法吗?
  • 你说得对——我终于把头绕过去了,并提供了一个更简单的答案stackoverflow.com/a/35025628/3232832,但可能会将其保留为解耦服务的数据点。
【解决方案4】:

你为什么不添加一个参数'someproperty'来传递给设置指令=像这样:

myApp.directive('setting', function() {
   return {
   restrict: 'E',
   template: '<input type="radio" ng-model="myProperty" 
   value="{{item}}" />',
   scope: {
      settings: '=',
      item: '=',
      myProperty: '='
   }
  };
});

在你的标记中:

<label ng-repeat="item in repeatingItems">
  {{item}}
  <setting item="item" myProperty="settings.someProperty" />
</label>

【讨论】:

  • myProperty 参数是 2 路数据绑定,对吧?所以新的参数“myProperty=setting.someProperty”绑定到控制器$scope.settings。如果子指令对其进行更改,控制器将看到这些更改。并且还在模板输入元素中,将参数传递给 ng-model。
猜你喜欢
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-09
  • 2017-02-01
相关资源
最近更新 更多