在angularjs中有没有办法动态设置ngModel?

时间:2015-11-10 12:28:35

标签: javascript angularjs

我有一个组件(具有隔离范围的指令),它将对象列表映射到允许修改该对象的一个​​属性的输入列表。

但我想让这个组件具有普遍性。 因此它应该接受应该绑定到输入的列表中每个对象的深层嵌套属性的路径。

例如,我们有一个人员列表,每个人都有不同语言的名称:

var people = [
  {
    age: 31,
    multilang_attributes: {
      en: {name: 'John'},
      ru: {name: 'Иван'}
    }
  },
  {
    age: 29,
    multilang_attributes: {
      en: {name: 'Peter'},
      ru: {name: 'Пётр'}
    }
  },
];

我想将我的通用组件应用于以下人员列表:

<input-list
  items="people",
  item-model="multilang_attributes[locale].name"
></input-list>

我尝试使用&创建范围属性,这将允许我在父范围内执行表达式,然后将该表达式传递给ngModel,但这不起作用。您可以查看此次尝试in plunkr

如何以角度接近该任务?

1 个答案:

答案 0 :(得分:2)

一个选项是$parse访问者字符串,并使用getter/setter作为模型。为此:

  1. 将directive-html更改为:

    item-accessor="'multilang_attributes.' + app.locale + '.name'"

    这将使multilang_attributes.en.name可用。

    1. 将指令代码更改为:

      app.directive('inputList', function () {
        return {
          restrict: 'E',
          scope: {
            items: '=',
            itemAccessor: '='
          },
          template: '<ul><li ng-repeat="item in items"><input ng-model="getModel(item)" ng-model-options="{ getterSetter: true }" /></li></ul>',
      
          controller: function ($scope, $parse) {
            $scope.getModel = function(item) {
              return function (newValue) {
                var getter = $parse($scope.itemAccessor);
      
                if (arguments.length > 0) {
                  getter.assign(item, newValue);
                }
      
                return getter(item);
              };
            };
          }
        };
      });
      
    2. 外部演示http://plnkr.co/edit/VzFrBxNcsA5BarIVr6oG?p=preview

      &#13;
      &#13;
      var app = angular.module('TestApp', [])
      
      app.controller('AppCtrl', function AppController() {
          
        this.locales = ['en', 'fr']
        this.locale = 'en';
        
        this.people = [
          {
            age: 31,
            multilang_attributes: {
              en: {name: 'John (en)'},
              fr: {name: 'John (fr)'}
            }
          },
          {
            age: 29,
            multilang_attributes: {
              en: {name: 'Fred (en)'},
              fr: {name: 'Fred (fr)'}
            }
          },
        ];
        
      });
        
      app.directive('inputList', function () {
        return {
          restrict: 'E',
          scope: {
            items: '=',
            itemAccessor: '='
          },
          template: '<ul><li ng-repeat="item in items"><input ng-model="getModel(item)" ng-model-options="{ getterSetter: true }" /></li></ul>',
          
          controller: function ($scope, $parse) {
            
            $scope.getModel = function(item) {
              return function (newValue) {
                var getter = $parse($scope.itemAccessor);
                
                if (arguments.length > 0) {
                  getter.assign(item, newValue);
                }
                
                return getter(item);
              };
            };
          }
        };
      });
      &#13;
      <!DOCTYPE html>
      <html>
        <head>
          <script data-require="angular.js@1.4.7" data-semver="1.4.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
          <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
        </head>
      
        <body ng-app="TestApp" ng-controller="AppCtrl as app">
          <div class="container">
            <select ng-model="app.locale" ng-options="v as v for v in app.locales"></select>
            <hr>
            
            <input-list
              items="app.people"
              item-accessor="'multilang_attributes.' + app.locale + '.name'"
            ></input-list>
            
            <hr>
            <pre>{{ app.people|json }}</pre>
          </div>
        </body>
      </html>
      &#13;
      &#13;
      &#13;

      注意 您应该使用正确的注入语法和controllerAs / bindToController。