ng-repeat fails on a p>div structure, but works for a div>div structure? - angularjs

I'm maintaining a legacy product, and found a quirk that I haven't seen before in AngularJS.
As demonstrated in this Plunker, the following HTML fails to render:
<p ng-repeat="item in items">
<div>{{item.type}}</div>
</p>
while this renders just fine:
<div ng-repeat="item in items">
<div>{{item.type}}</div>
</div>
Is there any explanation as to why this might be the case?
I was rather caught off-guard with this, as I don't recall seeing anything about this in the development resources.

It most likely is due to the fact that the HTML spec specifies that for a <p> immediately followed by a <div>, the close tag is optional.
I would assume this means that somehow the browser silently ignores the presence of any explicit source-specified </p> tag. I'd guess that when ng-repeat is parsing the source, it then cannot find the end of the repeated section, and therefore cannot render as expected.

Related

Angular with Microdata

Does Microdata work with dynamic Angular ng-repeat items?
Can I use it as:
<div itemscope itemtype="http://schema.org/Product" ng-repeat="item in items">
…
</div>
I have found schema validator which, for my site actually shows angular expressions:
...
datePublished {{lvl_project['year']}}
name "{{lvl_project['title']}}"
keywords {{lvl_project['tools'].join(',')}}
...
Furthermore, it does NOT show all of the ng-repeat-generated elements.
This seems to me like a strong indication that the google-bot did not see the angular-generated elements and their values, but there could be more to the issue that I don't know.
Yes, you can use...it will work on all (but use if all comes in same category).

SlyRepeat and ngInclude asking for transclusion on

I need to display a potential huge treeview in my webapplication. During testing I found out that using the standard template rendering method of angular with ngRepeat and ngInclude are not performing enough (it takes around 5 seconds to show the info). Removing binding (because there is no use for it) gave no results.
After some googling I found a module called scalyr https://github.com/scalyr/angular This should really optimize the performance of rendering.
My code:
<script type="text/ng-template" id="tree_item_renderer.html">
{{data.name}}
<ul>
<li sly-repeat="data in data.childNodes " ng-include="'tree_item_renderer.html'"></li>
</ul>
</script>
<ul>
<li sly-repeat="data in vm.rows" ng-include="'tree_item_renderer.html'"></li>
</ul>
When running this code I get an exception
Error: [$compile:multidir] Multiple directives [slyRepeat, ngInclude] asking for transclusion on: <li sly-repeat="data in data.childNodes " ng-include="'tree_item_renderer.html'">
Is this fixable? Or is it impossible to run scalyr with ng-Include.
There is a problem with multiple transclusions on the same element, but there's an easy solution:
<li sly-repeat="data in data.childNodes ">
<div ng-include="'tree_item_renderer.html'"></div>
</li>
There is a module that offer multiple transclusions, but I've never played with it, so I'm not sure that it works.
When you figure out your tree, tell me if the sly-repeat is worth it, as I've got a huge tree to build as well.

Why does using ng-repeat to iterate html fail when the html contains divs?

When I use ng-repeat to iterate the following code, everything is fine:
<p ng-repeat="user in users">
<input size="50" ng-model="user.name"></input>
<span>Foo</span>
</p>
However, using the following fails:
<p ng-repeat="user in users">
<input size="50" ng-model="user.name"></input>
<div>Foo</div>
</p>
In the latter case, it looks like the div is excluded from the loop and appended only once after the input tags that have been repeated as expected.
I'm trying to understand the difference in behaviour towards div tags.
Thanks for any insights.
EDIT: The question was already answered, but here's a js-fiddle that allowed me to demonstrate the issue: http://jsfiddle.net/f26Cg/5/
You cannot nest <div> elements in <p> element: as shown here, it's permitted to contain so-called phrasing content only.
As <div> opening tag is considered to be an end of <p> element, technically its corresponding element is outside of <p> in the second case - that's why it's not repeated.
I'll quote Josh's answer to this question : Directive inside ng-repeat only appears once
It is actually related to how your browser will handle blocks inside a non-allowing blocks tag.
I imagine this is the browser's doing. Technically, paragraph tags are
only allowed to contain inline elements, which div is not. Some
browsers (most?) will automatically close the <p> when hits an
unauthorized tag. If you inspect the DOM, you will see that even the
div that makes it into the DOM from the ngRepeat is not inside the
generated paragraph.
Josh

Iterating over a list and calling directives depending upon the item types , in angular js

I have a HTML file it iterates over a list of objects as shown and every object has a template( stored in the db) that it uses I get "List" from a web service :-
<ul>
<li ng-repeat="object in List" ng-include="object.TemplateName" > </li>
</ul>
Let object.TemplateName be "template1"
A sample template would have a specific directive with the attributes needed and few html tags as shown "template1":-
template1:-
<directive1 s-web-service-path="object.WebServicePath" >
<h1>any html content</h1>
</directive1>
my directive calls a web service to get the content to be displayed and has its own template... instead of putting directives in a template and including them cant I directly call my directive depending upon the different types of objects that i obtain in List
something like
for Object.Type="1" i call directive1 instead of template1
for Object.Type="2" i call directive2 instead of template2
ngIf or ngSwitch might be helpful here, with a few extra wrapping elements within the ngRepeat, in order to dynamically choose what to include based on Object.Type. Using ngSwitch:
<ul>
<li ng-repeat="object in List">
<div ng-switch="object.Type">
<div ng-switch-when="'1'">
<div ng-include="object.TemplateName"></div>
</div>
<div ng-switch-when="'2'">
<directive1 s-web-service-path="object.WebServicePath" >
<h1>any html content</h1>
</directive1>
</div>
</div>
</li>
</ul>
The above is not tested, so there could potentially be an error. You might also be able to cut down on some of DOM nesting level by including the ng-switch-when attributes on the directive1 / ng-include divs, but the way above makes the behaviour clear, and avoids any unexpected issues that might arise from having multiple directives work on the same element.

Include behaviour inside ng-switch

I'm building a reasonably non-trivial Angular-js application for the first time and am trying to establish some intuition about how to get things done. Most things are making sense, but there's one pattern in particular that has me stumped -
Whenever I place an "include" style directive inside an ng-switch, it is ignored. I've experimented with just about every style of ng-switch, ng-include, and ng-transclude I can think of to achieve the desired behaviour, but to no avail. I haven't noticed any documentation indicating that this would be disallowed, nor any equivalent style of pattern.
Here is an example of what I have tried to do:
<div ng-switch="is_logged_in()">
<div ng-switch-when="true">
logged-in:
<div ng-include="'views/logout.html'"> </div>
</div>
<div ng-switch-default>
not-logged-in
</div>
</div>
The expected behaviour being that the logout form is displayed when $scope.is_logged_in() returns true.
The behaviour I see is that "logged-in:" is displayed, but the include isn't.
I've tried various versions of Angular-js. I've inspected the network traffic and seen that the include is in-fact being fetched, but I can't get this to work. I've had the same behaviour manifest when trying to build my own template control structures using directives.
The way I've seen most examples dodge this is by using JS in a directive to manually show/hide various sections of the transcluded content - is this really the idiomatic way to get the behaviour I'm looking for?
Thanks!
While using ng-include I always assign the path to a variable in controller.
$scope.logoutlink ='views/logout.html'
And in the view you can assign as
<div ng-include="{{logoutlink}}"> </div>
It would be helpful to post a JSfiddle link.

Resources