Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arrays of strings not being handled properly within ng-repeat #1267

Closed
donovanh opened this issue Aug 15, 2012 · 22 comments

Comments

Projects
None yet
@donovanh
Copy link

commented Aug 15, 2012

When displaying a series of values from an array, the data items are not being bound to the model properly, as in:

$scope.model = {
  values: [
    "Value 1",
    "Value 2,
    ...
  ]
}

If the above is displayed in a series of input fields, changes to the content are not reflected in the model. However, binding the above using code like the following does maintain binding to the model:

<div ng-repeat="value in model.values">
  <input type="text" ng-model="model.values[$index]" />
</div>

However the issue with this approach is that the text field loses focus on each keyup. A demo is here:
http://jsfiddle.net/donovanh/GSx76/

@mhevery

This comment has been minimized.

Copy link
Member

commented Aug 15, 2012

I am assuming you had this:

<div ng-repeat="value in model.values">
  <input type="text" ng-model="value" />
</div>

this will not work since you are binding to a scope. Basically you have to have a . in ng-model or the revers data binding does not work on primitives.

so this is basically expected because you are binding to a scope.value property not to the original value in the repeater.

The flicker is also expected with your workaround since data binding changes the array, which then makes it look like to the repeater as if Value 1 left and new Value 2X appeared, so the repeater removes the old DOM node and replaces it with a new DOM node hence the loss of focus.

I know this is counter intuitive, but that is how the system is architected. Don't bind to primitives is my answer.

@mhevery mhevery closed this Aug 15, 2012

@donovanh

This comment has been minimized.

Copy link
Author

commented Aug 15, 2012

Thank you for the follow up. I'll adjust my data structure to take this into account.

@nicholasrq

This comment has been minimized.

Copy link

commented Nov 15, 2012

My example doesn't work too: http://jsfiddle.net/nicholas_r/7KrQ5/

I followed the solution given here but it didn't give any effect and the problem is still here.

@petebacondarwin

This comment has been minimized.

Copy link
Member

commented Nov 15, 2012

The solution given here says, "you have to have a . in ng-model." You did not do this. Yours is ng-model="field".
You need to restructure your data so that you have an array of objects not strings.
Here is a fixed fiddle: http://jsfiddle.net/7KrQ5/1/

@nicholasrq

This comment has been minimized.

Copy link

commented Nov 15, 2012

Oh, my fault. Thanks.

@NickHeiner

This comment has been minimized.

Copy link
Contributor

commented Dec 11, 2012

I would like to submit having this work as a feature request (although I recognize that's unlikely, given the response to this issue so far haha). Is this comment sufficient to do so, or should I open a new issue?

@petebacondarwin

This comment has been minimized.

Copy link
Member

commented Dec 12, 2012

Have you tried this version of the ng-repeat directive?
#1661
It fixes a number of issues the repeater had with primitive values.
@NickHeiner : I am not exactly sure what specific feature you are requesting?

@NickHeiner

This comment has been minimized.

Copy link
Contributor

commented Dec 12, 2012

I'm requesting a feature where you can bind directly to a string within an ng-repeat.

@petebacondarwin

This comment has been minimized.

Copy link
Member

commented Dec 12, 2012

You can do that now. I suspect what you mean is that you want the scope outside the ng-repeat to update when the string is updated?

@NickHeiner

This comment has been minimized.

Copy link
Contributor

commented Dec 12, 2012

Yes, I would like to be able to use ng-model within an ng-repeat on a list of strings and be able to have two way binding work as expected.

I understand why it doesn't work now, and realize that making it work could be more trouble than it's worth, but I think it's worth looking in to because it would make angular easier to work with.

@petebacondarwin

This comment has been minimized.

Copy link
Member

commented Dec 12, 2012

The only way to make it work without changing the way that Javascript works
is to use someArray[$index] within your repeat loop. E.g.

This allows you to reference the element directly so that changes are
reflected in the array.

But this doesn't work correctly with the current ng-repeat implementation
because the divs that contain the input keep getting destroyed or moved
around on each change. The fix I referenced before does allow this.

On 12 December 2012 15:35, Nick Heiner notifications@github.com wrote:

Yes, I would like to be able to use ng-model within an ng-repeat on a
list of strings and be able to have two way binding work as expected.

I understand why it doesn't work now, and realize that making it work
could be more trouble than it's worth, but I think it's worth looking in to
because it would make angular easier to work with.


Reply to this email directly or view it on GitHubhttps://github.com//issues/1267#issuecomment-11293595.

@NickHeiner

This comment has been minimized.

Copy link
Contributor

commented Dec 14, 2012

Yep, that works. Thanks!

@joshuawoodward

This comment has been minimized.

Copy link

commented Dec 9, 2013

This works in angular 1.1.4- (repeating an array of strings)

http://jsfiddle.net/ez86K/

@webnesto

This comment has been minimized.

Copy link

commented Apr 12, 2014

Here's a way to effectively bind the members of a string array to a UI component. I used textarea boxes, but it could be done the same with an input or whatever:

http://jsfiddle.net/VvnWY/4/

@babaphemy

This comment has been minimized.

Copy link

commented Jan 13, 2015

Hi, Please I need to bind a text field to each row in a ng-repeat. I want the text field to have different value for each row. My ng-model is instead binding one value to all the textfield in my ng-repeat. Please how do you advise I proceed.

@phillipCouto

This comment has been minimized.

Copy link

commented Jan 28, 2015

Ok I figured out a way to get it to work using the latest version of angular. If the size of the array won't change then you can use one time binding like so:

<li ng-repeat="str in ::arrayOfStrings">
<input ng-model="arrayOfStrings[$index]" />
<br/>
</li>

This will prevent the repeat from changing the dom and changes to the primitives will be watched correctly.

@toboid

This comment has been minimized.

Copy link

commented Jan 29, 2015

I was able to work around this and use avoid the issue with lost focus by using track by (tested against ver 1.3)

<div ng-repeat="value in model.values track by $index">
  <input type="text" ng-model="model.values[$index]">
</div>              
@joselee

This comment has been minimized.

Copy link

commented Jun 2, 2015

toboid: thanks for sharing that workaround! I was in a situation where restructuring my array data to an array of objects would have been very cumbersome (in recursive directive views). Track by $index helped.

I'm wondering why 'track by' fixes this issue though? What is the underlying reason?

@ufologist

This comment has been minimized.

Copy link

commented Jun 16, 2015

thanks @toboid sloved my problem, it works.

if you do not want wrap a object in array

<div ng-repeat="value in model.values track by $index">
  <input type="text" ng-model="model.values[$index]">
</div>
@gissivaraman

This comment has been minimized.

Copy link

commented Jul 3, 2015

<div class="col-md-6">
<i class="fa fa-exclamation-circle"></i>&nbsp;
    <label class="control-label">{{data.rulename}}</label>
</div>
                                            
<div class="col-md-2 balradio">
<label>
<input type="radio" name="{{data.rulelabel}}" ng-model="data.rulemodel" value="No action" />
 <img />
</label>
</div>
                                            
<div class="col-md-2 balradio">
<label>
<input type="radio" name="{{data.rulelabel}}" ng-model="data.rulemodel" value="Add" />
<img />
</label>
</div>
                                            
<div class="col-md-2 balradio">
<label>
<input type="radio" name="{{data.rulelabel}}" ng-model="data.rulemodel" value="Subtract" />
 <img />
</label>
</div>

I have created form with radio buttons dynamically with sample as above in which i could not get the form data values while submit action.please guide how to resolve

@gissivaraman

This comment has been minimized.

Copy link

commented Jul 3, 2015

In the above sample ng-model not working with ng-repeat . while form submit it gives only undefined value in console....

@bobber205

This comment has been minimized.

Copy link

commented Jan 26, 2016

@gissivaraman open a new ticket and please follow the basic guidelines for submitting an issue. Don't tack your issues onto another.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.