How to toggle classes in AngularJS using ng-class across various elements

I found a solution on this S.O. question to toggle a class using ng-click in AngularJS. Specifically, I am trying to show a Font Awesome closed folder icon when a list element is not clicked and an open folder icon when the list element is clicked within a nested menu structure. The toggling of icons works correctly when opening and closing submenus by clicking. However, after clicking on other list elements, their icons change as expected while the original opened folder icon remains visible for items that have been closed.

To resolve this issue, I want to toggle the class for all other list elements displaying the open folder icon back to the closed folder icon when one item is clicked. How can I achieve this functionality? Refer to the provided screenshot illustrating the problem:

You can see the code snippet I'm using to toggle the class below:

<a ng-click="folderOpen = !folderOpen" href="#">
  <i ng-class="folderOpen ? 'fa fa-folder-open-o' : 'fa fa-folder-o'"></i>
  <{ item.pretty_name }>
</a>

I need a way to toggle the classes from 'fa fa-folder-open-o' to 'fa fa-folder-o' for all list elements whenever any anchor element is clicked. How should I approach implementing this?

For more context, here is the surrounding code snippet that generates the list elements within the menus:

  <li ng-repeat="item in data.dirs" metis="">
    <a ng-click="folderOpen = !folderOpen" href="#">
      <i ng-class="folderOpen ? 'fa fa-folder-open-o' : 'fa fa-folder-o'"></i>
      <{ item.pretty_name }>
    </a>
    <ul class="nav nav-second-level metismenu">
      <li ng-repeat="item2 in item.files" metis="">
        <a href="#">
          <i class="fa fa-file"></i>
          <{ item2.pretty_name }>
        </a> 
      </li> 
    </ul>
  </li>

Answer №1

For every node in your structure, you can create a custom field like 'isExpanded'. Then, on ng-click of the element, you can toggle the value of this field for the current node. Here's an example implementation:

controller:

// Inside init function
initDirs($scope.data.dirs)
....
function initDirs (dirs) {
    angular.forEach(dirs, function(dir) {
        dir.isExpanded = false;
        if (dir.children.length) {
            initDirs(dir.children)
        }
    })
};

template:

<li ng-repeat="item in data.dirs" metis="">
    <a ng-click="item.isExpanded= !item.isExpanded" href="#">
        <i ng-class="item.isExpanded ? 'fa fa-folder-open-o' : 'fa fa-folder-o'"></i>
        <span>{{ item.name }} </span>
    </a>
    <ul ng-show="item.isExpanded">
        <!-- Child nodes here -->
    </ul
</li>

If you are not familiar with folder tree properties like depth, it is advisable to create 2 directives: [tree] (for the entire tree) and [tree-node] for each individual node. Using these directives will allow you to build trees of varying structures.

Answer №2

Deciphering the code you've provided is a bit challenging, but one potential issue could be how ng-click is being used. ng-click is intended to execute methods, not define complex logic within the HTML body. Angular might be having difficulty understanding the logic within ng-click. It would be advisable to move your logic into the scope.

$scope.changeFolder = function(){
    $scope.folderOpen = !$scope.folderOpen;
}

Subsequently, update your HTML accordingly:

<a ng-click="changeFolder()" href="#">
  <i ng-class="folderOpen ? 'fa fa-folder-open-o' : 'fa fa-folder-o'"></i>
  <{ item.pretty_name }>
</a>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Show a Google map when hovering over a link or text

I have been trying to implement a Google map display over text by following a tutorial. However, I've encountered an issue where the map is appearing in the wrong location – at the bottom of the page instead of where it should be. Upon inspecting th ...

Is it possible to dynamically add attributes to XHTML tags using Javascript? For instance, adding a title attribute to an anchor tag like <a title="text">

Is it possible to modify XHTML source code through JavaScript? Can attributes be added to any XHTML tag dynamically, such as adding a title attribute to an anchor tag (<a title="text">)? ...

Configuring JsFiddle with Vue and integrating vue-tables-2 - The variable "t" is not defined

Seeking assistance for implementing the vue-tables-2 package and encountering a persistent issue. Despite my efforts to set up a jsfiddle, I keep encountering an error stating "t is undefined" even with a simple implementation. Has anyone faced this specif ...

Issues with Express js routes in MEAN stack causing unexpected behavior

I've recently started working with express/mongoose and I'm having trouble understanding why my routes are not functioning correctly in the MEAN stack. On my application, I have a general offer route '/offers' and then specific offer r ...

Tips for Removing AngularJS File from Source Code

Every time I launch my project, it displays all of my angular.JS files in the Source Code. Is there a way to exclude the js files from being shown? ...

In the Sandbox, element.firstChild functions properly, but it does not work in the IDE

Encountered an issue that has me puzzled. To give you some context, I attempted to create a native draggable slider using React and positioned it in the center of the screen, specifically within my Codesandbox file. The code snippet I utilized is as follow ...

Handling synchronous reception with Socket.io

Dealing with socket.io has been quite frustrating lately. I've spent about an hour trying to tackle this issue, but there isn't much helpful information available online. Due to JavaScript's synchronous nature, finding relevant details on th ...

Verifying if checkboxes are selected in PHP using JavaScript

echo '<div class="col-lg-10 col-lg-offset-1 panel">' . "<table id='data' class='table'> <tr> <th></th> <th>Document No</th> <th>AWB NO</th> ...

What is the best way to reset an a-select component in Ant Design Vue?

I need to programmatically reset the selection in my a-select component after a specific event is triggered. Here's an example of my a-select code snippet: <a-select style="marginTop: 8px;width: 20%" @change="onChanged" > ...

What might be causing req.body to be an empty object?

I'm currently diving into the world of XMLHttpRequests. My goal is to send some input data to the server, but when it reaches its destination, the Object appears empty as if it were {}. I've noticed that by commenting out the setRequestHeader sec ...

Is there a way to effectively remove the data stored in a BufferAttribute on the GPU using threejs?

When working with BufferAttributes in threejs, I encountered a scenario where I needed to delete a specific attribute without affecting others. The initial setup looked something like this: geometry.setAttribute("xxx", new THREE.BufferAttribute(new Float3 ...

What is the best way to allow users to click a Grid component in order to toggle the state of a

I have a Grid component that is part of a row within the grid container, along with other rows. This particular row consists of a description and a checkbox. How can I set it up so that clicking anywhere on the row will toggle the checkbox on and off? &l ...

Is it possible to replicate a stale closure similar to React's useEffect hook without the use of the useEffect hook?

I have a good understanding of closures, but I am struggling to grasp how a stale closure can be created in React's useEffect without providing an exhaustive dependencies array. In order to explore this concept further, I am attempting to replicate a ...

Position text next to an element using jQuery

<h:inputText id="usernameInput" value="#{userBean.un}" styleClass="form-control" required="true" onfocus="popupMessage(this, 'username');"> <f:validateRegex pattern="([a-zA-Z_0-9]+)">< ...

Press the delete button to remove both the box and text dynamically with JavaScript

My task involves managing a shopping list with delete buttons next to each item. I am trying to use JavaScript to remove both the button and the corresponding text when the button is clicked. So far, my attempts have been unsuccessful. I used document.getE ...

Tips for sending personalized notifications through Web push technology

I've successfully implemented web push on Chrome, but I'm facing an issue where all users receive the same notification from the server. Is there a way to include user-specific data or endpoint ID in the latest notification request sent by the se ...

Passing refs in React can be achieved by using sibling components. By passing a

Here is my parent component: import React from 'react' import logo from '../Assets/LOGO.png' import EmailInput from '../Components/LoginPage/EmailInput' import PasswordInput from '../Components/LoginPage/PasswordInput&apo ...

Trouble with toggling div visibility using jQuery and AJAX

I'm trying to display a specific div based on the result of an SQL query. The problem I'm facing is that I can't seem to toggle the divs asynchronously. Currently, the page needs to be reloaded for the div to reflect the changes. <?ph ...

Forbidden access error in codeigniter with Ajax request 403

I'm struggling to send a value via Ajax to a Controller file in Codeigniter, but unfortunately I haven't been successful. Despite researching this issue and finding that it has been asked many times before, I still can't seem to find a solut ...

I possess a solitary div element that requires dynamic replication

I have a single container and an unspecified number of rows of data. I want to display this data on HTML cards that are generated dynamically based on the number of rows. For example, if there are 10 rows of data, I need to create 10 card elements with ea ...