Динамически назначать 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.