assign alias to long reference names inside ng-repeat - javascript

I would like to be able to assign an alias to a long reference name inside an ng-repeat directive.
Right now I have 2 complex objects, one acts as a kind of grouped index for the other. The ng-repeat template code works fine but it is becoming very difficult to read and I dread the thought of returning to it in a few months time.
If possible, I would like convert something like this:
<div ng-repeat="a in apples">
<div>
<span>Type</span>
<span>{{a.category[1].information.type}}</span>
</div>
<div>
Don't you just love <span>{{a.category[1].information.type}}</span> apples.
My granny says {{a.category[1].information.type}} apples are the best kind.
I would pick {{a.category[1].information.type}} over {{apples[0].category[1].information.type}} apples any day of the week.
</div>
</div>
into something like this
<div ng-repeat="a in apples"
ng-example-assign="ta = a.category[1].information.type">
<div>
<span>Type</span>
<span>{{ta}}</span>
</div>
<div>
Don't you just love <span>{{ta}}</span> apples.
My granny says {{ta}} apples are the best kind.
I would pick {{ta}} over {{apples[0].category[1].information.type}} apples any day of the week.
</div>
</div>
The ng-example-assign directive I made up for this example. Can anyone tell me if something like this is possible using angular or ng-repeat? It may be that I need to rethink the code but I thought I would ask here first. TIA!

You can use ng-init for this:
<div ng-controller="MyCtrl">
<div ng-repeat="s in data" ng-init="address = s.address">
{{ address }}
</div>
</div>
jsfiddle:
http://jsfiddle.net/5yfgLgr9/2/

Using a directive with isolated scope it would be fairly straightforward.
Template HTML
<div assign="ta" source="data[0].items[0].subitems[0]">
Directive
app.directive('assign',function(){
return {
scope:{'assign':'#', "source": '='},
templateUrl: 'testTemplate',
link:function(scope){
scope[scope.assign]=scope.source;
}
}
});
generally a good idea to avoid naming custom directives with ng to avoid possible conflicts with upgrades or third party modules that might also use them
DEMO

Related

How to use the ng-repeat $index variable in an AngularJs expression?

I'm generating a lot of HTML with ng-repeat. I rely on the $index variable in order to index data in my controller.
I do alot of stuff like
ng-submit="validateExistingGuest($index)"
In this case, an undetermined number of HTML forms is generated, hence the index.
Problem is, i sometimes need to use this variable inside a different kind of expression. That would look something like that:
ng-if= "user{{$index}}.valid"
Of course, that doesn't work. I tried ways of constructing that expression, with no success.
How would one go about doing this?
You need something like
ng-if="user[$index].valid
<div ng-repeat="value in user track by $index"> ...
//now you can use the {{$index}}
<div ng-if="user[$index].valid">Show only if valid!</div>
</div>
Why don't you use the object instead the $index?, try
<div ng-repeat="car in cars" >
<p {{car}}></p>
<button ng-click="buy(car)" > buy </button>
</div>

ng-controller variable Vs ng-init vairable

For below code, using angularJS,
<script type="text/javascript">
angular.module('app').controller('add', ['$scope',function($scope) {
$scope.name = "Bonita Ln";
}]);
</script>
corresponding Javascript code to access $scope variable member name is,
<div ng-app="app" ng-controller="add">
<script type="text/javascript">
var dom_el = document.querySelector('[ng-controller="add"]');
var ng_el = angular.element(dom_el);
var ng_el_scope = ng_el.scope();
var name = ng_el_scope.name;
</script>
</div>
Below is the angular code, accessing ng-init variable name using angular expression,
<body ng-app="">
<div ng-init="name='Bonita Ln'">
{{name}}
</div>
</body>
How do I access the ng-init variable name using JavaScript?
you can do this by accessing variable $scope.name in your controller, but it has to be define inside your scope.
<div ng-init="name='Bonita Ln'">
{{name}}
<div ng-controller="MyCtrl">
Hello, {{name2}}!
</div>
</div>
angular.module('myApp',[]).controller('MyCtrl',function($scope) {
$scope.name2 = $scope.name;
})
this works, as you have define name in parent scope to controller, and is being inherited
but if for same controller html template will look like that:
<div ng-controller="MyCtrl">
<div ng-init="name='Bonita Ln'">
{{name}}
Hello, {{name2}}!
</div>
</div>
then it won't work, as variable was undefined when controller function was invoked
You could use it in exactly the same way, but you shouldn't.
I've downvoted your question because it is really really really bad practice, and I mean like every line of code you provided is bad practice.
I'm struggling trying to find out what you'd like to do, so I can't really provide you with better code to do so, but I can provide you with some links you must check out before continuing with whatever you're coding now.
Shaping up with Angular is a free codeschool course provided by the angular team, it is a really good course that will give you more insight on how to use angular than the phone-tutorial on the angular website.
Papa Johns Angular styleguide a great guide on how to write maintainable code.
thinkster.io a step by step guide to learn to master Angular
egghead.io a collection of good video tutorials
I know that my comment sounds quite harsh, but future you will thank you if you write more standardized Angular, and keep to a defined style-guide.
Also remember, in angular, your code should not know about the DOM, you don't need to specify eventListeners to DOM-elements, just use the appropriate directives like ng-click.
(yes I am aware that there can be exceptions to the rule)

AngularJS: how to optimize nested directives

I have the following template for directive item in angular. Item contains property type in it's scope. Based on this type I need to render different template.
<item ng-repeat="myItem in items track by myItem.id">
<div ng-switch="::myItem.type">
<div ng-switch-when="type1">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type2">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type3">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type4">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type5">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type6">
Some complex html with a couple of ng-if and ng-include
</div>
</div>
</item>
I'd like to rework every ng-switch-when in the standalone directive, and improve performance of ng-repeat (right now it has to make ng-include and set innerHTML for every item and it's a heavy operation for the browser even for list of 50 items).
So my questions are:
how to rework ng-switch-when into standalone directives
how to improve performance of the ng-repeat in this case
Update:
The question related to the AngularJS: Parse HTML events in timeline it's one the reasons why I would like to optimize current structure.
added missed track by
a lot of ng-if and ng-include statements is needed because every widget that represented by ng-switch-when has it's own logic and will be rendered based on some other parameters of myItem.
The problem also that I need to fully rebuild this list of item by some user action.
BTW:
In react I can do something like:
render: function() {
//it's for two items, but can be extended for any number of templates
var child = this.props.type === 'Type A' ? <TemplateA /> : <TemplateB />;
return child;
}
I don't know why you need a lot of IF statements, and why you want use directives for that, but i can help you with advice for ng-repeat.
Use track by $index in ng-repeat to improve performance. And check articles about Angular performance, like this: 11 Tips to Improve AngularJS Performance
Also, if you have interface with a lot of elements which need to render, may be you should look in ReactJS which is faster for rendering.

Store value in a directive for later use

I would like to save an object in a ngRepeat so that I can use that object in its children, like shown in this code:
<div ng-repeat="bar in foo.bar>
<div ng-repeat="qux in baz.qux" myvalue="{'item1':foo.var1, 'item2':qux.var2}">
<div ng-click="myFirstFunction(myvalue)"></div>
<div ng-click="mySecondFunction(myvalue)"></div>
</div
</div
The object I want to generate and then use is rather large and I'd rather not define it repeatedly for each ngClick directive.
I considered saving it into a scope variable but the object will change for each iteration of the ngRepeat.
Is there a directive or an other way that I can use to store this value for later use?
To avoid the repetition of what is probably a long variable definition, you can use the ngInit directive, whose content will be executed each time a corresponding element is created.
<div ng-repeat="bar in foo.bar>
<div
ng-repeat="qux in baz.qux"
ng-init="myValue = {'item1':foo.var1, 'item2':qux.var2 }"
>
<div ng-click="myFirstFunction(myValue)"></div>
<div ng-click="mySecondFunction(myValue)"></div>
</div>
</div>
However, a complex code in a template is rarely a good idea. Contemplate moving your logic inside a controller, as advised by the documentation:
The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
You can just do the naive thing here and it'll work:
<div ng-repeat="bar in foo.bar>
<div ng-repeat="qux in baz.qux">
<div ng-click="myFirstFunction(foo, quz)"></div>
<div ng-click="mySecondFunction(foo, quz)"></div>
</div>
</div>
Angular will know the scope of the repeat when you click.
You could store it in local storage using ng-storage.
https://github.com/gsklee/ngStorage
This would allow you to store it, then use it anywhere in the application.
cookies, you also have ng-cookies
https://docs.angularjs.org/api/ngCookies
try this out! or cookieStorage

Select different child JSON element with select input in AngularJS

I am printing a list of food types by making an API call per category. The food in the categories have this JSON structure:
{"uid":"56",
"title":"Nussbrot",
"code":"X 39 2000000",
"final_factor":"0",
"sorting":"0",
"unit":[
{"title":"Scheiben",
"gram":"45",
"max":"100"
},
{"title":"Messerspitzen",
"gram":"250",
"max":"12"}
]
}
I am looping through & printing the values out into a template. No problem. I am printing the "unit" values into a select box:
<option ng-repeat="title in food.unit">{{ title.title }}</option>
And I am currently printing out the grams & title of the first unit in each food like this:
<div class="max">Max is: {{ food.unit[0].max }}</div>
<div class="grams">Grams is: {{ food.unit[0].gram }} </div>
How can I make this dynamic, so that I am printing out the max & grams of the currently selected unit?
Here's my Plunkr.
Angular makes dealing with options and selected options very easy. You should stop thinking in terms of indexes or value. With angular you can bind the entire object, so there's no need to look it up. For example you could do the following for your select:
<select ng-model='selectedUnit' ng-options="unit as unit.title for unit in food.unit"></select>
Let me briefly explain the expression for ng-options
unit in food.unit means we will iterate over the food.unit array storing each value in unit as we go along.
unit as unit.title means what we are putting in the ng-model whenever the user selects an item is the entire unit object itself. The as unit.title tells angular to use the title of the unit as a display for the option.
What this ends up doing is that whenever the user selects one of the options, the entire unit object will be stored in the ng-model variable (in this case selectedUnit). This makes it really easy to bind it elsewhere. For example you can just do:
<div class="unit">Unit is: {{ selectedUnit.title }}</div>
<div class="max">Max is: {{ selectedUnit.max }}</div>
<div class="grams">Grams is: {{ selectedUnit.gram }} </div>
In angular, if you find yourself dealing with indexes or ids and then looking things up by id or index then you are typically doing it wrong. One of the biggest advantages of using angular is how easy it is to deal with objects, and you should really take advantage of it.
For example, I often see newbies doing something like
<li ng-repeat="person in persons">{{person.name} <a ng-click="savePerson(person.id)">Save</a></li>
And then in their code they use the id to look up the person from an array:
$scope.savePerson = function(id){
var person = persons[id];
$http.post('/persons/'+id, person);
};
This kind of lookup is almost always unecessary with angular. You can almost alway just pass the person right away:
<li ng-repeat="person in persons">{{person.name} <a ng-click="savePerson(person)">Save</a></li>
And then have the click handler take the person:
$scope.savePerson = function(person){
$http.post('/persons/'+person.id, person);
};
I know I strayed a bit from your original question. But hopefully this makes sense and helps you write things more simply using the "angular way"
Her is the plunkr for your example:
http://plnkr.co/edit/lEaLPBZNn0ombUe3GPa9?p=preview
you can fist of all handle the selected item with the ng-selected:
http://docs.angularjs.org/api/ng.directive:ngSelected
<select>
<option ng-repeat="title in food.unit" ng-selected="selectedIndex=$index">{{ title.title }}</option>
</select>
<div class="max">Max is: {{ food.unit[selectedIndex].max }}</div>
<div class="grams">Grams is: {{ food.unit[selectedIndex].gram }} </div>
This should propably work ;) Havn't tryed it yet!

Categories