【问题标题】:AngularJS : $watch not triggered on change ($scope issue with include page)AngularJS:$watch 未在更改时触发(包含页面的 $scope 问题)
【发布时间】:2013-04-22 23:35:22
【问题描述】:

HTML:

Filter: 
<input type="radio" ng-model="Type" value="Rear"> Rear
<input type="radio" ng-model="Type" value="Front"> Front
<br>
Select:
<name-value-select entry="entry" field="axleType" options="filterTypes"></name-value-select>

指令:

  .directive('nameValueSelect', function () {
    return {
    restrict: "E",
    scope: {
        entry: "=",
        field: "@",
        options: "=",
        onInputChange: "&"
    },
    controller: function ($scope) {

        $scope.onChange = function () {
            console.log("selected changed");
            $scope.entry.type = $scope.option.value;
            $scope.onInputChange();
        };

        var getItemForValue = function (value) {
            var item = null;
            $scope.options.forEach(function (_option) {
                if (_option.value == value) {
                    item = _option;
                }
            });
            return item;
        };

        $scope.$watch("entry", function () {
            console.log("entry changed");
            $scope.option = getItemForValue($scope.entry[$scope.field]);
        }, true);

    },
    template: '<select ng-model="option" ng-options="o.Description for o in options" ng-change="onChange()"><option value="" selected="selected">Please Select </option></select>'

};  })

控制器:

$scope.Description = '';
$scope.entry = {Description: ''};
$scope.Type = 'Front';
$scope.entry.type = '';


$scope.$watch('Type', function (Type) {
    $scope.filterTypes = [];
    $scope.axleTypes = new API.GetAxleTypes(function () {
        angular.forEach($scope.axleTypes, function(axleType) {
            if (axleType.Type == Type) {
                this.push(axleType);
            }
            // if(!$scope.$$phase) $scope.$digest(); // tried this, does not have any affect
    }, $scope.filterTypes); // '}, $scope.filterTypes, true)'--> did nothing for me here     
}); 
    $scope.filterTypes.sort(function (a, b) {
        return a.Description.localeCompare(b.Description);
    });
}); // '}, true)' --> did nothing for me here

问题:

自定义选择控件最初会填充类型为“Front”的项目,如果我将 Rear 设为默认值,也会填充“Rear”。

但是,在单选按钮之间切换时,不会调用监视功能,并且选择不会填充符合新选择的过滤器类型的项目。

/////////////////////////////////////// /////// 缩小问题范围: ///////////////////////////////////////// ///

将其移至独立项目时,我发现上面的代码有效:-(

这里是原始的 select NOT 作为自定义指令:

    <select ng-model="$parent.selectedFrontAxle" ng-options="axleType.Description for axleType in axleTypes | filterByType: 'Front' | orderBy:'Description'"  id="frontAxles" class="formRequire" required>            
        <option value="" selected>Select Axle Type ..</option>  
    </select>

这是作为自定义指令的选择控件:

  <name-value-select   entry="entry" field="axleType" options="filterTypes"></name-value-select>

显然这是问题所在:"ng-model="$parent.selectedFrontAxle"

如果我使用指令“name-value-select”并将其移动到父页面,而不是包含语句,它就可以工作。

但这不是我想要的。所以我需要把它留在包含页面中。

然而,如果我使用 ng-model="$parent.selectedFrontAxle" 并将其添加到包含页面上的任何元素,则没有任何效果。

任何没有 ng-model="$parent.selectedFrontAxle",仍然没有任何效果。

我可以看到问题是范围,但我不知道如何纠正它。

啊!!!还是没有解决办法。

//
//
///////////////////////////////////////// //////////// 马克·拉科克 ///////////////////////////////////////// ////////////

一如既往地感谢您的帮助。虽然,当我说我有希望代码预过滤而不是用户的场景时,我认为我没有明确说明第 2 点。不过我想通了。因此,对于希望通过指令抽象出控件的任何人,并且在这种情况下,过滤过程由用户和代码执行,这里是 plunker 解决方案:

http://plnkr.co/edit/tnXgPKADfr5Okvj8oV2S?p=preview

【问题讨论】:

  • 如果你为问题设置 plunker 或 fiddle 演示会更好
  • 标记见上面给你的评论。
  • 您不希望同一个控制器两次/嵌套。你能设置一个Plunker(使用ng-include)吗?或者至少显示你在哪里使用 ng-include?目前尚不清楚包含 ng 的 HTML。我也不明白$scope.Type$scope.entry.type 是干什么用的。如果您的指令应该监视单选按钮的变化,那么单选按钮需要使用entry.type。此外,on-input-change 未在您的 HTML 中指定,因此您的 `&' 绑定在指令中不起作用。 (顺便说一句,我没有收到您上述评论的通知……您需要使用@Mark。)
  • @MarkRajcok,见上面的 sNJ 老兄的 cmets
  • @MarkRajcok 你在吗?

标签: javascript angularjs


【解决方案1】:

this plunker 中,我重新编写了代码以允许用户选择“后”或“前”,并且选择列表将动态更新。所选值在 MainCtrl 范围内以 $scope.selected.item 的形式提供。 (我删除的指令中有很多不必要的代码。使用 ng-model 时不需要 onChange 处理程序。)

<name-value-select selected-item="selected.item" options="filterTypes">
</name-value-select>

app.directive('nameValueSelect', function () {
    return {
        restrict: "E",
        scope: {
            selectedItem: "=",
            options: '='
        },
        template: ...

由于 ng-include 创建了一个子作用域,所有原始属性都被转换为对象属性,因此 JavaScript 原型继承将按预期工作(即,当值更改时,MainCtrl 中定义的 $scope 对象会更改而不是新建在本地范围内创建的原始属性)。

我相信上面提到的 plunker 会满足您的“第 1 点”。

我现在将考虑为“第 2 点”创建一个 plunker...(我会在更新此答案时添加评论)。


This plunker 过滤指令中的选择列表:

<name-value-select selected-item="selected.item" choice="choice.type"
 options="myTypes"></name-value-select>

app.directive('nameValueSelect', function () {
    return {
        restrict: "E",
        scope: {
            selectedItem: "=",
            choice:  "=",
            options: "=",
        },
        controller: function($scope)  {
          $scope.$watch('choice', function (selectedType) {
            $scope.selectedItem = '';  // clear selection
            $scope.filterTypes = [];
            angular.forEach($scope.options, function (type) {
              if (type.Type === selectedType) {
                this.push(type);
               }
            }, $scope.filterTypes);
            $scope.filterTypes.sort(function (a, b) {
              return a.Description.localeCompare(b.Description);
            });
          });
        },
        template: '<select ng-model="selectedItem" ' +
         'ng-options="o.Description for o in filterTypes">' +
         '<option value="" selected="selected">Please Select</option>' +
         '</select>'
    };
});

【讨论】:

    【解决方案2】:

    我不完全理解您的要求,但我只是假设您想根据单选按钮组的值动态更改选择的内容。选择被过滤和排序,您可以选择要显示数据的哪个字段。

    您可以看看这个Plunker,其中包含一个经过少量修改的演示。

    HTML

    Filter: 
    <input type="radio" ng-model="filter.type" value="rear"> Rear
    <input type="radio" ng-model="filter.type" value="front"> Front
    <br />
    Field:
    <select ng-model="filter.field" ng-options="item for item in fields"></select>
    <br />
    Select:
    <select ng-model="entry" ng-options="item[filter.field] for item in entries | filter:type=filter.type | orderBy:filter.field">
      <option value="">Default</option>
    </select>
    <br />
    Selected: <span>{{entry}}</span>
    
    <h2>Alternative</h2>
    Filter: <span>{{filter}}</span>
    <br />
    <select ng-model="altentry" ng-options="item[filter.field] for item in altentries | orderBy:filter.field">
      <option value="">Default</option>
    </select>
    <br />
    Selected: <span>{{altentry}}</span>
    

    JS

    var app = angular.module('plunker', []);
    
    app.controller('MainCtrl', function($scope) {
      $scope.name = 'World';
    
      /* Default filter values */
      $scope.filter = {
        type: 'rear',
        field: 'name'
      };
    
      /* List of fields */
      $scope.fields = [
        "id", "type", "name"
      ];
    
      /* Data coming from an API */
      $scope.entries = [
        {"id":1, "type":"rear", "name":"Rear Part 01"},
        {"id":2, "type":"rear", "name":"Rear Part 03"},
        {"id":3, "type":"rear", "name":"Rear Part 05"},
        {"id":4, "type":"rear", "name":"Rear Part 02"},
        {"id":5, "type":"rear", "name":"Rear Part 04"},
        {"id":6, "type":"front", "name":"Front Part 01"},
        {"id":7, "type":"front", "name":"Front Part 03"},
        {"id":8, "type":"front", "name":"Front Part 05"},
        {"id":9, "type":"front", "name":"Front Part 02"},
        {"id":10, "type":"front", "name":"Front Part 04"},
      ];
    
      /* Simulate different ajax return */
      $scope.$watch('filter.type', function(newval, oldval) {
        if (newval || newval !== oldval) {
          $scope.altentries = [];
          angular.forEach($scope.entries, function(v,k) {
            if (v.type === $scope.filter.type) {
              $scope.altentries.push(v);
            }
          });
        }
      });
    
      /* Monitoring any selected value */
      $scope.$watch('entry', function(newval, oldval) {
        console.log('entry:', oldval, newval);
      }, true);
    
      $scope.$watch('altentry', function(newval, oldval) {
        console.log('altentry:', oldval, newval);
      }, true);
    
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-10
      • 1970-01-01
      • 2015-10-16
      相关资源
      最近更新 更多