Retrieving DOM elements within a directive once ng-if has finished compilation

I am currently working on creating a dynamic side navigation menu that will populate its items based on the state of the DOM, specifically the <section> elements in my document.

The challenge I am facing is that I have applied some ng-if directives to certain <section> elements, and these directives are dependent on scope variables that are fetched via AJAX using $http.get. As a result, when the directive is compiled or linked, these scope variables have not yet been retrieved and the ng-if conditions are unstable as they evaluate as if the variables are undefined.

Main HTML

<my-sidenav></my-sidenav>

<!-- Various other content and structure -->

<section id="foo1" class="sidenav-item">...</section>
<section id="foo2" class="sidenav-item">...</section>
<section id="foo3" class="sidenav-item" ng-if="fooVar1 === fooVar2">...</section>
<section id="foo4" class="sidenav-item">...</section>
<section id="foo5" class="sidenav-item" ng-if="fooVar3 !== fooVar4">...</section>

Sidenav HTML

<div>
    <a ng-repeat="section in ctrl.sections track by section" href="#" ng-click="ctrl.scrollTo(section)">{{section}}</a>
</div>

Directive Definition

function mySidenav() {
    return {
        templateUrl: 'sidenav.html',
        controller: function() {
            var ctrl = this;

            // Once template URL is linked
            // !!! ng-if still not stable !!!
            ctrl.$postLink = function() {
                // Convert nodeList to array for easier manipulation
                var nodeList = document.querySelectorAll('.sidenav-item');
                var nodeArray = Array.prototype.slice.call(nodeList);

                // Extract section id
                ctrl.sections = nodeArray.map(function(el) {return el.id;});
            };

            ctrl.scrollTo = /*...*/
        },
        controllerAs: 'ctrl'
    };
}

Is there a preferred method to access DOM elements on the page only after the ng-if expressions have stabilized? I was considering using $timeout, but I'm unsure of what would be a safe delay value.

Alternatively, could I utilize $watch? Is there a way to ensure that ctrl.sections dynamically updates?

Answer №1

After implementing $watchCollection successfully, I plan to leave this question open for potential feedback on alternative solutions.

I made adjustments to the directive definition as shown below:

function customSidenav() {
    return {
        templateUrl: '/custom/resources/html/sidenav.html',
        controller: ['$rootScope', function($rootScope) {
            var ctrl = this;

            $rootScope.$watchCollection(
                function(scope) {
                    return fetchSections();
                },
                function(newValue, oldValue, scope) {
                    ctrl.sections = newValue;
                }
            );

            ctrl.scrollTo = /*...*/;

            function fetchSections() {
                // Optimal method for retrieving IDs
                var ids = [];

                var nodeList = document.querySelectorAll('.sidenav-item');
                for (var i = 0; i < nodeList.length; i++) {
                    ids.push(nodeList[i].id);
                }

                return ids;
            }
        }],
        controllerAs: 'ctrl'
    };
}

Answer №2

To implement the link function, follow these steps:

function mySidenav() {
    return {
        templateUrl: 'sidenav.html',
        link: function(scope, elm) {
                // Transform nodeList into an array for easier handling
                var nodeList = document.querySelectorAll('.sidenav-item');
                var nodeArray = Array.prototype.slice.call(nodeList);
                var sections = nodeArray.map(function(el) {return el.id;});   
        }
    };
}

Check out this CodePen example for reference.

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

Parameterized Azure Cosmos DB Stored Procedure

I am currently learning about Azure Cosmos Db, and I am in the process of developing a simple JavaScript stored procedure that will return a document if a specific Id is provided. However, when I run the stored procedure, I do not receive a "no docs foun ...

Client requests are not being responded to by the server

I've been trying to send a request from the client to the server using Jquery and Ajax, but I'm running into some issues. I've also attempted using Ajax and Xml, but without success. Can anyone offer assistance with this problem? Here is my ...

The 'async' keyword is not permitted in this context within a TypeScript React application

An issue has arisen with the aync, indicating that the async modifier is not permitted in this context: private async getValue= (acc: Access): void => { await this.service.getForm(''); } It appears that there might be an ...

Design a recurring report using an endless JavaScript cycle

I am in the process of creating a brand new scheduled report and have encountered an issue. How can I incorporate a script that includes a loop to run a specific function every 10 seconds? Here's what I have so far: var count = 1; while(count > 0 ...

Utilizing Grunt to streamline a personalized project

I have set up Grunt as my "JS Task Runner". Node.js is installed in the directory "C:/Program Files". NPM has been installed in C:/users/Peterson/appdata/roaming/npm. Inside the npm folder, I have Grunt, Bower, and Grunt-cli. I am working on a pro ...

Using a uibCollapse within a nested directive element may not function as expected

Whenever I try to click on my custom directive, the elements that are supposed to expand remain collapsed. To ensure that the click event is actually triggered, I have specified a size in the css for the .btn class. // index.html <body ng-controller=" ...

Refresh your HTML page automatically while keeping the scroll position and functioning with anchors

I am currently facing an issue with a web service that generates HTML and I need it to automatically refresh in the browser every 10 seconds. Initially, I used the <meta http-equiv="refresh" content="10"> method which worked successfully, maintaining ...

Can a personalized form be dynamically modified in Camunda BPM without the need for redeployment?

As a newcomer to Camunda, I am still exploring the possibilities it offers. Camunda BPM allows for the creation of custom forms in at least three ways: Create a web-based form using AngularJS. Here is an example: https://github.com/camunda/camunda-bpm-e ...

What is the best way to extract the selected text from a dropdown list using Kendo UI jQuery?

I currently utilize the Kendo UI jQuery version 2019.2.514 . Below is a snippet of my code: <input id="skuCode" name="skuCode" style="width: 100%;"/> <input id="productName" name="productName" style="width: 100%;"/> <script> $(docume ...

Error message: When the mouse hovers over, display the chart(.js) results in TypeError: t is

I encountered a persistent error that I just can't seem to resolve. My goal is to showcase a chart using Chart.js when the mouse hovers over the canvas. However, upon hovering over the canvas, I keep getting a TypeError: t is null error. Error: { ...

Is there a way for me to convert my HTML code into a Vue component?

I am trying to display a tiff file on a web page, I successfully did it with test.html, but now I need to do it within a vue file. How can I achieve this? Additionally, I am unsure about the specific content in the tiff.js[![enter image description here][1 ...

Is there an alternative method to including a PHP file from a remote server other than using the "<?php include(); ?>" syntax?

I have developed a PHP script that retrieves information from a MySQL database and I am looking to integrate this script (which contains extracted content from the database) onto various remote servers. These clients have websites built with Joomla/WordPre ...

The array is coming back empty after attempting to add objects to it

My Node JS and Express JS controller code is below: const UserComment = require(".../model/UserComment"); router.post("/get/comments", async (req, res) =>{ try{ let currentUserID = req.body.userID; let myUserComment = await UserComment.find({userID: cu ...

The issue of an undefined value being returned for a dynamic id in jQuery within a

Struggling to fetch the Post Id in WordPress dynamically using jQuery. Unfortunately, when I try to debug in the console, it keeps returning undefined. Any assistance would be greatly appreciated! Snippet of the code: Displaying the post ID with data-id ...

Issue: The type does not have any compatible call signatures, therefore cannot be invoked. Error message: 'Cannot invoke an expression whose type lacks a call

I'm currently integrating https://github.com/mapbox/polylabel into my Angular project. However, when I attempt to run ng server, the build fails and displays the following error: error TS2349: Cannot invoke an expression whose type lacks a call signa ...

The $rootScope object cannot be accessed in the controller

At module run, I created a $rootScope that is accessible from the view. However, I am struggling to access this value inside another controller. Can someone please suggest a way to achieve this? I attempted to make the datepicker popup options available ...

Issue with jQuery click event not triggering on dynamically created input boxes for removal

Having some trouble with the remove buttons not working on dynamically generated text boxes. The click function doesn't seem to be triggering, and I'm a bit stuck. Any ideas on what might be causing this issue? Take a look at the following co ...

Is there a way to hide the tooltip displaying the most recent dates in Bootstrap?

After implementing a datepicker with bootstrap, I noticed that whenever I click on the field, it displays the last years I have selected. This behavior obstructs the calendar view and serves no real purpose. Below is an excerpt of my current script along ...

The date picker functionality provided by ngMaterial is currently malfunctioning within an AngularJS environment

Can anyone assist me with adding a date picker to an input box? I've come across ngMaterial which seems to provide the necessary features. Despite including all required files, I am encountering an error. angular.js:68Uncaught Error: [$injector:un ...

Creating a dropdown menu in React using the React.createElement() function

I've created this HTML code snippet: <select id ='Font_Size' onchange="ChangeFont()"> <option>Font Size </option> <option id ='sizeUp'>Large </option> <option id ...