I apologize in advance if i'm not wording this properly. I have a textbox with ng-model
inside an ng-repeat
and when I try to get the textbox value it's always undefined
. I just want it to display whatever I type in the corresponding textbox.
It seems to be an issue with the $scope
, so how would I make the $scope.postText
global or at the controller root level so it can be accessible?
Here's the JSFiddle to help clear things up: http://jsfiddle.net/stevenng/9mx9B/14/
As @Gloopy already stated, ng-repeat creates a new child scope for each item in your posts
array. Since each item of the posts
array is a primitive (a string), ng-repeat also creates a post
property on each child scope, and assigns each of them the appropriate value from the array. Inside the ng-repeat block is ng-model="postText"
. This creates a postText property on each of the child scopes. Here is what that all looks like (for 2 of the 4 child scopes):
When a user types some text into one of the input textboxes, the appropriate gray box will store the text. (E.g., the 2nd (from the top) gray box will store text a user types into the "tech" textbox.) The parent scope cannot see the postText properties in the child scope -- this is the problem you had. There are three common solutions:
posts
array. E.g.,$scope.posts = [ {type: 'tech'}, {type: 'news'}, ...];
<input type="text" ng-model="post.postText">
posts
, rather than a copy (of a value). Therefore, post.postText
gets created on parent $scope property posts
, and hence it is visible to the parent scope. (So, in this case the child scopes would simply call savePost()
-- there would be no need to pass any values up to the parent scope.)posts
array in the parent would be automatically updated as follows:$scope.posts = [ {type: 'tech', postText: 'this is tech related'}, {type: 'news'}, ...];
ng-model="$parent.someProperty"
to bind the form element to a property on the parent scope, rather than on the child scope. This solution would be difficult to implement for your scenario, and it is a rather fragile solution, as it depends on the HTML structure for scope inheritance... but I mention it for completeness.(A fourth solution was presented by @Renan in comments on @Gloopy's answer. This is a like solution 1., but with a variation: this
is used instead of passing a value up to the parent. I'm not a fan of this approach as it makes it difficult to determine which $scope is being accessed or modified. I think it is better that functions defined on $scope only access and modify their own $scope.)
For more information (and lots more pictures) about how prototypal scope inheritance works in Angular, see What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
In your click expression you can reference the postText
and access it in your savePost
function. If this wasn't in an ng-repeat you could access the single $scope.postText
successfully but ng-repeat creates a new scope for each item.
Here is an updated fiddle.
<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);
}
This may be a late answer. Please refer this fiddle. http://jsfiddle.net/X5gd2/ Please refer to the firebug's console, when u click on the links after typing some texts in the text box. The idea is to have a itemcontroller for each of the view that is repeated inside the ng-repeat.
The item controller:
function postItemController($scope){
$scope.savePost = function(){
console.log($scope.postText + " which belongs to " + $scope.post +" will be saved")
}
}
Split the model up into heading and value
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 below..
<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>