Static list item inside ngRepeat - angularjs

So,
I am rendering a basic list using ngRepeat, but need the first <li> to be static content, rather than being generated from the data array:
e.g.
<ul ng-repeat="item in items">
<li>This is text from the template and will always be the same.</li>
<li>{{item}}</li>
</ul>
I've also looked at using ng-repeat-start, but just can't quite get to a solution.

It is a common misconception that people want to use ng-repeat on the parent element, when in fact you use it on the actual elements that do the repeating.
You just need to change it to:
<ul>
<li>This is text from the template and will always be the same.</li>
<li ng-repeat="item in items">{{item}}</li>
</ul>

Related

Bootstrap dropdown header using ngRepeat

I want to populate a BootStrap dropdown using ngRepeat. I can populate the items just fine but what if I want to have one header per iteration?
<ul class="dropdown-menu">
<li class="dropdown-header">Dropdown header 1</li>
<li ng-repeat="order in orders">{{order.name}}</li>
</ul>
With this I can get only one header understandably.
Use ngRepeatStart and ngRepeatEnd
<li ng-repeat-start="order in orders" class="dropdown-header">Dropdown header {{$index}}</li>
<li ng-repeat-end="order in orders">{{order.name}}</li>
You can use ng-repeat-start and ng-repeat-end.
<ul class="dropdown-menu">
<li ng-repeat-start="order in orders" class="dropdown-header">Dropdown header {{$index}}</li>
<li ng-repeat-end>{{order.name}}</li>
</ul>
You also don't have to write: ng-repeat-end='order in orders'. you can just mention ng-repeat-end
Read more about it here: ng-repeat start and end
You didn't specify, but I assume you're using the jQuery library that goes along with it. I would highly suggest using Angular UI Bootstrap instead. They've taken care of this for you. I'm sure there are other components you'd like to use as well.
https://angular-ui.github.io/bootstrap/#/dropdown
Update I now realize I misunderstood your question, but I would still take a look at the Angular UI Boostrap library if you're not using it already.

Angular Directive with Replace=false creates list html that is non semantic

We are thinking about moving to directives that use replace=false, as I hear replace=true is being deprecated. One problem I cant figure out how to fix, is for all directives that are based on lists, the resultant html is not semantic.
For example a list directive might be something like:
<tg-list tg-compact="true">
<tg-list-item>foo</tg-list-item>
<tg-list-item>bar</tg-list-item>
</tg-list>
this will currently (with replace=true) compile to:
<ul class="o-list o-list--compact">
<li class="o-list-item">
foo
</li>
<li class="o-list-item">
bar
</li>
</ul>
with replace=false we will end up with either:
<tg-list class="o-list-icon o-list-icon--compact">
<ul>
<tg-list-item>
<li class="o-list-item">foo</li>
</tg-list-item>
<tg-list-item>
<li class="o-list-item">bar</li>
</tg-list-item>
</ul>
</tg-list>
or:
<tg-list class="o-list-icon o-list-icon--compact">
<tg-list-item>foo</tg-list-item>
<tg-list-item>bar</tg-list-item>
</tg-list>
The first is bad because it is definitely non semantic, the second is bad because although it is "semantic" (as in html5, custom tags are ok), we lose anything that ul>li would have given us (a screen reader, for example, may have special ways to treat them).
Perhaps we can use the html5 'role' attributes? But if so i think the list item would need add the role to the element in the link function?
Dunno, but how have you lot solved this?
You can configure directives to have restrict set to A which stands for attribute. That way you can use it as:
<ul tg-list tg-list-compact=true>
<li tg-list-item>
foo
</li>
<li tg-list-item>
bar
</li>
</ul>
So what I did in the end is make the list-item wrap itself in an "li" in its link function.
The list-item link:
public link = ($scope: angular.IScope, $element: angular.IAugmentedJQuery) => {
$element.wrap('<li></li>'); }
Pretty simple in the end, but makes the html much more symantic so i am happy. Shout out to Sander for the help

Is there any directive that acts like a "with" in angular?

Say you have an object yourObject on the scope and you want to access some deep properties like the following :
<ol>
<li ng-bind="yourObject.thing.map.one"></li>
<li ng-bind="yourObject.thing.map.two"></li>
<li ng-bind="yourObject.thing.map.three"></li>
</ol>
Is there any built-in directive that could make it look more like this:
<ol ng-with="yourObject.thing.map">
<li ng-bind="one"></li>
<li ng-bind="two"></li>
<li ng-bind="three"></li>
</ol>
UPDATE
A similar question was already. Please see Equivalent of {{#with}} in angular
One way I would do this scenario is by implementing a controller that will have a variables to those an array of one, two three... and then using ng-repeat to loop over that.
So for ng-controller, you could write, ng-controller="SomeCtrl as ctrl"
and then ctrl.arrayVariable would hold an array of all the data you want to show
To make matters very simple, you could use ng-repeat to loop through the data.
So, possibly, ng-repeat="var in ctrl.arrayVariable"
Anyways, I'm not sure exactly how your code is structured, but it should work in most instances.
Long story short, ng-repeat is awesome

How to use nginfinite-scroll to work on an element?

I have got a number of components/windows (divs) on my html page; each div meant to show a large amount of data. Am trying to use nginfinite-scroll (http://binarymuse.github.io/ngInfiniteScroll/documentation.html) on each of these components so that infinite scrolling happens inside each of them. But looks like the infinite-scrolling is triggered only when an element on which the nginfinite-scroll is called nears the end of the browser-window. But i can't have my components move. How do i get infinite scroll happen in-place, i mean inside each component/element whose position would not near the browser end? Hope, the problem statement is understood.
Here's my html:
<div id="myDiv">
<ul class="list" infinite-scroll='nextPage()' infinite-scroll-disabled="false">
<li data-ng-repeat="item in items">
<span>{{item}}</span>
</li>
</ul>
</div>
Regards

correct strategy to generate html dynamically with angular

I have a huge JSON object tree with two levels. First level has around 500 elements, and each element contains an average of 100 child elements.
I want to display the first level of the tree and I am doing it with a simple ng-repeat. When the user clicks on the element I want to display the child elements of that element. If I use a span ng-switch or a ng-show to show/hide child elements when the page first renders it freezes for around 10 seconds while generating all the HTML.
It doesn't sound like the right solution. There must be a different way of doing it, but I can't figure out. Anyone knows?
I have explained most in my comment, and here is a working plunker:
http://plunker.co/edit/RSZwfLlsCJ68MUkACbdp?p=preview
the new ng-if directive will do what you want
<h1>ng-if</h1> <h5>Click on the level to expand</h5>
<div class="well">
<ul class="nav nav-list" ng-repeat="(attr,element) in tree">
<li ng-click="expand=!expand" ng-class="{'active':expand}"><a>{{element.name}}</a></li>
<ul ng-if="expand" class="nav nav-list">
<li ng-repeat="item in element.items">{{item.name}}</li>
</ul>
</ul>
</div>
you can also do this in the "old-way" with ng-show using new ternary operator or its alternative expr && if_true || if_false
<h1>old-way</h1> <h5>Click on the level to expand</h5>
<small>use ternary operator or <pre>expand && element.items || []</pre></small>
<div class="well">
<ul class="nav nav-list" ng-repeat="(attr,element) in tree">
<li ng-click="expand=!expand" ng-class="{'active':expand}"><a>{{element.name}}</a></li>
<ul ng-show="expand" class="nav nav-list">
<li ng-repeat="item in (expand ? element.items : [])">{{item.name}}</li>
<!--<li ng-repeat="item in (expand && element.items || [])">{{item.name}}</li>-->
</ul>
</ul>
</div>
See this answer on ng-repeat performance. Essentially, it just takes a long time since Angular's ng-repeat, and basically all other directives, are set up to always look for updates in the whole JSON structure. So if you have lots of data and don't need live updates in the HTML view when changing the JSON, I wouldn't recommend using AngularJS. Generally, AngularJS performance also depends a lot on the browser and its JavaScript engine.
Alternatively, you could divide your JSON into subparts and then use pagination to display it.
I would recommend to fetch the data gradually from the server. Use server-side pagination and retrieve only the fields that you are going to display. Then, when a user clicks on one of the first level items, you can do another XHR to the server with the new data. I had similar requirements for a project and that solved the latency issue.
Regards,
Agustin.

Resources