Expand/Collapse child elements in a tree (AngularJS) - javascript

I'm a newbie in AngularJS and faced with an issue.
Need to create message history tree, which provides expand/collapse functionality on the parent item.
I've created view:
<div class="tree">
<ul>
<li ng-repeat="appt in apptsToFilter() | filter: groupByAppt" ng-click="showChilds()">
<span>{{appt.startTime}} - Appt. Id: {{appt.appointmentId}} </span>
<ul>
<li ng-repeat="item in appts | filter: {appointmentId: appt.appointmentId}" ng-show="active">
<span>{{item.message}}</span>
</li>
</ul>
</li>
</ul>
</div>
This is my controoler for this view:
function MessageHistoryController($scope, $routeParams, MessageHistoryResource) {
......//some code
$scope.active = false;
$scope.showChilds = function() {
if ($scope.active == false) {
$scope.active = true;
} else {
$scope.active = false;
}
};
}
This is what I get, when I've expanded first parent item:
ParentItem2:
- Child1
- Child2
- Child3
ParentItem2
- Child1
- Child2
ParentItem3
- Child1
When I click on any parent item - all of my subtrees expanded or collapsed.
But I expected this result, as below (only clicked item should be expanded):
ParentItem2:
- Child1
- Child2
- Child3
ParentItem2
ParentItem3
Any ideas are appreciated. Thanks.

That's because you have all of your parent, clickable items, set to one boolean. This can be resolved in the HTML without the active bool.
Set your show/hide element to:
ng-show="appt.active"
Then set your click call to:
ng-click="appt.active = !appt.active"
Full Example:
<div class="tree">
<ul>
<li ng-repeat="appt in apptsToFilter() | filter: groupByAppt" ng-click="appt.active = !appt.active">
<span>{{appt.startTime}} - Appt. Id: {{appt.appointmentId}} </span>
<ul>
<li ng-repeat="item in appts | filter: {appointmentId: appt.appointmentId}" ng-show="appt.active">
<span>{{item.message}}</span>
</li>
</ul>
</li>
</ul>
</div>
Even though appt.active would initialize as undefined when clicked it will change to true, at least it does on my end and this is how I handle these cases.
You could also loop through the appt and define active in the javascript.
For future reference you can simplify your $scope.showChilds function to:
$scope.showChilds = function () {
$scope.active = !$scope.active
}

Related

How to add an active class when the button is clicked and remove the active class from other buttons?

There are five buttons. When one of these buttons is clicked, the active class must be added and the others must be deleted. How can I do this with react? Buttons are not links.
enter image description here
<ul>
<li className="active">
All
</li>
<li>
Draft
</li>
<li>
Under assessment
</li>
<li>
Need data
</li>
<li>
Ready
</li>
</ul>
I see you are using className. That probably means you are using react. If you are, then please do not use jquery. JQuery and React do not like each other. JQuery manipulates the dom, whereas React schedules updates to its own virtual dom.
You could do something like this. Create two classes, active and inactive (or whatever you want to call them). Add a click event to it and have that click set the index. Then you can set it as active or not by the index.
const [activeIndex, setActiveIndex] = React.useState(0);
const handleOnClick = index => {
setActiveIndex(index);
};
const boxs = [0, 1, 2, 3];
const box = boxs.map((item, index) => {
return (
<li
key={index}
onClick={() => handleOnClick(index)} // pass the index
className={activeIndex === index ? "active" : "inactive"}
>
{item}
</button>

Listen for class change on nav

I have setup an event listener to determine whether a class attribute has changed, however this is only currently working on the first element of the menu. This needs to be triggered on each element with the specified class when it changes too.
const menu = document.querySelector('.elementskit-megamenu-panel')
const options = {
attributes: true
}
function callback(mutationList, observer) {
mutationList.forEach(function(mutation) {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
// handle class change
console.log(mutation.target.className);
}
})
}
const observer = new MutationObserver(callback)
observer.observe(menu, options)
markup
<ul>
<li>
<a>Item</a>
<div class="elementskit-megamenu-panel"></div>
</li>
<li>
<a>Item</a>
<div class="elementskit-megamenu-panel"></div>
</li>
<li>
<a>Item</a>
<div class="elementskit-megamenu-panel"></div>
</li>
</ul>

OnClick check, remove & add class name in angular13

I want to add the class name 'active' onClick to 'li a' & also remove any 'active' class present on the 'li a'. The current code is working properly if I click sequence from top elements, but when I click elements from bottom to top, it's not working.
component.html
<div class="container text-center">
<ul id="myList" class="pt-5">
<li class="p-3">
List 1
</li>
<li class="p-3">
List 2
</li>
</ul>
</div>
component.ts
linkActive(event) {
const activeClass = event.srcElement.classList.contains('active');
const classFound = document.querySelector('li a');
const hpn = classFound.classList.contains('active');
if (activeClass == true) {
if (hpn == true) {
classFound.classList.remove('active');
}
alert('true');
event.srcElement.classList.remove('active');
} else {
if (hpn == true) {
classFound.classList.remove('active');
}
alert('false');
event.srcElement.classList.add('active');
}
}
Please find the sample code : https://stackblitz.com/edit/angular-ivy-jf9xvp
Do not manipulate the DOM directly like this,
You can use ngClass to achieve the desired result:
template:
List1
.ts
public activeList: number;
...
public linkActive(listNumber: number) {
this.activeList = listNumber;
}
In general, as recommended in comments, do the heroes tutorial and try to understand how to use typescript.

vuex state splice keep removing the last item

I created a list on each list I've set up a remove method. Every-time I click the list in my jsfiddle I get what I want, but when I attach my project up with vuex it seems like the index is wrong. It just keeps removing the last item on my list no mater where i click. instead of the one i click.
<md-table>
<md-table-row v-for="(opt, index) in this.getAddedSegmentationList" :key="index">
<md-table-cell>
<ul >
<li>Name: API_NEEDS_TO_BE_UPDATED</li>
<li>Created: {{opt.created_time | newTime}}</li>
<li>Finished: {{opt.end_time | newTime}}</li>
</ul>
<ul class="channel-segements__tab-handlers">
<li class="channel-segements__tab-handlers-items" #click="removeSegement(index, opt)">
<md-icon>delete</md-icon>
</li>
</ul>
</md-table-cell>
</md-table-row>
</md-table>
methods: {
removeSegement(index, opt) {
this.getAddedSegmentationList.splice(index, 1)
}
},
computed: {
getAddedSegmentationList() {
return this.$store.state.channels.channelSegmentList
}
},
My original jsfiddle https://jsfiddle.net/ronoc4/eywraw8t/65812/ for testing to make sure it was possible.

Assigning a class based on a property value in angular2 typescript

I would like to assign a classes on html based on a property in angular2. That is am trying top open a dropdownlist without use of jquery and bootstrap
So i have
<li
class="dropdown mega-menu mega-menu-wide"
//stuck at adding class of open if propertyval is admin
>
<a #admin class="dropdown-toggle" (click)="toggle(admin)" >Administrative</a>
</li>
in my ts i have
export class ... {
propertyval :null
toggle(val){
this.propertyval = null;
}
}
So now i would like to assign class of open to the list if the value of propertyval is admin else it should be null
How do i go about this
You can use property binding to add the class dynamically.
<li
class="dropdown mega-menu mega-menu-wide"
[class.WhateverYouWant]="propertyval === 'admin'"
//stuck at adding class of open if propertyval is admin
>
<a #admin class="dropdown-toggle" (click)="toggle(admin)" >Administrative</a>
</li>
You can use NgClass directive:
<li [ngClass]="{'class-open': open}">
<a #admin class="dropdown-toggle" (click)="open = !open;" >Administrative</a>
</li>
class-open - is your class that affects dropdown list. open is your variable that you set initially to false or true in your component, so no need for toggle() method.
Hi you can use [ngClass] for adding dynamic styles.
<a #admin class="dropdown-toggle" (click)="toggle(admin)" [ngClass]="{'dynStyle': isAdmin }" >Administrative</a>
//style
.dynStyle{
color:green;
}
//.ts
toggle(val){
if(val!='admin')
{
this.propertyval = null;
return isAdmin=false
}
else
{
return isAdmin=true;
}
}
Create a getter on your class, returning boolean for the state of your property.
get propertyHasValue(): boolean {
return !isNullOrUndefined(this.propertyval);
}
Then add an ng-class directive to your element
<a [ng-class]="{ 'open': propertyHasValue }"/>

Categories

Resources