Uib accordion toggle issue - angularjs

I am using uibAccordion where the toggling is not happening properly,
If I click 1st repeated element all others also opening. Below is the code.
<ul>
<li ng-repeat="(key, value) in scenariosViewAll.collectionBookObject">
<div class="desc">
<uib-accordion close-others="true" class="">
<div uib-accordion-group id="{{$index+1}}" class="panel-default" is-open="status.open" is-disabled="true" prevent-click="false" ng-init="status.open = (key == scenariosViewAll.shared.currentSelectedAccordion) ? true : false" ng-class="{'opened': status.open}" ng-if="value.length > 0">
<uib-accordion-heading>
<span class="accordion-toggle-wrapper">
<span class="accordion-title">
{{key}}
</span>
<span class="pull-right acc-icon-set">
<span class="collection-indicator">{{value.length}}</span>
<span class="arrow-toggle">
<button class="btn btn-icon" aria-hidden="true" ng-click="status.open = !status.open;">
<i class="icon" ng-class="{'icon-chevron-up': status.open, 'icon-chevron-down': !status.open}"></i>
</button>
</span>
</span>
</span>
</uib-accordion-heading>
</div>
</uib-accordion>
</div>
</li>
</ul>
I have tried passing id as {{index+1}} and also close-others="true".
But it's not working

Here
ng-init="status.open = (key == scenariosViewAll.shared.currentSelectedAccordion) ? true : false"
I really don't know what you are binding status.open to, but clearly this is wrong and really ambiguous
Simplify it, and give is-open a property that refers to a different value for each iterated key/value, for example
ng-init="value.ui.isOpen = false;"
is-open="value.ui.isOpen"
If you are raelly lazy, and don't need to access these variables inside your controller, just don't bind it to anything
ng-init="isOpen = false;" // by now this is redundant and can be removed
is-open="isOpen"
this will work because ngRepeat created a new scope for every iteration it goes, so a new isOpen will be created per such scope.

I got solution by passing index:
<div uib-accordion-group class="panel-default" ng-init="status.open = false;" is-open="status.open[$index]" prevent-click="false" ng-class="{'opened': status.open}" ng-if="value.length > 0">

Related

Adding a HTML tag to an ng-repeat block

I am trying to add a block of HTML to a ng-repeat block. the idea is to build up a breadcrumb trail, with a chevron between each item.
<div class="pull-left breadcrumbs">
<span ng-repeat="crumb in breadcrumbs">
{{crumb.display}} {{$last ? '' : '<span class=\'fa fa-chevron-right\'></span>'}}
</span>
</div>
However, this does not render as expected.
I have also tried changing the single quotes for double quotes in the class= part of the HTML.
you can do it with the ng-hide directive.
This directive hides an element, if the expression evaluates to true.
<div class="pull-left breadcrumbs">
<span ng-repeat="crumb in breadcrumbs">
{{crumb.display}}
<span class="fa fa-chevron-right" ng-hide="$last"></span>
</span>
</div>
or you could use the ng-if directive.
<div class="pull-left breadcrumbs">
<span ng-repeat="crumb in breadcrumbs">
{{crumb.display}}
<span class="fa fa-chevron-right" ng-if="!$last"></span>
</span>
</div>
One solution would be to utilize the angularjs feature, track by $index.
$scope.maxlength = $scope.breadcrumbs.length-1;
And utilize the ng-show tag, to display the span only if it is not the last item in the repeater.
<div ng-controller="MyController">
<span ng-repeat="crumb in breadcrumbs track by $index">
{{crumb.name}} <span ng-show="$index < maxlength" class="fa fa-chevron-right">></span>
</span>
</div>

$index restart each row in ng-repeat

I want to repeat this code for each element in my array:
<div class="container" ng-init="parentIndex = $index" ng-repeat="urn in apsocket.mensajes | filter:searchTextURN">
<button style="width:100%" type="button" class="btn btn-info" data-toggle="collapse" data-target="{{'#urn_'+$index}}">{{urn.urn }}</button>
<div id="{{'urn_'+$index}}" class="collapse">
{{urn.timestamp}}
<br>
<p>
<div align="right" ng-repeat="meas in urn.measurements track by $index">
<button style="width:90%;background-color: #68ec6a;border-color:#8bf48c;" type="button" class="btn btn-success" data-toggle="collapse" data-target="{{'#meas_'+parentIndex + '_' +$index}}">{{meas.phenomenon}} </button>
<div style="width:90%" id="{{'meas_'+parentIndex + '_' +$index}}" class="collapse">
{{meas.value + ' ' + meas.uom}}
</div>
</div>
</p>
</div>
</div>
But, while first button in each row works fine and creates a working collapsible, the inner ng-repeats seem not.
Each inner element in each outter row, have the same id. So, for each "container", parentIndex is the same and starts in 0.
What should I do in this case? This is not a fixed array which I load at the beggining. This array recevies data from socket and it get bigger each time a message is received.
If you need any more code or so, just ask.
I would recommend just using the pure angular way. In a repeat, each item has it's own scope so you can do an ng-click="collapse = ! collapse" (something like that), I made you an example here
http://jsfiddle.net/X8era/82/
I just made a fake data structure for examples sake
<ul>
<li ng-repeat="item in objs" ng-click="collapse = ! collapse">
{{item.id}}
<ul ng-show="item.more.length > 0 && collapse">
<li ng-repeat="child in item.more" ng-click="collapse = ! collapse; $event.stopPropagation();" >
{{child.id}}
<ul ng-show="child.more.length > 0 && collapse">
<li ng-repeat="baby in child.more">
{{baby.id}}
</li>
</ul>
</li>
</ul>
</li>
</ul>
If you would like to use the collapse class for an animation or whatever, you can change the part of the ng-show that is collapse to
ng-class="{ 'collapse' : collapse }"
The first 'collapse' being whatever class you want to be toggled.
You don't have to use ng-init="parentIndex = $index". You can access to parent $index like this $parent.$index.
Each ng-repeat creates new scope, that's why you can access to parent by using $parent keyword.
Demo:
var app = angular.module('app',[]);
app.controller('ctrl', function($scope) {
$scope.items = [0, 1, 2, 3, 4];
});
<div ng-app="app" ng-controller="ctrl">
<ul>
<li ng-repeat="item in items track by $index">
<ul>
<li ng-repeat="item in items track by $index">
parent: {{$parent.$index}}
current: {{$index}}
</li>
</ul>
</li>
</ul>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

Clickable link in draggable node in angular-ui-tree

In angular-ui-tree I'm looking for a way to have links inside a draggable node.
What's happening now is that when I click on the link inside the node it starts "holding" the whole node to drag it.
I saw this answer Angular JS (angular-ui-tree) ng-click conflict vs drag start event, however it is not similar to what I want to do. In this answer ng-click is bound to the node, where in my case I have multiple links inside the node.
Below is my html:
<div ui-tree="treeOptions" drag-delay="1000" id="tree-root">
<ol ui-tree-nodes ng-model="filteredModules" data-nodrop>
<li ng-repeat="module in filteredModules" ui-tree-node>
<div ui-tree-handle ng-click="toggle(this)">
<a class="btn btn-xs"><span class="glyphicon" ng-class="{'glyphicon-chevron-right': collapsed, 'glyphicon-chevron-down': !collapsed}"></span></a>
{{module.name}}
</div>
<ol ui-tree-nodes ng-model="module.stages" data-nodrop ng-class="{hidden: collapsed}">
<li ng-repeat="stage in module.stages" ui-tree-node>
<div ui-tree-handle ng-click="toggle(this)">
<a class="btn btn-xs"><span class="glyphicon" ng-class="{'glyphicon-chevron-right': collapsed, 'glyphicon-chevron-down': !collapsed}"></span></a>
{{stage.name}}
</div>
<div ui-tree-nodes ng-model="stage.cases" ng-class="{hidden: collapsed}">
<div ng-repeat="case in stage.cases" ui-tree-node>
<div ui-tree-handle>
<!-- HERE I HAVE TWO LINKS -->
{{case.name}}
<span class="glyphicon glyphicon-edit"></span> Edit
</div>
</div>
</div>
</li>
</ol>
</li>
</ol>
</div>
Is there a way to have multiple links inside a draggable node?
Thanks in advance
Add the no-drag attribute to the links like this:
<a data-nodrag href="/#/admin/cases/{{case._id}}">{{case.name}}</a>
<a data-nodrag href="/#/admin/cases/edit/{{case._id}}" class="pull-right btn btn-primary btn-xs"><span class="glyphicon glyphicon-edit"></span> Edit</a>
I had the same issue. This is how I fixed it:
Add the a element in line number 602 of angular-ui-tree.js
eventElmTagName = eventElm.prop('tagName').toLowerCase();
if (eventElmTagName == 'input' ||
eventElmTagName == 'textarea' ||
eventElmTagName == 'button' ||
eventElmTagName == 'i' ||
eventElmTagName == 'a' || //this would ignore 'a' elements while dragging
eventElmTagName == 'select') {
return;
}
Just an FYI - you are using glyphicons in the span element. So you might face the same problem if you click on the glyphicon. Add span element in the above statement to fix that as well.

how to select a li which is nested within another ng-repeat in angular js

(please do not update the english grammer in this question/ I wont be able to approve it and this question wont get resolved.)
This is my UI
It contains various li elements whose values are populated using this angular html
<div class="row">
<li class="no-bullet-li li-12 monaco-font"> {{selectedChangeEligibilityPlan}}</li>
<ul class="ul-plan-1">
<li class="no-bullet-li" ng-repeat="plan in fewThings">
<div ng-class="{ 'selected-class-name': $index == selectedIndex }" ng-click="itemClicked($index)" class="li-alt monaco-font"> p2|{{plan.planName}} | {{plan.planId}}
<a class="iconing-sub" ng-click="addClick(item)" href=""><i class="glyphicon glyphicon-plus"></i></a>
<a ng-click="deleteClick(item)" ng-class="{ active : active.one }" href=""><i class="glyphicon glyphicon-remove iconing_1-sub"></i></a>
</div>
<ul class="ul-plan">
<li class="no-bullet-li li-8 monaco" ng-repeat="item in plan.planIds">
p1| {{ plan.planNames[$index]}} | {{item}}
<a <a ng-click="editClick(item)" href=""><i class="glyphicon glyphicon-pencil iconing"></i></a>
<a ng-click="deleteClick(item)" href=""><i class="glyphicon glyphicon-remove iconing_1"></i></a>
</li>
</ul>
</li>
</ul>
</div>
It uses the nested ng-repeat.
The whole UI is contained within a one controller ( no directives used)
the following code gets triggered when someone clicks the blue lis.
$scope.itemClicked = function ($index) {
console.log($index);
// console.log($(item).closest('li') );
$scope.selectedIndex = $index;
};
here's how to ui looks and its great.
problem arises when I try to do the same logic for the pink ones (nested ng-repeat li). It selects other pink lis in all the other stack too.
here's the screenshot.
second part of question:
I have I have the above UI plus I also have this second UI that is loaded along with this on the same page. It contains a bunch of horizontal rows.
Once the user click the blue pink colored lis it goes into the active state. Then the user can click the row which he likes. upon clicking it the plan name of currently selected li will get replaced.
Here is the html for it.
<div class="row">
<li class="no-bullet-li li-12 monaco-font"> {{selectedChangeEligibilityPlan}}</li>
<ul class="ul-plan-1">
<li class="no-bullet-li" ng-repeat="plan in fewThings">
<div class="li-alt monaco-font"> p2|{{plan.planName}} | {{plan.planId}}
<a class="iconing-sub" ng-click="addClick(item)" href=""><i class="glyphicon glyphicon-plus"></i></a>
<a ng-click="deleteClick(item)" ng-class="{ active : active.one }" href=""><i class="glyphicon glyphicon-remove iconing_1-sub"></i></a>
</div>
<ul class="ul-plan">
<li ng-class="{ 'selected-class-name': $index == selectedIndex }" ng-click="itemClicked($index)" class="no-bullet-li li-8 monaco" ng-repeat="item in plan.planIds">
p1| {{ plan.planNames[$index]}} | {{item}}
<a ng-click="editClick(item)" href=""><i class="glyphicon glyphicon-pencil iconing"></i></a>
<a ng-click="deleteClick(item)" href=""><i class="glyphicon glyphicon-remove iconing_1"></i></a>
</li>
</ul>
</li>
</ul>
</div>
The problem lies in the fact that you are trying to save the state of the data (which one is selected) inside your controller using $index. The $index property isn't unique among different ng-repeats, so when you set your $scope.selectedIndex to $index, each of your sub lists will see that their $index matches, and so will each trigger the ng-class and add the selected-class-name class.
What you could do instead is have each item in the data have a unique index and use that id to store which item is selected in $scope.selectedIndex.
<ul class="ul-plan">
<li ng-class="{ 'selected-class-name': item.id == selectedIndex }" ng-click="itemClicked(item.id)" class="no-bullet-li li-8 monaco" ng-repeat="item in plan.planIds">
p1| {{ plan.planNames[$index]}} | {{item}}
<a ng-click="editClick(item)" href=""><i class="glyphicon glyphicon-pencil iconing"></i></a>
<a ng-click="deleteClick(item)" href=""><i class="glyphicon glyphicon-remove iconing_1"></i></a>
</li>
</ul>
This line looks strange.
<a ng-click="select('one')" href="">
Did you really mean to pass a hardcoded 'one' to the function? Or was it supposed to be the index, like the deleteClick() call.

How to check whether the value of my scope data is changed or not in angularjs?

I have created a html for customized dropdown.path of below html is "partials/institutions/coordinatorDropdown.html"
<div class="dropdown" ng-click="toggleDropDown">
<button class="form-control overflow" type="button" id="dropdownMenu-list" data-toggle="dropdown" name="datatype" id="datatype" ng-required="true" ng-class="{ 'selected-class-name': $index == selectedIndex }" ng-model="coordinator.role" ng-bind="coordinator.role" required>
</button>
<ul class="dropdown-menu dropdown-menu-list" role="menu" aria-labelledby="dropdownMenu-list" ng-init="toggleDropDown = true" ng-show="toggleDropDown" >
<li role="presentation" ng-repeat="item in role" value="{{ item.roleid }}" ng-click="changeCoordinatorType(item.value, $index)">
<span ng-class="{ 'dropdown-selected-item': $index == selectedIndex }">{{ item.coordinator_type }}</span>
</li>
</ul>
</div>
In my original html i am using this like below:
<div class="col-md-6">
<div class="error-message">
<span ng-show="addCoordinatorForm.coordinatorType.$error.required && !addCoordinatorForm.coordinatorType.$pristine"
class="errormessage" ng-bind="'Please select a coordinator type.'"></span>
</div>
<div name="coordinatorType" ng-include="'partials/institutions/coordinatorDropdown.html'"></div>
</div>
Now in my controller,
I need to check whether the $scope.coordinator.role value is changed or not.
In my controller when i give
if ($scope.addCoordinatorForm.$dirty){
}
It is checking the other controls but not the dropdown value changed or not.
Can anyone suggest a solution for me please?.

Resources