Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Complex object with empty values missing the loop in ng-repeat + custom directive #1098

Closed
zzal opened this issue Jun 28, 2012 · 4 comments
Closed

Comments

@zzal
Copy link

zzal commented Jun 28, 2012

Here, I've summarized my problem in that JSfiddle to point out what I think is a bug:

Click once on each button. Then run it again and click in reverse order:

http://jsfiddle.net/zzal/nRgmC/3/

You'll see that the ng-repeat doesn't render as expected, in the second element.

Explanation:
I'm dynamically building a form depending on a config file passed through structured objects. There is 2 kinds of info there to help display the fields:

  1. what kind of form element should be rendered, and
  2. what's the value to be shown.

The problem is, when a value is empty, angularJS doesn't seems to pass in the ng-repeat loop and use a previously rendered HTML element to display.

I found that the scope.$watch(attr.myText, ...) is not even triggered if sub element in object watched is an empty string.

@petebacondarwin
Copy link
Member

If you are watching a complex object you need to put a true parameter at the end of your watch.

scope.$watch(attr.myText, function(value) { ... }, true)

@zzal
Copy link
Author

zzal commented Dec 6, 2012

Does it solve my issue?
No.

http://jsfiddle.net/nRgmC/10/

@petebacondarwin
Copy link
Member

@zzal: OK Alain. So you still have a problem but I don't think it is a bug in Angular. I will take a look later and see what I can do to help.
Pete

@petebacondarwin
Copy link
Member

@zzal : Sorry but your code was so convoluted I couldn't see what your problem was.

DOM operations are very slow. ng-repeat is optimized so that if an element has not changed then it is left alone. In you example, you are passing in an array. The second item is always '' and so ng-repeat assumes that nothing has changed so it doesn't destroy and reinstate the element. Therefore the second div in the list never changes. You can see this if you put some console.logs in the linking function.

Your problem is that you are thinking that ng-repeat is some kind of imperative for loop that runs through each item every time the list changes. This would be inherently slow. (I suspect that you are thinking in terms of server side rendering where on each request the whole page has to be rebuilt.)

ng-repeat is actually not a loop function. It is a mapping of the array items to DOM elements. So as you would expect, in a mapping, if the item doesn't change neither should the element.

As an aside, because you are thinking that on each change to the list the whole structure is recreated you are actually doing something fundamentally wrong, by "appending" to the directive element. If the DOM element were updated rather than ignored when the primitive value appeared then you would find that your append is going to keep adding child after child to your element.

So really you are going about things the wrong way. What you should be doing is thinking about how to map the data that you have to the elements that you want to see. The easiest thing to solve your immediate problem is to iterate over objects rather than strings, since then the ng-repeat will see that the objects change and update the elements accordingly.

See this... http://jsfiddle.net/Vka3K/

I hope that solves your problem. Yes?

Next time, this is probably a question for Stack Overflow or the mailing list. If you can get agreement that it is a bug then you can raise an issue. There are enough issues for us to go through as it is.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants