Динамически назначать ng-модель


82

Я пытаюсь создать набор флажков из массива объектов. Я стремлюсь, чтобы флажки динамически отображали свою ng-модель на свойство нового объекта, который будет отправлен в массив.

Я имел в виду что-то вроде

<li ng-repeat="item in items">
    <label>{{item.name}}</label>
    <input type="checkbox" ng-model="newObject.{{item.name}}">
</li>

Это не работает, как видно на этом JSFiddle:

http://jsfiddle.net/GreenGeorge/NKjXB/2/

Кто-нибудь может помочь?

Ответы:


146

Это должно дать вам желаемый результат:

<input type="checkbox" ng-model="newObject[item.name]">

Вот рабочий план: http://plnkr.co/edit/ALHQtkjiUDzZVtTfLIOR?p=preview


1
хм, на самом деле это буквально дало мне '<input ng-model = "newObject [item.name]">', мне чего-то не хватает?
Джордж Ананда Эман

Хм, странно, только что добавил живой пример (плункер, поскольку jsFiddle по какой-то причине сегодня у меня не работает).
pkozlowski.opensource 06

ах да, я привык думать на php и ожидал, что фактическая разметка изменится на имя, это сработало. Спасибо!
Джордж Ананда Эман

2
Великолепно, именно то, что я искал. Я люблю Angular!
SharkofMirkwood

1
Он также отлично работает в Angular 2. Но есть ли решение для многомерных объектов? В вашем примере if item.nameдолжно иногда указывать на, newObject['x']а иногда на newObject['x']['y'].
Мартин Шнайдер

23

РЕДАКТИРОВАТЬ Как правильно отмечено в комментариях, использование этого с ng-change требует наличия «фиктивной» ng-модели заранее. Однако следует отметить, что, очевидно, в версии 1.3 необходимые параметры были предусмотрены фреймворком. Пожалуйста, проверьте https://stackoverflow.com/a/28365515/3497830 ниже! /РЕДАКТИРОВАТЬ

На всякий случай, если вы, как и я, спотыкаетесь в простом случае, имея более сложную задачу, это решение, которое я придумал для динамической привязки произвольных выражений к ng-модели: http://plnkr.co/edit/ccdJTm0zBnqjntEQfAfx?p = предварительный просмотр

Метод: я создал директиву dynamicModel, которая принимает стандартное угловое выражение, оценивает его и связывает результат с областью действия через ng-model и $ compile.

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

app.controller('MainCtrl', function($scope) {
  $scope.data = {};
  $scope.testvalue = 'data.foo';
  $scope.eval = $scope.$eval;
});

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

app.controller('MainCtrl', function($scope) {
  $scope.data = {};
  $scope.testvalue = 'data.foo';
  $scope.eval = $scope.$eval;
});

app.directive('dynamicModel', ['$compile', function ($compile) {
    return {
        'link': function(scope, element, attrs) {
            scope.$watch(attrs.dynamicModel, function(dynamicModel) {
                if (attrs.ngModel == dynamicModel || !dynamicModel) return;

                element.attr('ng-model', dynamicModel);
                if (dynamicModel == '') {
                    element.removeAttr('ng-model');
                }

                // Unbind all previous event handlers, this is 
                // necessary to remove previously linked models.
                element.unbind();
                $compile(element)(scope);
            });
        }
    };
}]);

Используется просто dynamic-model = "angularExpression", где angularExpression приводит к строке, которая используется в качестве выражения для ng-модели.

Я надеюсь, что это избавит кого-то от головной боли от необходимости придумывать это решение.

С уважением, Юстус


3
Ты спасатель. Я почти отчаялся, прежде чем нашел этот пост.
Nelo Mitranim

Вы можете быть более конкретным, Брайан? Что вы пробовали и что вышло?
Justus Wingert

Это настоящая жемчужина решения. Вы вытащили меня из очень щекотливой проблемы - спасибо!
Mikebert4

1
ng-change с этим не работает. Если вы посмотрите в исходный код angular, директива ngChange имеет ngModel в качестве обязательной директивы. Быстрый поиск показывает, что эта проблема есть только у ngChange и ngList. Похоже, что все остальные директивы имеют ngModel в качестве необязательного контроллера. Я решил эту проблему, добавив ng-model = "dummyValue" к любому элементу, используя директиву dynamic-model. Поскольку изменение динамической модели вызывает $ compile, ngChange и любые другие директивы, использующие значение ng-model, обновляются правильно.
EverPresent

1
Это более надежное решение, когда вам не нужно наблюдать за изменением значения динамической модели - stackoverflow.com/a/32096328/887092
Тодд,

6

В Angular 1.3 вы можете использовать ng-model-optionsдирективу для динамического присвоения модели или привязки к выражению.

Вот такой plunkr: http://plnkr.co/edit/65EBiySUc1iWCWG6Ov98?p=preview

<input type="text" ng-model="name"><br>
<input type="text" ng-model="user.name" 
ng-model-options="{ getterSetter: true }">

Подробнее ngModelOptionsздесь: https://docs.angularjs.org/api/ng/directive/ngModelOptions


Простите меня, если я что-то упускаю, но, похоже, ничего в вашей планке не включает динамическое назначение модели. И ничто в ngModelOptions, очевидно, не поддерживает этого. Не могли бы вы уточнить? Потому что было бы очень полезно, если бы это действительно так работало ...
XML

@XMLilley "getterSetter: логическое значение, которое определяет, следует ли рассматривать функции, связанные с ngModel, как геттеры / сеттеры."
Крис Болтон

Спасибо, Роб, что обратил на это мое внимание, я обновил свой ответ и добавил ссылку на ваш.
Justus Wingert

1

Это мой подход для поддержки более глубокого выражения, например, 'model.level1.level2.value'

<input class="form-control" ng-model="Utility.safePath(model, item.modelPath).value">

где item.modelPath = 'level1.level2' и Utility (model, 'level1.level2') - служебная функция, которая возвращает model.level1.level2.


Не могли бы вы подробнее рассказать, как это работает? Что возвращает Utility.safePath, чтобы затем можно было использовать .value?
Девон Холкомб

Utility.safePath возвращает значение вложенной переменной, заданной строкой пути. например, level1.level2 относится к model.level1.level2.
Канит Мекриттхикрай

0

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>

    <div ng-app="myApp" ng-controller="myCtrl">
        <form name="priceForm" ng-submit="submitPriceForm()">
            <div ng-repeat="x in [].constructor(9) track by $index">
                <label>
                    Person {{$index+1}} <span class="warning-text">*</span>
                </label>
                <input type="number" class="form-control" name="person{{$index+1}}" ng-model="price['person'+($index+1)]" />

            </div>
            <button>Save</button>
        </form>
    </div>

    <script>
        var app = angular.module('myApp', []);
        app.controller('myCtrl', function ($scope) {
            $scope.price = [];
            $scope.submitPriceForm = function () {
                //objects be like $scope.price=[{person1:value},{person2:value}....]
                console.log($scope.price);
            }
        });
    </script>
</body>
</html>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.