Increasing the concealment of items

My query is about creating an expandable tree structure while iterating through an array in AngularJS. I managed to make it work, but the issue is that all nodes expand and collapse together.

Here's my HTML:

[...]
<div ng-repeat="item in items">
    <div class="item-title" ng-click="setState()">{{ item.title }}</div>
    <div class="item-container" show-me="isShown">
         {{ item.content }}
    </div>
</div>

And here is my JavaScript code:

[...]
// In the controller:

$scope.isshown = false;
$scope.setState = function() {
    $scope.isshown = !$scope.isshown;
};
[...]

.directive("showMe", function($animate) {
    return function (scope, element, attrs) {
        scope.$watch(attrs.showMe, function(newVal) {
            if(newVal) {
                $animate.addClass(element, 'show');             
            } else {
                $animate.removeClass(element,'show');
            }
        });
    };
});

Currently, this setup opens every item at once. I have been searching for a solution for 3 days now, and I am trying to avoid complex jQuery manipulations. Any suggestions?

Answer №1

If you want to enhance your directive, consider implementing an isolate scope:

.directive("displayToggle", function($animate) {
    return {
        scope: {},
        link: function (scope, element, attrs) {
            scope.isDisplayed = false;
            scope.$watch('isDisplayed', function(newVal) {
                if(newVal) {
                    $animate.addClass(element, 'display');             
                } else {
                    $animate.removeClass(element,'display');
                }
            });
        }
    };
});

-- Solution to address query in the comments section --

To interact with the isolate scope externally, utilize the angular element. Retrieve the node using JavaScript methods like document.getElementById, document.getElementsByClassName or document.querySelector. Once you have the desired element, proceed as follows.

var node = document.getElementById('MyElement');
var el = angular.element(node);
var scope = el.scope();
scope.isDisplayed = false;

Alternatively, you can establish a listener within your directive to manage its value dynamically like so:

.directive("displayToggle", function($animate) {
    return {
        scope: {},
        link: function (scope, element, attrs) {
            scope.isDisplayed = false;

            element.bind('click', function(e) {
                e.preventDefault();
                scope.$apply(function() {
                    scope.isDisplayed = !scope.isDisplayed;
                });
            });

            scope.$watch('isDisplayed', function(newVal) {
                if(newVal) {
                    $animate.addClass(element, 'display');             
                } else {
                    $animate.removeClass(element,'display');
                }
            });
        }
    };
});

Answer №2

The directive's scope is shared among all instances, meaning every showMe directive will check the same isshown variable. To address this issue, you can update your code as follows:

<div ng-repeat="item in items">
    <div class="item-title" ng-click="setState(item)">{{ item.title }}</div>
    <div class="item-container" show-me="isShown(item)">
         {{ item.content }}
    </div>
</div>

Then, in your controller:

$scope.setState = function(item) {
    item.isshown = !item.isshown;
};
$scope.isShown = function(item) {
    return item.isshown;
};

In this approach, each item serves as both data source and a state holder for its "openness". The directive will trigger the isShown function in your controller to retrieve the item's state. Alternatively, you could maintain an array elsewhere to track shown items (removing them when hidden), with isShown checking if the item is in the array.

Answer №3

To achieve this functionality, simply utilize the following structure:

<div ng-repeat="item in items">
    <div class="item-title" ng-click="item.isShown = !item.isShown">{{ item.title }}</div>
    <div class="item-container" ng-show="item.isShown">
         {{ item.content }}
    </div>
</div>

No additional javaScript code is necessary.

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

Ways to retrieve row and column data from a datagrid

Below is the code snippet I am currently working with: import React from 'react' import Button from '@material-ui/core/Button'; import Checkbox from '@material-ui/core/Checkbox'; import { DataGrid } from '@material-ui/da ...

Testing Vue with Jest - Unable to test the window.scrollTo function

Is there a way to improve test coverage for a simple scroll to element function using getBoundingClientRect and window.scrollTo? Currently, the Jest tests only provide 100% branch coverage, with all other areas at 0. Function that needs testing: export de ...

Filtering Tables with AngularJS

Currently, I'm experimenting with using angularJS to filter data in a table. My goal is to load the data from a JSON file that has a structure like this (example file): [{name: "Moroni", age: 50}, {name: "Tiancum", age: 43}, { ...

Issue encountered in IE9 and IE10 when loading the angular library results in the "SCRIPT5007: Object expected" error for Angular JS

I am currently working on an AngularJS application that needs to be compatible with Firefox, IE 9, and IE 10. We are using the latest version of the AngularJS library (currently at 1.3.15). Our serverside is based on Java in the JavaEE platform, running on ...

Error: Trying to send FormData to ajax results in an Illegal Invocation TypeError being thrown

Successfully sending a file to the server for processing using the code below: var formData = new FormData(); formData.append('file', $('#fileUpload')[0].files[0]); options = JSON.stringify(options); // {"key": "value"} $.ajax({ ...

Place a div element immediately following a table row in the HTML document

Welcome to my hotel and cabin availability page! I've created a PHP query that displays the available hotels and cabins in a table format. However, I want to enhance the user experience by displaying a Google Maps location and some pictures of each ho ...

Utilizing FullCalendar for showcasing comprehensive details

I'm a big fan of the fullcalendar plugin and all its amazing features. I want to enhance it by displaying more customized information for each event when in agendaWeek or agendaMonth view. Switching between views is easy, but I need help filtering out ...

The values are not being displayed in the local storage checkbox

I attempted to transfer checkbox values to another HTML page using local storage, however they were not appearing on the other page Here is my page1 HTML code snippet: <input class="checkbox" type="checkbox" id="option1" name="car1" value="BMW"> ...

What is the best way to determine the quantity of elements received from an ajax request?

Here's the method I am currently using to count the number of li elements returned from an AJAX call: $.post('@Url.Action("actionName", "controller")', function (data) { $('#notificationCounter').html($(data).find('li&a ...

How to allow users to input strings on web pages with JavaScript

I created a Language Translator using java script that currently translates hardcoded strings in an HTML page. I want to enhance its flexibility by allowing users to input a string into a textbox/textarea for translation. Any assistance would be greatly a ...

Efficiently transferring a style property to a child component as a computed property in Vue.js

Currently, I am facing an issue that involves too much logic in my inline style, which I would like to move inside a computed property. While I understand that this is the correct approach, I am unsure of how to implement it. To provide a clearer understa ...

Using ng-init to pass a JSON object

I'm attempting to pass a JSON Object to my application using ng-init and the stringify method, but I am encountering an error. Instead of working as expected, I am getting a Lexer error. Lexer Error: Unexpected next character at columns 8-8 [#] in ex ...

When an item in the accordion is clicked, the modal's left side scroll bar automatically scrolls to the top. Is there a solution to prevent this behavior and

When I first load the page and click on the Sales accordion, then proceed to click on Total reported and forecasted sales, the scrollbar jumps back up to the top The marked ng-container is specifically for the UI of Total reported and forecasted sales He ...

What is the best way to send a file object to a user for download?

When working within a route: app.get('some-route', async (req, res) => { // ... } I am dealing with a file object called file, which has the following structure: https://i.stack.imgur.com/ByPYR.png My goal is to download this file. Cur ...

What is the method for designating the specific pages on which the stripejs script should be loaded?

The performance of the main-thread is being significantly impacted by Stripe's script, as illustrated in the image provided by Google Insights. https://i.stack.imgur.com/bmdJ2.png My concern is that the page currently experiencing issues does not ac ...

The Chrome extension functions properly when the page is refreshed or loaded, but it does not work with internal navigation

When landing on a YouTube page starting with w*, I have a script that triggers an alert with the URL. However, this only works when entering the page directly or upon refreshing. I am trying to make the alert trigger when navigating internally to that page ...

Ways to automatically refresh a page in Javascript after a short period of user inactivity

Similar Question: How Can I Modify This Code To Redirect Only When There Is No Mouse Movement I am looking to update a web page automatically if the user is inactive, specifically through key presses or mouse clicks using Javascript. ...

Having trouble with a Reactjs Facebook login library - update the componentClicked function to be async

Currently, I am working on incorporating Facebook login into my React application using Redux. Within my loginUser.js file, the "FacebookLogIn" component appears as follows: <FacebookLogin appId="375026166397978" autoLoad={true} fields="name, ...

What could be causing React to render only the final two elements of my array?

I am currently working on a project where I need to display a series of images from a folder. While I have managed to accomplish this, I am facing an issue where the images are being displayed in rows of 2. Although the implementation is successful, it see ...

Guide on invoking personalized server-side functions (such as object parsing) utilizing Typescript and Angular tools

I've been grappling for weeks to make custom service calls function with Typescript / Angular / C#. It's been a challenge to find a workable solution online, and the more I search, the more bewildered I become. My current approach has largely be ...