Angularjs Accordion Access isOpen State - angularjs

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

Related

How to access nested elements in AngularJS

I have a list of items (divs) with a button. When I click on one of this buttons I can access the element using
$event.currentTarget
that returns some thing like
<div ng-click="myFunc()">
<i class="someclass"></i>
<span>bla bla</span>
</div>
how can I access and elements to modify attributes like class?
Don't. Use existing directives like ng-class or ng-if, etc in your html templates.
<div ng-click="clicked = true">
<span ng-class="{'someclass': clicked}">bla bla</span>
</div>
See stackblitz
Although you can get the html dom element and edit it you should only do this as a last option and other angularjs supported methods have failed or are not supported.
template
<div ng-click="myFunc($event)">
<i class="someclass"></i>
<span>bla bla</span>
</div>
controller
$scope.myFunc(event) {
var elem = angluar.element(event.currentTarget);
elem.children(".someclass").removeClass("someclass")
}

ng-show not working inside ng-if section

ng-show is not working in following code
<button ng-click="itemIndex=0;showHome=true;" class="btn btn-link">Home</button>
<div ng-if="itemIndex==0">
<div ng-show="showHome">{{showHome}}
<h3>Home Section</h3>
<img ng-click="showHomeItems=showHomeItems?false:true;showHome=false;" ng-src="images/home.png"/>
</div>
<div ng-show="showHomeItems">
Home Items{{showHome}}
</div>
</div>
Without ng-if it is working fine but with ng-if its not working.
Read this article.
There are some directives in Angular that create a child scope, like ng-repeat, ng-if.
Inside those scopes, the booleans (such as showHome) are searched only within that new scope, and not in the parent scope.
In order to avoid such bugs, it's considered best practice to place the logic in the controller (or service, just not in the HTML) inside an object, which is not a primitive variable and will be looked up in the scope prototypical chain.
Try declaring a variable like this:
$scope.switch = {showHome : true}
and then use it in the html like this:
<div ng-show = "switch.showHome" >

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

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.

Jasmine-jquery, testing generated GUI for (nested) directives

I recently started using jasmine-jquery (1.3.1) together with angular (1.0.6) and need an advice on testing GUI.
I have some view for controller, which has angular directives, like 'view.html':
<div id='main-div'>
<div my-directive objects-to-iterate='someScopeObjects'>
<span id='default-span'>some default text</span>
</div>
</div>
, and in JS a directive "myDirective" is defined, having template-by-url 'myDirective.html' which includes ng-repeat and makes some nested div (row) foreach in objectsToIterate.
I load fixtures for 'view.html' and 'myDirective.html'.
Now I would like to test that during user interaction there are really some elements (rows) in 'myDirective' repeated block.
Beginning was simple:
var div = $('div#main-div');
div = $compile(div)(scope);
scope.$digest();
expect(div).toBeVisible();
And now I'm stuck. Cannot get access to "generated" source of 'myDirective' element. If I use
div.find('whatever-selector-for-element-my-directive'),
I get
<div my-directive objects-to-iterate='someScopeObjects'>
<span id='default-span'>some default text</span>
</div>
If I try to compile+digest this html against scope, I still get same markup. How could I get "generated" source, looking like (pseudo)
<div id='my-directive-content'>
<div id='object-1'>blah</div>
<div id='object-2'>blah</div>
</div>
in order to check if there are N rows visible to user?
someScopeObjects in scope exist and are valid.
And my next step is actually testing same thing for directives nested inside of 'my-directive', so I somehow have to get access to the scope of 'my-directive'. How? :)
Thank you.

Resources