AngularJS ng-model $scope в ng-repeat - undefined
Я заранее извиняюсь, если не буду правильно формулировать это. У меня есть текстовое поле с ng-model
внутри ng-repeat
, и когда я пытаюсь получить значение текстового поля, оно всегда undefined
. Я просто хочу, чтобы он отображал все, что я набираю в соответствующем текстовом поле.
Кажется, проблема с $scope
, так как я могу сделать $scope.postText
глобальный или на уровне корневого контроллера, чтобы он мог быть доступен?
Здесь JSFiddle поможет разобраться: http://jsfiddle.net/stevenng/9mx9B/14/
Ответы
Ответ 1
В выражении click вы можете ссылаться на postText
и получить доступ к нему в вашей функции savePost
. Если это не было в ng-repeat, вы можете получить доступ к одиночному $scope.postText
, но ng-repeat создает новую область для каждого элемента.
Здесь - обновленная скрипка.
<div ng-repeat="post in posts">
<strong>{{post}}</strong>
<input type="text" ng-model="postText">
<a href="#" ng-click="savePost(postText)">save post</a>
</div>
$scope.savePost = function(post){
alert('post stuff in textbox: ' + post);
}
Ответ 2
Как уже говорилось в @Gloopy, ng-repeat создает новую дочернюю область для каждого элемента в вашем массиве posts
. Поскольку каждый элемент массива posts
является примитивным (строка), ng-repeat также создает свойство post
для каждой дочерней области и назначает каждому из них соответствующее значение из массива. Внутри блока ng-repeat находится ng-model="postText"
. Это создает свойство postText для каждого из дочерних областей. Вот что это все выглядит (для 2 из 4 дочерних областей):
![ng-repeat scopes]()
Когда пользователь вводит какой-либо текст в одно из текстовых полей ввода, соответствующий серый квадрат сохранит текст. (Например, второй (сверху) серый ящик будет хранить текст, который пользователь вводит в текстовое поле "tech".) Поля родительского объекта не могут видеть свойства postText в области дочерних объектов - это проблема, которая у вас была. Существует три общих решения:
- @Gloopy answer: определите функцию в родительской области (к которой могут иметь доступ дочерние области, поскольку дочерние области ng-repeat прототипически наследуются от родительской области) и передать значение свойства дочерней области (т.е. значение postText) до родительский.
- Используйте объекты вместо примитивов в массиве
posts
. НАПРИМЕР,
$scope.posts = [ {type: 'tech'}, {type: 'news'}, ...];
Затем в вашем цикле ng-repeat используйте
<input type="text" ng-model="post.postText">
Поскольку каждый элемент массива является объектом (а не примитивным), каждая дочерняя область получает ссылку на соответствующий объект в массиве posts
, а не на копию (значения). Поэтому post.postText
создается в родительском объекте $scope posts
, и, следовательно, он отображается в родительской области. (Итак, в этом случае дочерние области просто вызывают savePost()
- не нужно было бы передавать какие-либо значения до родительской области.)
Другими словами, если пользователь набрал "это связано с технологией" в первом текстовом поле, массив posts
в родительском объекте будет автоматически обновляться следующим образом:
$scope.posts = [ {type: 'tech', postText: 'this is tech related'}, {type: 'news'}, ...];
Последнее примечание: свойство postText не добавляется к объекту posts, пока пользователь не наберет что-то.
- Используйте
ng-model="$parent.someProperty"
, чтобы привязать элемент формы к свойству в родительской области, а не к области дочернего элемента. Это решение будет сложно реализовать для вашего сценария, и это довольно хрупкое решение, так как оно зависит от структуры HTML для наследования области... но я упоминаю его для полноты.
(Четвертое решение было представлено @Renan в комментариях к ответу @Gloopy. Это похоже на решение 1., но с вариацией: this
используется вместо передачи значения до родителя. не является поклонником этого подхода, так как это затрудняет определение того, к какой переменной области доступа обращаются или изменяются. Я думаю, что лучше, чтобы функции, определенные в области $scope, только открывали и изменяли свою собственную область $.)
Для получения дополнительной информации (и большего количества изображений) о том, как наследование прототипического объема работает в Angular, см. Каковы нюансы объема прототипа/прототипного наследования в AngularJS?
Ответ 3
Это может быть поздний ответ. Пожалуйста, обратитесь к этой скрипке. http://jsfiddle.net/X5gd2/
Пожалуйста, обратитесь к консоли firebug, когда вы нажимаете на ссылки после ввода некоторых текстов в текстовое поле. Идея состоит в том, чтобы элемент itemcontroller для каждого из представлений повторялся внутри ng-repeat.
Контроллер элемента:
function postItemController($scope){
$scope.savePost = function(){
console.log($scope.postText + " which belongs to " + $scope.post +" will be saved")
}
}
Ответ 4
Разделите модель на заголовок и значение
angular.module('MyApp',[]);
function PostCtrl($scope) {
$scope.posts = [{heading:'tech',value:''}, {heading:'news',value:''}, {heading:'sports',value:''},{heading:'health',value:''}];
$scope.savePost = function(post){
alert( 'post stuff in textbox: ' + post);
}
}
HTML ниже..
<div ng-app="MyApp">
<div ng-controller="PostCtrl">
<div ng-repeat="post in posts">
<strong>{{post.heading}}</strong>
<input type="text" ng-model="post.value">
<a href="#" ng-click="savePost(post.value)">save post</a>
</div>
</div>
</div>
Проверьте этот скрипт..