AngularJS: ng-model setter inside ng-repeat
Asked Answered
C

2

5

I've found some great answers on how to get the value of an ng-model inside an ng-repeat, but so far, I haven't found any that cover the setter. Suppose I have something like this:

<div ng-repeat="item in getItems()">
    <input ng-model="itemTitle" ng-model-options={getterSetter:true}">
</div>

If I had a single input box, I'd use something like this:

...
var _val = '';
$scope.itemTitle = function(val){
    return angular.isDefined(val) ? (_val = val) : _val;
}
...

However, that would change the value for every single input box. Is it possible to define the variables and a setter, potentially using arrays? Or is there a better method to get and set input boxes inside an ng-repeat?

Complicacy answered 18/1, 2015 at 0:30 Comment(0)
A
6

The answer by Wayne Ellery does answer the question as it shows "a better method to get and set input boxes inside an ng-repeat".

However if you actually want to use ng-model-options="{getterSetter: true}" within an ng-repeat as is implied in the question and the comments then it's a little more complicated as within your getterSetter function you don't know which item from the ng-repeat is being referred to.

Essentially what you need to do is pass a different getter/setter function for each item, and you can do that by passing a function to ng-model that creates your row specific getter/setter for you.

<div ng-app="app" ng-controller="ctrl">
  <div ng-repeat='row in items'>
    <span>{{row.name}}</span>
    <input type='text' ng-model='createTitleGetterSetter(row.name)' 
      ng-model-options='{ getterSetter: true }' />
  </div>
  <hr/>
  <pre>{{ itemTitles | json }}</pre>
</div>

And the JS code:

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

app.controller('ctrl', function($scope) {
    $scope.items = [
        {'name': 'a'},
        {'name': 'b'},
        {'name': 'c'}
    ];

    $scope.itemTitles = {};
    $scope.createTitleGetterSetter = function(name) {
        if (!$scope.itemTitles[name]) {
            $scope.itemTitles[name] = {
                getterSetter: function(newValue) {
                        return arguments.length === 0 ? 
                        $scope.itemTitles[name].title :
                        $scope.itemTitles[name].title = newValue;
                },
                title: ''
            }
        }

        return $scope.itemTitles[name].getterSetter;
    };
});

JSFiddle here: http://jsfiddle.net/zLg3mLd0/1/

In this case the item titles are of course not stored along with the item objects (if you wanted to do that, just a simple ng-model would suffice) but in the itemTitles map.

Credit to this answer and its comments on which this answer is heavily based.

Anaerobe answered 11/3, 2016 at 15:39 Comment(0)
B
2

You would set ng-model to item.title so each object in the array returned from getItems() would contain a title.

<div ng-repeat="item in getItems()">
    <input type="text" ng-model="item.title"/>
</div>
Bookcraft answered 18/1, 2015 at 0:33 Comment(12)
How would I create the setter? As it is, all you've done is renamed the variable. The getting isn't the issue; it's the setting.Complicacy
You didn't mention that in your question so I just left it as is. What are you trying to accomplish with ng-model-options={getterSetter:true}Bookcraft
I have a dynamic list of items, each with an input box. I'd like to both get the data from each individual box and set it.Complicacy
Without seeing what's in getItems it's difficult to answer, but as long as each item has title set to the title then each textbox will be populated with the title. If the value is changed in the textbox then the item title will be setBookcraft
It doesn't really matter what the array returns. It's just an array with uncertain length that also generates an array of input boxes as ng-repeat iterates. I'm not seeing the code here. Could you elaborate? Sorry. Using the generic getter/setter I use for single values, as I pointed out, just changes all the values.Complicacy
It does because for my above code to work each item in the array would need to be an object with a title propertyBookcraft
Let us continue this discussion in chat.Bookcraft
Because it doesn't answer the question. You reference item.title as if his model has a title for each item, but he's asking (clarified by his code), how to use a getter/setter called itemTitle on each item in the ng-repeat and no title exists. I'm in the same situation. Typically the getter/setter is passed the value, but then how do we properly reference the object it should be assigned to (or retrieved from) since it's not an absolute reference on $scope, but an object from an array?Kimberykimble
@Kimberykimble if the title doesn't exist on the item then it will be created. The OP said if the title was shared at the root level then it would change for each item so title must be on each item in order for it not to change. If you refer to the chat log he said he was happy with the solutionBookcraft
I did refer to the chat log and there isn't a solution there either. The op in fact said, "Hm. That did it, but I'm not too happy with the result." The issue remains.Kimberykimble
@Kimberykimble Can you please post a new question clearly explaining your problem and I'll do my best to answer it. It's still not exactly clear what the OP was exactly wanting. The solution does do what the OP said: "is there a better method to get and set input boxes inside an ng-repeat"Bookcraft
@rainabba, my answer should hopefully resolve this once and for all :)Anaerobe

© 2022 - 2024 — McMap. All rights reserved.