Clickable link in draggable node in angular-ui-tree - angularjs

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.

Related

Uib accordion toggle issue

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

Positioning ui-angular carousel controls

I am creating a carousel that displays images with some meta data. On md and lg screens I want the meta data to appear to the right, and on smaller screens I want it below the image, which is working fine using col-md-8 / col-md-4
Here is my carousel code:
<uib-carousel active="active" interval="0" no-wrap="noWrapSlides" template-url="/Scripts/MainClient/views/cwCarouselTemplate.html" style="height:100%">
<div uib-slide ng-repeat="slide in slides track by slide.id" index="slide.id">
<div class="row">
<div class="col-md-8 " ng-style="{height: hackheight}" id="img-div">
<div style="padding:10px; height:100%;" class="black-bkgd">
<span class="helper"></span><img class="img-responsive " ng-src="{{slide.image}}" style="vertical-align:middle; display:inline-block">
</div>
</div>
<div class="col-md-4">
Here's where the meta data goes go!
<h4>Slide {{slide.id}}</h4>
<p>{{slide.text}}</p>
</div>
</div>
</div>
</uib-carousel>
The problem I have is regarding the right hand control - it is positioned to the right of the whole carousel, and I want it right relative to the col-md-8 div (so it appears over the right hand side of the image, not over the meta data). It works if I set right to be 34% on the control, but this then doesn't work on xs/sm screens (the control is in the middle of the image).
I can get it to the right position on either xs/sm screens (with right:0) OR on md/lg screens (with right:34%) but not on all screens at the same time!
One idea I had is to add a <span class="hidden-xs hidden-sm" style="width:34%"></span> to the right to push the control over on larger screens but I can't get it to work - the span just stacks with the carousel control.
Here's the template I'm using:
<div class="carousel">
<div class="carousel-inner" ng-transclude></div>
<a role="button" href class="left carousel-control" ng-click="prev()" ng-class="{ disabled: isPrevDisabled() }" ng-show="slides.length > 1">
<span aria-hidden="true" class="glyphicon glyphicon-chevron-left"></span>
<span class="sr-only">previous</span>
</a>
<a role="button" href class="right carousel-control" ng-click="next()" ng-class="{ disabled: isNextDisabled() }" ng-show="slides.length > 1">
<span aria-hidden="true" class="glyphicon glyphicon-chevron-right"></span>
<span class="sr-only">next</span>
</a>
<!--
<ol class="carousel-indicators" ng-show="slides.length > 1">
<li ng-repeat="slide in slides | orderBy:indexOfSlide track by $index" ng-class="{ active: isActive(slide) }" ng-click="select(slide)">
<span class="sr-only">slide {{ $index + 1 }} of {{ slides.length }}<span ng-if="isActive(slide)">, currently active</span></span>
</li>
</ol>
-->
</div>
Many thanks for any help
You could wrap your buttons in a absolute positioned col-md-8 to achieve the result.
If the element height remains an issue, you could provide a plunkr of your code, so we can look into that.

How to use ng-click in Angular ui-tree for drag and drop as well as performing some function

My Angular code
<div ui-tree="rootTree" data-drag-enabled="false">
<ol ui-tree-nodes="" ng-model="course.sections" ng-class="{hidden: collapsed}">
<li ng-repeat="section in course.sections" ui-tree-node> <div ui-tree-handle class="tree-node tree-node-content" ng-click="editSection(section)" >
<a class="btn btn-success btn-xs"ng-if="section.sectionInstances && section.sectionInstances.length > 0" data-nodrag ng-click="toggle(this)">
<span class="glyphicon glyphicon-chevron-down" ng-class="{'glyphicon-chevron-right': collapsed,'glyphicon-chevron-down': !collapsed }">
</span>
</a>
{{section.sec_name}}
<a class="pull-right btn btn-danger btn-xs" data-nodrag ng-click="removeSection(section)">
<span class="glyphicon glyphicon-remove">
</span>
</a>
<a class="pull-right btn btn-primary btn-xs" data-nodrag ng-click="addSectionInstance(section)" style="margin-right: 8px;">
<span class="glyphicon glyphicon-plus">
</span>
</a>
</div>
</li>
</ol>
</div>
If i use data-drag-enabled="false", then ng-click function is calling. I want both the function drag and drop as well as ng-clik function.
If you are just wanting to perform functionality on 'dragStart', then it appears according to the angular-ui-tree documentation, that you can define treeOptions in your controller and assign them to your tree directive attribute value.
myAppModule.controller('MyController', function($scope) {
$scope.treeOptions = {
dragStart: function(sourceNodeScope, destNodesScope, destIndex) {
// Do things here
},
dragEnd: function(sourceNodeScope, destNodesScope, destIndex) {
}
};
});
<div ui-tree="treeOptions">
<ol ui-tree-nodes ng-model="nodes">
<li ng-repeat="node in nodes" ui-tree-node>{{node.title}}</li>
</ol>
</div>
same trouble here, few years after.
Sean answer doesn't seem to answer the question.
issue:
* with drag n drop enable: I can't use ng-click to remove/edit a node, but I can drag n drop it.
* w/o drag n drop enable: my ng-click works.
Solution:
move the "ui-tree-handle" from the global div to specific location w/o any ng-click in.

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.

Toggling accordion panel icons with ng-class and ng-click

I have an accordion with "chevron" icons that are toggled to point up or down when clicked, this is done with ng-click and ng-class. The accordion only permits one panel to be open at the same time - so when I click on a panel that is closed, the panel that is open closes. But how do I toggle the chevron icon on the open panel that is getting closed with ng-click?
Originally i could do it with DOM manipulation etc, but since this is a partial view in angular I cannot do it.
Code:
<div class="panel-group" id="accordion">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" ng-click="firstpaneisopen=!firstpaneisopen">
<i class="glyphicon" ng-class="{'glyphicon-chevron-up': firstpaneisopen, 'glyphicon-chevron-down': !firstpaneisopen}"></i> Collapsible Group Item #1
</a>
</h4>
</div>
<div id="collapseOne" class="panel-collapse collapse in">
<div class="panel-body">
Body
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" ng-click="secondpaneisopen=!secondpaneisopen>
<i class="glyphicon" ng-class="{'glyphicon-chevron-up': secondpaneisopen, 'glyphicon-chevron-down': !secondpaneisopen}"></i> Collapsible Group Item #2
</a>
</h4>
</div>
<div id="collapseTwo" class="panel-collapse collapse">
<div class="panel-body">
Body
</div>
</div>
</div>
</div>
This is what I've tried and it seems to work
In my controller I have
$scope.menuStatus = [ { isOpen : true },
{ isOpen : false },
{ isOpen : false } ]
In my html I have
<accordion id='cntLeftMenu' close-others='false'>
<accordion-group is-open='menuStatus[0].isOpen'>
<accordion-heading class='menu-title'>
Cars <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': menuStatus[0].isOpen , 'glyphicon-chevron-right': !menuStatus[0].isOpen }"></i>
</accordion-heading>
<ul class='left-menu'>
<li><a href=''>test1</a></li>
<li><a href=''>test1</a></li>
<li><a href=''>test1</a></li>
</ul>
</accordion-group>
<accordion-group is-open='menuStatus[1].isOpen'>
<accordion-heading class='menu-title'>
Customers <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': menuStatus[1].isOpen , 'glyphicon-chevron-right': !menuStatus[1].isOpen }"></i>
</accordion-heading>
<ul class='left-menu'>
<li><a href=''>test1</a></li>
<li><a href=''>test1</a></li>
<li><a href=''>test1</a></li>
</ul>
</accordion-group>
<accordion-group is-open='menuStatus[2].isOpen'>
<accordion-heading class='menu-title'>
Staff <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': menuStatus[2].isOpen , 'glyphicon-chevron-right': !menuStatus[2].isOpen }"></i>
</accordion-heading>
<ul class='left-menu'>
<li><a href=''>test1</a></li>
<li><a href=''>test1</a></li>
<li><a href=''>test1</a></li>
</ul>
</accordion-group>
<accordion>
How about working with CSS? Bootstrap adds a class collapsed on the html element that has the data-toggle="collapse". When the slide opens, it removes this collapsed class. We can then work with css to, for example, rotate the span element (a child of the element that has the data-toggle attribute).
<style>
button.collapsed span {
transform: rotate(-90deg);
}
</style>
<button type="button" class="btn btn-info collapsed" data-toggle="collapse" data-target="#demo">
Simple collapsible
<span class="glyphicon glyphicon-chevron-down"></span>
</button>
<div id="demo" class="collapse">
Lorem ipsum dolor...
</div>
IMPORTANT NOTE : Ensure collapsed class is added to the element that has the data-toggle="collapse" attribute for this to work smoothly. Otherwise, on initial loading of the element, the span element doesn't rotate as expected the first time.
I would recommend that you check out 'UI Bootstrap' from the AngularUI team. It's a collection of "Bootstrap components written in pure AngularJS".
http://angular-ui.github.io/bootstrap/
Their website features an example which shows their Accordion directive using ng-class to toggle the chevron icons.
http://angular-ui.github.io/bootstrap/#/accordion
Their directive also features a close-others attribute which, if true, will ensure only a single panel is open at any one time.
<accordion close-others="true">
The easiest solution I have ever think. And not to use any controller,
<div
class="fa fa-fw list-arrow"
ng-class="{'fa-angle-down': isClicked, 'fa-angle-right' : !isClicked}"
ng-click="isClicked = !isClicked">
</div>
You can write similar like me.
Did some researching, I was able to use this method to add the class open to the panel-header when it's toggled open. This is example allows multiple panels to be open and uses Angular Strap Collapse.
Template:
<div class="panel-group"
role="tablist"
data-ng-model="multiplePanels.activePanels"
data-allow-multiple="true"
data-bs-collapse>
<div class="panel panel-default" ng-repeat="location in locations">
<div class="panel-heading"
role="tab"
data-ng-class="{'open' : multiplePanels.activePanels.indexOf($index) > -1}"
bs-collapse-toggle>
<h3>Some Header Stuff</h3>
</div>
<div class="panel-collapse" role="tabpanel" bs-collapse-target>
<div class="panel-body">
<p>Stuff in the panel body...</p>
</div>
</div>
</div>
</div>
JS in the controller:
$scope.multiplePanels.activePanels = [];
You can use bootstrap (tested in 4+) collapse and the following styles to toggle the button;
<style>
[id^='particon'] {
display: block !important;
}
[id^='particon']:after {
font-family: 'Glyphicons Halflings';
color: grey;
}
[id^='particon'].collapse:after {
content: "\e081";
}
[id^='particon'].collapse.show:after {
content: "\e082";
}
/*optional*/
[id^='particon'].collapsing {
transition: none;
}
</style>
For fully working snipplet;
https://js.do/code/changecollapseicon
After some research i've got one way to solve this.
JS:
$scope.firstpaneisopen = false;
$scope.secondpaneisopen = false;
Modified ng-click on the first pane:
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" ng-click="firstpaneisopen=!firstpaneisopen; secondpaneisopen=false">
vice versa on the second pane.
I don't think this is any elegant solution, especially if we got more than two panes, but it works.

Resources