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

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

Related

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

How do I create a read-only ng-repeat?

Initial rendering is very slow in ng-repeat. How do I create a read-only version of ng-repeat, such that when the array that you're iterating over changes, the rendered HTML does not change
A double colon makes things in Angular read-only. Use the following syntax:
<ul>
<li ng-repeat="item in ::items">{{item.name}}</li>
</ul>
if read only, have you tried bindonce?
https://github.com/Pasvaz/bindonce

Static list item inside ngRepeat

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>

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.

Angular.js - Understanding what statements can go in an ng-class query

The Angular docs are really sparse on what is acceptable in an "expression" within a conditional ng-class.
For example, I'm running an ng-repeat over a list:
<ul class="clothes">
<li ng-repeat="piece in clothes | filter:query">
{{piece.name}}
</li>
</ul>
On every third <li> element I'd like to add a class of "third". Can this be done using ng-class with something like ng-class="{third : li:nth-child(3)}" or similar?
Side-note, is there a general reference somewhere that defines and gives examples of what can be used in an Angular expression? There's some really basic stuff that I can do with vanilla Javascript/css but I can't work out how to cram it into Angular!
Just create an expression that evaluates to true or false, a bit similar to Javascript expressions but with some differences, you can read about it here.
<ul>
<li ng-repeat="item in items" ng-class="{third: !(($index+1)%3) && !$first }">{{item}}</li>
</ul>
Here is a jsBin.
In my code I am telling ng-class to add the class 'third' when ($index+1)%3 is zero and it is not the $first list item ($index, $first and $last are created by ng-repeat).
if you want to use css instead of angular for the styling, you can use the css nth selector
http://www.w3schools.com/cssref/sel_nth-child.asp
li:nth-child(3n+3)
{
background:#ff0000;
}

Resources