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

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">

Related

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

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>

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>

Angularjs make invisible accordion if subelement are filtered

i have created an accordion dynamically with angular.
Code:
<input type="text" class="form-control pull-left" ng-model="searchSingoloCampo.title">
<accordion-group ng-repeat="category in categories">
<li ng-repeat="resource in category.resources | filter:searchSingoloCampo">
</li>
</accordion-group>
The accordions is generated by a list , and inside each accordion there is a sublist of elements.
I can filter the element inside the accordion by using the simple angular filter, but i'm not able to handle the visibility of the Primary accordion when the sublist of element is completely "filtered" by the filter.
Any help?
Thank you
Thanks for the solution!
Here how i have handled it:
<accordion-group ng-repeat="category in categories" ng-show="(category.resources | filter:searchSingoloCampo).length>0">
In this way, i handle the visibility of the "master" accordion when the subset of element are filtered!
Thank you very much
One approach would be to introduce another variable which stores the contents of the filtered array. When the size of this array is 0, you can close the accordion. Something along these lines:
<accordion-group ng-repeat="category in categories" close-accodrion="filteredResources.length">
<li ng-repeat="resource in filteredResources = (category.resources | filter:searchSingoloCampo)">
</li>
</accordion-group>
I made up the "close-accordion" attribute, not sure how you actually close your accordion-group. This assumes you can open/close it w/a boolean expression like filteredResources.length. Maybe you just want to hide it w/a ng-show or ng-hide ... the same approach would work.

Angularjs Accordion Access isOpen State

Is there a way to access whether an accordion-group is open or not? I know there's the isOpen directive but I'm not sure if there's a way to access the state of that while purely in the html. Using (and abusing?) two way binding I can set a variable to hold that state but it will not work out for nested accordions without doing something like isOpen0, isOpen1, isOpen2, etc. I can also use ng-init to "declare" a new isOpen on the scope of the nested accordions but that doesn't sound like a good idea.
<accordion>
<accordion-group is-open="isOpen">
<accordion-heading>
<div ng-class="{'myClass': isOpen}">Static Text</div>
</accordion-heading>
This content is straight in the template.
</accordion-group>
</accordion>
http://plnkr.co/edit/l5y4raei99pedNWcE225
First, you have to use a parent object like in Angular UI's docs' example, status object for example:
<div accordion-group="" ng-init="status = {isOpen: false}" is-open="status.isOpen">
<div accordion-heading="">
<div ng-class="{'is-open': status.isOpen}">NUTRIENT PROFILES</div>
</div>
...
</div>
Then, you can perfectly use the same object name for nested accordion. Reason is simple: accordion-group directive will instantiate a new scope for each group. This way, when a status.isOpen is changed, it won't affect other groups.
Check it: http://plnkr.co/edit/nJ654pvE1itnGDQGp2rk?p=preview

ng-if without breaking stylesheet?

Is there a way to use an ng-if directive without adding a containing element? I'm playing around with dynamic menu items placed by the current view controller and want to handle a dropdown type and non dropdown type, however the ng-if has to be in some kind of element which breaks the bootstrap css.
Here's an example of what I'm trying to do:
<li ng-repeat="item in dynNavList">
<div ng-if="item.dd" ><!--There will be more stuff in here-->
Dropdown test {{item.title}}
</div>
<span ng-if="!item.dd">
NoDropDown {{item.title}}
</span>
</li>
Any nav item created in that html above doesn't style correctly in the navbar because it's inside a div or span element so the css doesn't apply.
I do not want to modify the bootstrap css to get this working and I'm trying to avoid writing any custom directives if possible.
Any suggestions?
ng-if directly on the anchor is fine, demo.

Resources