Angular.js ng-repeat unique identifier - angularjs

I am using ng-repeat on a <tr> tag to populate the <td> tags with data pulled from mysql and converted into Json. This works just fine. However, one of the <td> tags that I'm using contains a button.
What I would like to do, is have each of these buttons identified somehow in the DOM, so that I can target then with specific requests.
Example: Page loads, ng-repeat repeats a button 4 times. Each of these buttons would have an ng-click attached to it. I want each of them to open and filter different information in a json file.
Am I correct in assuming that ng-repeat would simply open the same item for each button, and how would I go about making them seperate? thanks.

You can do something like this on the front-end:
<button ng-repeat="item in items track by $index" ng-click="someFunction($index)" >Something happens</button>
Then in your controller:
$scope.someFunction = function (index) {
if (index === 1):
// etc.
else...
// Or use switch, whichever works for you.

You could create the specific function on each item in the array.
<button ng-repeat="button in buttons" ng-click="button.functionName()">{{button.name}}</function>

There's $index for that. It's a very good habit to take for any of your ng-repeat. Also don't forget bind-once if your buttons UI isn't subject to modifications once the DOM has loaded.
<ul>
<li ng-repeat="page in pages">
<a ng-class="{ testClass: $index == pageNumber }" ng-click="setPageNumber($index)">{{ page }} - index is : {{$index}}</a>
</li>
</ul>
http://jsfiddle.net/bonatoc/4z1t4gsm/3/
Also you could do (using bind-once):
<button
ng-repeat="button in ::buttons track by $index"
id="button_{{$index}}"
class="{{button['css_class']}}"
...given your buttons were a JSON object as well (beware, ng-repeat likes arrays, not objects. Arrays of objects are fine):
$scope.buttons = [
0: {
'css_class': someClass,
'functionToTrigger': function(...
// ...

Related

How to create an independent indexer with default value inside ngRepeat loop

I have a list of posts with comments. I need to traverse through array of comments inside each of the posts on my page. I'm trying to create variable inside ngRepeat for posts which I can use like an indexer to display exact comment for each post. Due to ngRepeat creating nested scope, this variable must be unique for each iteration. But when I'm trying to change it with ng-click, it doesn't change.
My ngRepeat:
<div class="question_block col-xs-12"
ng-repeat="answer in question.content.answer track by answer.id">
is followed by <span style="display:none">{{counter=0}}</span>. And then I'm showing some items like <span>{{answer.comments[counter].user.organization.title}}</span>. When I'm trying to do something like <a href ng-click="counter++">Increment</a> nothing happens. What's the matter ?
Use ng-init="counter = 0" and attach your ng-click to a function in your controller:
<div ng-repeat="item in items track by $index" ng-init="counter=0">
{{item}} ({{counter}})
<button ng-click="clickHandler()">Increment</button>
<hr />
</div>
Then, to increment counter in the context of the event, use this.counter
$scope.clickHandler = function() {
this.counter++;
};
Plunker demo : http://plnkr.co/edit/J4d0JlJSKD7i4OfMT2r4?p=preview

AngularJS ng-repeat list with buttons: Disable button after click

I have in AngularJS a list with multiple entries and for each entry a button. When clicking the button, the application will do some stuff and after that was successful, the button should be disabled.
The interesting part in my template look like this:
<li ng-repeat="item in items">
<span>{{item}}</span>
<button ng-click="doSomeStuff(item)">Request</button>
</li>
I already tried to use the ng-if directive, but then of course every button will disappear.
Previously, I thought about a solution in raw Javascript or jQuery, because it is very easy just to modify the button by its id. But is there a solution provided by AngularJS?
Use ng-disabled as follows:
<li ng-repeat="item in items">
<span>item</span>
<button ng-click="doSomeStuff(item)" ng-disabled="item.disabled">Request</button>
</li>
Controller:
$scope.doSomeStuff = function(item) {
//do operations and finally set disabled to true for that button
item.disabled = true;
}

How to display data in angular accordion differently for each accordion

I am using angular accordion. It will display accordions based on the object size in the (ng-repeat). When I click the Accordion Heading it should make an api call and store the result in a variable (department details) and it should be displayed in the Expanded window of the accordion.
When I click the first Accordion, it is making an API call and displaying data correctly in the Accordion window. But, When I click the second Accordion it is making an api call and now the data in both the accordions (first and second) are the same because the department details variable has the result of the second accordion api call.
How can I display the data unique to each accordion?. Should I make all api calls in controllers itself, store the results in an array, and use it in html instead of making api calls only when I click Accordion-heading. Thanks in Advance.
HTML:
<accordion close-others="false">
<accordion-group is-open="isopen" ng-repeat="item in object">
<accordion-heading">
<span ng-click="Ctrl.getinfo(item.id)">
{{item.label}}
</span>
</accordion-heading>
<div>
{{Ctrl.departmentdetails}}
</div>
</accordion-group>
</accordion>
Controller:
public getinfo (departmentid): void {
this.departmentdetails = null;
this.services.getdepartmentdetails(departmentid).then((response):any=>{
this.departmentdetails= response;
});
}
your problem is that Ctrl.departmentdetails is one string value that you use in each section of your ng-repeat. your current design just updates the value of one variable that gets repeated many times. Ctrl.departmentdetails has little to do with your ng-repeat and that is your problem. Right now you have the same string bound to many places in your view and when you do getinfo(), you are just updating that one string, which is then going to update it everywhere that it appears in your html.
your getinfo(item) function should take the item object and not just the id as an argument and then it will set departmentdetails on on the item object that you pass into it. this would allow each item to have its own departmentdetails data.
you need to make getinfo() add a departmentdetails property to your item object when you make the api request, or else stick it in another array that you can use as a datasource for your view.
and change your html to something like this, or something that refers to the array of departmentdetails data that collects as your user expands each section.
<accordion close-others="false">
<accordion-group is-open="isopen" ng-repeat="item in object">
<accordion-heading">
<span ng-click="Ctrl.getinfo(item)">
{{item.label}}
</span>
</accordion-heading>
<div>
{{item.departmentdetails}}
</div>
</accordion-group>

Pagination repeater has an active class that i must move when pagination button clicked

Take the following pagination html and repeater:
<ul id="ProductListPagination" class="pagination">
<li class="disabled"><span aria-hidden="true">«</span><span class="sr-only">Previous</span></li>
<li ng-repeat="n in PageCount" ng-class="{active: n==1}"><a ng-click="Paginate( n )" href="#"><% n %> <span class="sr-only">(current)</span></a></li>
</ul>
How do I go about moving the active class on the repeater when one of the pagination buttons are pressed... Is there a built in angular way?...
context:
If there is no built in way in angular, how do I pass the dom element through to the Paginate( n ) function?
I have the receiving function:
$scope.Paginate = function( obj, page ){
// Remove currently active button's active class
$( "#ProductListPagination li.active" ).each( function() {
$( this ).removeClass( "active" );
} );
// Add to element just clicked on
$( obj ).parent().addClass( "active" );
...
}
And the html to go with that, you'll see I tried passing in this.
<li style="cursor:pointer" ng-repeat="n in PageCount" ng-class="{active: n==1}"><a ng-click="Paginate( this, n )" href="#"><% n %> <span class="sr-only">(current)</span></a></li>
But that doesn't work as this, is not a dom element.
Directives
This could be done with Directives, these allow you to define custom markup ie. an element, an attribute name, it even can hook onto class names. Then from that you can attach all sorts of stuff.
https://egghead.io/lessons/angularjs-first-directive
So you could make a "Pagination" directive.
and that would then be used something like:
<my-pagination pages="arrayInScope">
You can then provide an external template or even a string of markup (eww) for what needs to be either IN this element or to replace this element.
Another Solution
But this is a quick way and I guess it doesn't really need any more over complicating anyway.
Example on CodePen
From the markup I am calling the paginate function parsing ng-repeat's provided $index. In the paginate function in the js i then set it.
As angular digests this: ng-class="{ active : page == current }" will then re-evaluate.
But if you need access to the element for some reason then use directives. jQuery is best avoided when using Angular, if it is just a class change or a visibility toggle etc. then its best to let Angular do it for ya'
Hope that helps.

Getting the jQuery object that has been clicked on in angular via $event

I have a list like this. It is pre rendered and so cannot make use of anything attached to ng-repeat.
<li ng-class="{ 'active': 1 == selectedIndex }">
Item 1
</li>
I want to be able to toggle the class of the <li> when the a is clicked.
Looking at some other answers to similar questions on here, it seems as though there is a variable associated with ng-repeat which means you can use an $index variable to achieve this. As this list is pre-rendered this is not available and so I guess I have to do it the jQuery way.
I see that I have access to an $event object but event.target only gives me the DOM element, I would like to be able to convert it into a jQuery object. Is this possible?
You have to think about this in a different way than you would normally. You can't modify the DOM within angular like you do with plain old jquery. Here is what you should do:
<li ng-class="{ active: selectedItem == item }" ng-repeat="item in list">
{{ item.name }}
</li>
Then in your controller:
$scope.selectedItem = null; // if this is loaded from a service then you can set it after it loads.
$scope.itemSelected = function( item ) {
$scope.selectedItem = item;
}
No need to play around with indexes, jquery, or one off code.
Charlie

Resources