使用ngModel和使用$ formatters和$ parsers进行数据转换时,数据不会流入指令

时间:2015-09-23 23:53:15

标签: angularjs angularjs-directive angular-ngmodel

我遇到的问题是指令没有从它所基于的父数据进行更新。它可能与使用ngModel输入和数据转换的所述指令有关。

我已经设置了一个模仿我正在处理的应用程序结构的plunker示例:

plnkr example

精确问题:单击“随机数”时,将更新根范围中myData对象的属性。但是,myObjectInput子指令(包含基于myData的转换数据)不会更新。

任何帮助都会受到热烈的赞赏!下面的代码粘贴在下面,如果您更喜欢筛选,而不是查看plunker示例。

的index.html

<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@1.4.5" data-semver="1.4.5" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="main.js"></script>
    <script src="my-object-inputs.js"></script>
  </head>

  <body>
    <h1>Data Binding with Directive Transformation</h1>

    <p>Problem: When "Shuffle Numbers" is clicked, properties in the myData object in the root scope are updated. However, the myObjectInput child directives, which contain transformed data based on myData, do not update.<p>

    <div ng-app="myApp" ng-controller="MainCtrl">
      <div class="left">
        <h2>Directives Data (editable)</h2>
        <div class="group" ng-repeat="group in myData.myGroups">
          <h4>{{ group.myGroupName }} 
            <a class="btn" ng-click="duplicateGroup( group )">+</a>
            <a class="btn" ng-click="removeGroup( group )">-</a>
          </h4>
          <my-object-inputs ng-model="group.myObjs"></my-object-inputs>
        </div>
        <div class="group"><a class="btn" ng-click="shuffle()">Shuffle Numbers</a></div>
      </div>
      <div class="right">
        <h2>Root Data</h2>
        <textarea disabled='disabled'>{{ myData | json }}</textarea>
      </div>
    </div>
  </body>
</html>

main.js

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

myApp.controller('MainCtrl', ['$scope', '$filter',
  function ($scope, $filter) {
    $scope.myData = {
      myGroups : [
        {
          myGroupName: 'First',
          myObjs : [
            {
              order: 0,
              number : 'one'
            },
            {
              order: 0,
              number : 'two'
            },
            {
              order: 1,
              number : 'three'
            },
            {
              order: 1,
              number : 'four'
            }
          ]
        },
        {
          myGroupName: 'Second',
          myObjs : [
            {
              order: 0,
              number : 'five'
            },
            {
              order: 0,
              number : 'six'
            },
            {
              order: 1,
              number : 'seven'
            },
            {
              order: 1,
              number : 'eight'
            }
          ]
        },
        {
          myGroupName: 'Third',
          myObjs : [
            {
              order: 0,
              number : 'nine'
            },
            {
              order: 0,
              number : 'nine'
            },
            {
              order: 1,
              number : 'nine'
            },
            {
              order: 1,
              number : 'nine'
            }
          ]
        }
      ]
    };

    $scope.shuffle = function() {
      // gather all numbers
      var numbersArr = [];
      for ( var i = 0; i < $scope.myData.myGroups.length; i++ ) {
        for ( var j = 0; j < $scope.myData.myGroups[i].myObjs.length; j++ ) {
          numbersArr.push( $scope.myData.myGroups[i].myObjs[j].number );
        }
      }

      // shuffle list of all numbers
      numbersArr = numbersArr.sort(function() { return 0.5 - Math.random() });

      // assign shuffled numbers to original data
      var k = 0;
      for ( var i = 0; i < $scope.myData.myGroups.length; i++ ) {
        for ( var j = 0; j < $scope.myData.myGroups[i].myObjs.length; j++ ) {
          $scope.myData.myGroups[i].myObjs[j].number = numbersArr[k++];
        }
      }
    }

    $scope.duplicateGroup = function( group ) {
      $scope.myData.myGroups.push( angular.copy( group ) );
      $scope.myData.myGroups[$scope.myData.myGroups.length-1].myObjs = angular.copy(group.myObjs);
    };

    $scope.removeGroup = function( group ) {
      if ( $scope.myData.myGroups.length > 1 ) {
        var index = $scope.myData.myGroups.indexOf( group );
        $scope.myData.myGroups.splice(index, 1);
      }
    };
  }
]);

我-对象inputs.html

<ul>
    <li class="my-object-inputs" ng-repeat="arr in transformedObjs">
        <input type="text" ng-repeat="item in arr" ng-model="item.number" />
    </li>
</ul>

我-对象inputs.js

myApp.directive('myObjectInputs', function() {
  var controller = ['$scope', function ($scope) {
    $scope.transformedObjs = [];
    $scope.showTransformedObjs = function() {
      console.log('transformedObjs = ');console.dir($scope.transformedObjs);
    };
  }];

  return {
    restrict: 'E',
    replace: true,
    require: 'ngModel',
    templateUrl: 'my-object-inputs.html',
    controller: controller,
    scope: {
      ngModel: '='
    },
    link: function( $scope, element, attrs, ngModelCtrl ) {

      // transform to new data format
      ngModelCtrl.$formatters.push( function(modelValue) {
        var transformedData = [[],[]];

        for (var i=0; i<modelValue.length; i++) {
          var transformed;
          if (modelValue[i].number == "zero") { transformed = 0 }
          else if (modelValue[i].number == "one") { transformed = 1 }
          else if (modelValue[i].number == "two") { transformed = 2 }
          else if (modelValue[i].number == "three") { transformed = 3 }
          else if (modelValue[i].number == "four") { transformed = 4 }
          else if (modelValue[i].number == "five") { transformed = 5 }
          else if (modelValue[i].number == "six") { transformed = 6 }
          else if (modelValue[i].number == "seven") { transformed = 7 }
          else if (modelValue[i].number == "eight") { transformed = 8 }
          else if (modelValue[i].number == "nine") { transformed = 9 }
          if (transformed) {
            transformedData[ modelValue[i].order ].push({
              order: modelValue[i].order,
              number: transformed
            });
          }
        }

        return transformedData;
      });

      // transform back to original data format
      ngModelCtrl.$parsers.push( function(viewValue) {
        var untransformedData = [];

        for (var i=0; i<viewValue.length; i++) {
          for (var j=0; j<viewValue[i].length; j++) {
            var untransformed;
            if (viewValue[i][j].number == 0) { untransformed = "zero" }
            else if (viewValue[i][j].number == 1) { untransformed = "one" }
            else if (viewValue[i][j].number == 2) { untransformed = "two" }
            else if (viewValue[i][j].number == 3) { untransformed = "three" }
            else if (viewValue[i][j].number == 4) { untransformed = "four" }
            else if (viewValue[i][j].number == 5) { untransformed = "five" }
            else if (viewValue[i][j].number == 6) { untransformed = "six" }
            else if (viewValue[i][j].number == 7) { untransformed = "seven" }
            else if (viewValue[i][j].number == 8) { untransformed = "eight" }
            else if (viewValue[i][j].number == 9) { untransformed = "nine" }
            if (untransformed) {
              untransformedData.push({
                order: viewValue[i][j].order,
                number: untransformed
              })
            }
          }
        }

        return untransformedData;
      });

      // watch for updates to data
      $scope.$watch('transformedObjs', function() {
        ngModelCtrl.$setViewValue( angular.copy( $scope.transformedObjs ) );
      }, true);

      // update view
      ngModelCtrl.$render = function() {
        $scope.transformedObjs = ngModelCtrl.$viewValue;
      };
    }
  }
});

的style.css

h2,h4{margin:0 0 .5em}.right,p{max-width:600px}.left,.right{clear:none;float:left}a{color:#00f;cursor:pointer}h2{font-size:1.2em}h4{font-size:1em}ul{margin:0;padding:0}li{list-style:none}input{width:50px}textarea{border:1px solid #ccc;box-sizing:border-box;height:400px;width:100%}.btn{background:#ddd;padding:0 5px}.group{margin:0 0 1em}.left{padding:0;width:250px}.right{width:calc(100% - 300px)}

1 个答案:

答案 0 :(得分:1)

您不需要控制器。您可以传入范围,观察它并从指令转换它。

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

 myApp.directive('myObjectInputs', function() {
  return {
    restrict: 'E',
    replace: true,
    require: 'ngModel',
    transclude: true,
    templateUrl: 'my-object-inputs.html',
    scope: {
      model: '=ngModel'
    },
    link: function( $scope, element, attrs, ngModelCtrl ) {
      var transform = function(modelValue) {
                var transformedData = [[],[]];

        for (var i=0; i<modelValue.length; i++) {
          var transformed;
          if (modelValue[i].number == "zero") { transformed = 0 }
          else if (modelValue[i].number == "one") { transformed = 1 }
          else if (modelValue[i].number == "two") { transformed = 2 }
          else if (modelValue[i].number == "three") { transformed = 3 }
          else if (modelValue[i].number == "four") { transformed = 4 }
          else if (modelValue[i].number == "five") { transformed = 5 }
          else if (modelValue[i].number == "six") { transformed = 6 }
          else if (modelValue[i].number == "seven") { transformed = 7 }
          else if (modelValue[i].number == "eight") { transformed = 8 }
          else if (modelValue[i].number == "nine") { transformed = 9 }
          if (transformed) {
            transformedData[ modelValue[i].order ].push({
              order: modelValue[i].order,
              number: transformed
            });
          }
        }

        return transformedData;
      }

      var untransform = function (viewValue) {
        var untransformedData = [];

        for (var i=0; i<viewValue.length; i++) {
          for (var j=0; j<viewValue[i].length; j++) {
            var untransformed;
            if (viewValue[i][j].number === 0) { untransformed = "zero" }
            else if (viewValue[i][j].number == 1) { untransformed = "one" }
            else if (viewValue[i][j].number == 2) { untransformed = "two" }
            else if (viewValue[i][j].number == 3) { untransformed = "three" }
            else if (viewValue[i][j].number == 4) { untransformed = "four" }
            else if (viewValue[i][j].number == 5) { untransformed = "five" }
            else if (viewValue[i][j].number == 6) { untransformed = "six" }
            else if (viewValue[i][j].number == 7) { untransformed = "seven" }
            else if (viewValue[i][j].number == 8) { untransformed = "eight" }
            else if (viewValue[i][j].number == 9) { untransformed = "nine" }
            if (untransformed) {
              untransformedData.push({
                order: viewValue[i][j].order,
                number: untransformed
              });
            }
          }
        }

        return untransformedData; 
      }

      // watch for updates on parent to data
      $scope.$watch('model', function() {
        $scope.transformedObjs = angular.copy(transform($scope.model));
      }, true);

      // watch for updates on directive to data
      $scope.$watch('transformedObjs', function() {
        $scope.model = angular.copy(untransform($scope.transformedObjs));
      }, true);
    }
  }
});