Unable to use ng-if with ng-repeat $index - angularjs

I'm trying to use ng-if to display a button based on filters being present on screen. I'm using md-chips to show filters in categories.
HTML:
<div ng-repeat="filter in sc.filters track by $index">
<md-chips ng-model="filter.value" ng-if="sc.isArray(filter.value)" md-on-remove="sc.filter()"></md-chips>
</div>
<button ng-if="$first" ng-click="sc.newSearch()">clear filters</button>
I track the index and try to add the button if first item was present. It doesn't show the button at all. Any help appreciated.

$first should be used within an ng-repeat statement. In this case you don't want to use $first though.
If you want to add the button if the first item is present, why not just do something like this:
<button ng-if="sc.filters.length" ng-click="sc.newSearch()">clear filters</button>

Related

How to run autoclick on first button in button set in ng-repeat?

I have set of buttons, I used ng-repeat. I would like to have pressed first button after load page
I thought about ng-init but I don't know how to use reference to first button..
You can use $first to return a boolean that is true if the element is the first in the array, and then put some logic in there that will check for that along the lines of
if($first){
//do something
}
or something like
ng-class="$first ? conditionA : conditionB"
if you want to conditionally set CSS
https://docs.angularjs.org/api/ng/directive/ngRepeat
You can achieve what you need with ng-init like this:
<td ng-repeat="item in items">
<a href="">
<button type="button" ng-click="onClick($index)" ng-init="$first && onClick($index)">{{item.title}}</button>
</a>
</td>
onClick function will be called only for the first button
see working demo here: demo

Angular.js ng-repeat unique identifier

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(...
// ...

Override ng-hide on ng-click

On the process of trying to learn angularjs, I am creating a set of divs using ng-repeat. I have five divs in all. I am only displaying the first div using $firstdirective component.
<div class="container" ng-app="demoApp" ng-controller="demoController">
<div class="row" ng-repeat="job in jobs" ng-hide="!$first">
<div class="col-md-4">
{{job}}
</div>
<div class="col-md-4">
<button class="btn-primary btn-xs add" ng-click="showNext($event)" ng-hide="$last">Add</button>
<button class="btn-primary btn-xs delete" style="display: none;">Delete</button>
</div>
</div>
</div>
That works.
Now, each div has two buttons, Add and Delete. When I click add I want to hide the add button and delete button of the current row and open the next row. So I wrote,
$scope.showNext = function(evt) {
var elm = evt.target;
$(elm).hide();
$(elm).next().hide();
$(elm).closest("div.row").next().slideDown();
};
This is not working as ng-hide is overriding my slideDown. What is the angularjs way of doing it?
Also I would like the delete button only on the $last visible row && !first. How to find last visible row in ng-repeat?
Fiddle: https://jsfiddle.net/codeandcloud/u4penpxw/
You shouldn't manipulate the DOM with things like $(elm).hide();, you should use ng-class= to let Angular add classes that hide or show the elements. If you switch your ng-repeat to ng-repeat="job in jobs track by $index", you could write something like that in your showNext()-function:
$scope.showNext = function(index) {
$scope.currentJob = $scope.jobs[index]
}
and call it like ng-click="showNext($index) - of course you'd need to do some refactoring as well. But then you could write something like ng-class="{hidden: (job == currentJob}" to hide all buttons except in the current row.
There's a lot of good thoughts in this q&a: "Thinking in AngularJS" if I have a jQuery background?

Show one position of ng-repeat and reload a dropdown each time

So, I'm actually new to angularJS and I've been searching for a while and trying different ways to achieve something, but it seems impossible, to me.
I have this ng-repeat that should show only one of my 6 position array. When I click in "Change", than I should load the second and then the third and so on, until all my data have been accessed and changed by the user, that's why I limited it to 1.
The Professor's select should load according to a parameter from the current ng-repeat class. I have no idea how to solve this problem. I'm trying right now to use a service to load the professor's dropdown, but with no success.
<div class="row" **ng-repeat="class in classes | offset:currentPage | limitTo: 1"** on-finish-render="ngRepeatFinished">
<div style="display: block;">
<div>
<p><label for="">Change:</label> {{ class.professorName }}</p>
</div>
<div>
<p><label for="">By:</label>
<select id="professor" name="professor" class="form-control">
<option ng-repeat="professor in professors" value="{{professor.id}}">{{ professor.name }}</option>
</select>
</p>
</div>
</div>
</div>
<hr>
<center><button type="button" ng-click="change(class.classId)" class="btn btn-primary">Change</button></center>
</div>
What's the best way to achieve something like this (Show only one item each time and after user submits the form, go to the next position... and for each ng-repeat item, I have to reload the professors dropdown)?
Thank you!
Am I understanding you correctly, you want
ng-repeat class in classes //limit 1 //index i.e. [0] +1 change index after button click so you move to the next class index location?
If your setting a value of professor.id in the class or a property that isn't set or is null/undefined before the button, then just add this to your parent div with the loop of class in classes.
ng-if="!class.propName" //if property/dropdown not set
If this isn't what your looking for please expand on your question.

Programmatically Open Bootstrap UI Accordion Generated by Nested Ng-Repeat when Filtered Array is Not Empty

I have a Bootstrap-UI accordion group that generates individual accordion menus using ng-repeat. The content under each accordion is also generated using a nested ng-repeat.
<accordion close-others="false">
<span data-ng-repeat="category in categories">
<accordion-group is-open="filterText.length > 0">
<accordion-heading>{{category}}: {{reportList.length}} Items </accordion-heading>
<div>
<ul>
<li data-ng-repeat="report in reportList = (getReports($parent.$index) | filter: filterText)">{{report}}</li>
</ul>
</div>
</accordion-group>
</span>
</accordion>
The content generated by the second ng-repeat needs to be searchable. When the search is executed, accordions that contain matching values should open and display the matching values. I know that the outside ng-repeat sees the filtered array and its length because i can display the length value in the view (i.e. {{reportList.length}} updates when the filter executes).
The problem comes when i try to put the reportList.length value in the is-open attribute of an <accordion-group>. Using is-open="reportList.length" seems to pass the literal into the directive. In desperation, I tried using is-open="{{reportList.length}}" but that throws the expected syntax error.
Here's a plunker that shows what i have working as well commented out lines that show the way i think it should work (lines 22 & 23). Any suggestions are more than welcome.
Your binding is-open inside of an ng-repeat which creates a child scope for each item (category). You need to bind to $parent.filterText.length as filterText is not a category property.
What you bind the is-open to, Angular needs to be able to assign to it, not just evaluate it. It can evaluate an expression like "foo == 5" but it cannot assign to it.
What I do is create a variable and bind to that, then the accordion can change it, and I can change it, and everybody's happy.
$scope.accordionSettings = {
IsOpen: {
Section1: true,
Section2: false
}};
In the markup:
<div uib-accordion-group is-open="accordionSettings.IsOpen.Section1">
... more markup ...
<div uib-accordion-group is-open="accordionSettings.IsOpen.Section2">

Resources