I'm using the ui-tree in angularjs. For binding I use a method which gives me the child elements:
<div ui-tree="treeOptions">
<ol ng-init="children=getChildren(website.id, '0')" ng-model="children" ui-tree-nodes>
<li ng-repeat="node in children" data-collapsed="node.isCollapsed" ui-tree-node ng-include="'nodeTemplate.html'" ng-cloak></li>
</ol>
</div>
With ng-init I initialize the children array for further usage. This code works, but ng-init is not reevaluated when data changes. So dynamically adding a new item is not possible. Is there a way of setting a local variable in HTML similar to ng-init that gets refreshed automatically?
Related
I want to use ng-repeat more or less as follows:
<div ng-repeat="One_Entry in Entries_List track by One_Entry.Entry_ID"
onClick="DoSomething(One_Entry.Entry_ID)">
<!---
present various fields within "One_Entry"
-->
</div>
Entries_List is a JSON array of objects, being Entry_ID one of the elements within the object.
DoSomething is a function within the related controller that is supposed to perform a specific activity on the structure whose ID is the passed Entry_ID.
I tried using $index as well as $parent.$index but I'm getting an error stating that these variable do not exist.
Could anyone tell me how I can achieve the above functionality?
Thanks.
The object One_Entry is scoped. Therefore onclick won't work. Use ng-click instead which is the Angular version for onclick:
<div ng-repeat="One_Entry in Entries_List track by One_Entry.Entry_ID"
ng-click="DoSomething(One_Entry.Entry_ID)">
<!---
present various fields within "One_Entry"
-->
</div>
It's not OnClick it's ng-click
Change
From :
<div ng-repeat="One_Entry in Entries_List track by One_Entry.Entry_ID"
onClick="DoSomething(One_Entry.Entry_ID)">
To:
<div ng-repeat="One_Entry in Entries_List track by One_Entry.Entry_ID"
ng-click="DoSomething(One_Entry.Entry_ID)">
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
I have this code
http://plnkr.co/edit/aycnNVoD96UMbsC7rFmg?p=preview
<div data-ng-app="" data-ng-init="names=['One']">
<input type="text" ng-model="names[0]">
<p>Looping with ng-repeat:</p>
<ul>
<li data-ng-repeat="name in names">
<input type="text" ng-model="name"> {{ name }}
</li>
</ul>
</div>
When i change value of name[0] in the first input box it changes values of the second input box.
But when i change value of name[0] in the second input box it does not change value of the first input box. Why?
It works if you bind your second input to : names[$index]
<input type="text" ng-model="names[$index]"> {{ name }}
This is due to ng-repeat creating a child scope, so the reference to name inside the ng-repeat is different to that original one in the names array, see here:
New AngularJS developers often do not realize that ng-repeat,
ng-switch, ng-view and ng-include all create new child scopes, so the
problem often shows up when these directives are involved. (See this
example for a quick illustration of the problem.)
Regarding as to why this happens, when you bind the input to name in names inside the ng-repeat, you are creating a new property on the new child scope created by the ng-repeat called name, and thus the ng-model of the textbox created by the ng-repeat is referencing a different name to that of the actual 0th element of the names array. As others have pointed out, if you use names[$index] you are implicitly referencing the 0th element of the names array, thus NOT creating a new name property on the child scope created by the ng-repeat. An angular best practice is not to have ng-models bound to primitives, rather objects, Sandy has mentioned in his answer if you bind to an object you will overcome this, and the 2 other posters have answered this by using $index to refer to the 0th element of the names array. This is one of the nucances of scope inheritance in angular.
A couple more handy links:
Here and here.
Just wanted to give my bit on this. Somewhat related to your problem as I see.
<body>
<div data-ng-app="" data-ng-init="names=[{value:'One'}, {value:'Two'}]">
<p>Looping with ng-repeat:</p>
<ul>
<li data-ng-repeat="name in names">
<input type="text" ng-model="name.value"> {{ name }}
</li>
</ul>
</div>
</body>
Instead of binding the array item directly to the control, I would prefer to create an object of the array and then bind value of each item. This way we can avoid reference problems.
A working prototype jsfiddle
Hope it helps.
You need to provide $index in your ng-model.
<li data-ng-repeat="name in names">
<input type="text" ng-model="names[$index]"> {{ name }}
</li>
You are binding ng-model="names[0]". So it means that you are binding value on first index of names array.
So when we write ng-model="names[$index]" in ng-repeat it means that all values will be bound accordingly into array. $index is an iterator offset of the repeated element.
names[0] = 'One'
names[1] = 'Two'
and so on!
I am following the tutorial on Lynda.com for AngularJS essential training.
Part of my index file looks like:
<div class="container" ng-controller="AppCtrl">
<h1>AngulAir</h1>
<ul class="nav nav-pills">
<li role="presentation" ng-class="destinationsActive">Destinations</li>
<li role="presentation" ng-class="flightsActive">Flights</li>
<li role="presentation" ng-class="reservationsActive">Reservations</li>
</ul>
<div ng-view>
</div>
<p>{{ flightsActive }}</p>
</div>
Now when I click on any link it should fire the setActive function defined in the AppCtrl which looks like this:
$scope.setActive = function (type) {
$scope.destinationsActive = '';
$scope.flightsActive = '';
$scope.reservationsActive = '';
$scope[type + 'Active'] = 'active';
};
Now the problem is very simple. The function should take the type for example 'destinations' and append 'Active' to it and set the scope variable 'destinationsActive' to active which in turn should be reflected in the ng-class directive of the li tags and the link should be active.
I have tried to insert alert('hello'); after setting it active which fires up. Now this means that the function is indeed being called. But when I do alert($scope.destinationsActive); it gives me a blank alert whereas it should give me active as the value.
I am not following with the exercise files and I feel that maybe because the tutorial is relatively older, there might be changes in the framework. I have already encountered such problems with the tutorial. Anyway, what is it that I am doing wrong?
In your ng-click directives you are passing the argument as a variable, not a string.
ng-click="setActive(destinations)"
Will pass in the value of the $scope.destinations, which is undefined. Try passing in a string i.e.:
ng-click="setActive('destinations')"
Note the single quotes
You need to put parenthesis around the parameters in your html javascript function call.
Destinations
Here is a working example: JSFiddle
I would recommend you to think of the model binding in more semantic way. For example use a checkbox instead of link and set the checkbox value as ng-model to a scope variable instead.
<input type="checkbox" ng-model="destinations">
<input type="checkbox" ng-model="flights">
<input type="checkbox" ng-model="reservations">
and thereafter use the model to reflect the rest of the changes (this is the answer to the original question, you have to specify a classname and a condition in brackets:
<li ng-class="{ destinationsActive: destinations }">
Pass argument as string in ng-click.
working code : http://jsfiddle.net/Virbhadrasinh/cLsLfkjm/
I'm listing a json file using angular, like this:
html:
<li ng-repeat="task in tasks">
<h1>{{task.title}}</h1>
<small>{{task.date}}</small>
<p>{{task.details}}</p>
<button ng-click="details($event)" data-title="{{task.title}}" data-date="{{task.date}}" data-details="{{task.details}}"></button>
</li>
js:
$scope.details = function(obj){
var title = obj.target.getAttribute('data-title'),
date = obj.target.getAttribute('data-date');
...
}
I pass all content via data-attributes, when I click on <button> it calls the ng-click and I access all data-attributes via pure javascript and create a <div> to wrap those contents. This way is working just fine, but is there an easier way to get those values via angular?
Much simpler and proper angular way, yes just pass task though the ng-click function expression and access it from your handler and say goodbye to DOM access from the controller (which is anyways bad) and data attributes:-
<li ng-repeat="task in tasks">
<h1>{{task.title}}</h1>
<small>{{task.date}}</small>
<p>{{task.details}}</p>
<button ng-click="details(task)"></button>
</li>
and
$scope.details = function(task){
console.log(task);
//console.log(this.task);
}
Plnkr