Creating an Angular directive that controls the visibility of an element based on

I have been implementing a pattern in my application to delay loading certain expensive DOM elements until they are needed. The pattern involves using conditional logic like this:

<div ng-if="someCondition || everShown" ng-show="someCondition">

This ensures that the element is only added to the DOM when someCondition is true and remains there thereafter. However, I noticed a lot of repetitive code and decided to create a directive to streamline this process.

Here is my attempt at creating the directive:

export function IfEverShown($parse: angular.IParseService): angular.IDirective {    
    return {
        restrict: "A",
        compile: function(element: angular.IAugmentedJQuery,
                          attributes: angular.IAttributes) {
            if (!attributes["ngShow"]) {
                return;
            }
            element.attr("ng-if", "everShown");

            return {
                pre: function(scope: angular.IScope) {
                    scope["everShown"] = false;
                    attributes.$observe('ngShow', function (expr) {
                        scope.$watch(function () {
                            return $parse(<any> expr)(scope);
                        }, function (value) {
                            if (value) {
                                scope["everShown"] = true;
                            }
                        });
                    });
                }
            };
        }
    };
}

To use the directive, you would do:

<div ng-show="someCondition" if-ever-shown>

However, despite changing the ng-if value in the DOM as expected, Angular seems to ignore the changes. The element is always present in the DOM if there was no previous ng-if, and observed even after it has been changed from its previous value.

How can I achieve the desired behavior? Is it possible to modify an ngIf from a directive? Alternatively, is there another way to ensure that the element is not added to the DOM until the ng-show condition has been true at least once?

Thank you!

Answer №1

The $compile service does not automatically compile directives that are added to the element during the compile phase. Any newly added directives must be manually compiled in the link phase:

app.directive("myIf", function($compile) {
  return {
    priority: 1000,
    terminal: true,
    compile: function(tElem, tAttrs) {
      tAttrs.$set("ngIf", tAttrs.myIf);
      tAttrs.$set("myIf", null);
      return postLink;
    }
  }
  function postLink(scope, elem, attrs) {
    $compile(elem)(scope);
  }
});

The example above showcases a custom directive named my-if. It introduces an ng-if directive during the compile phase and manually compiles it during the link phase.

It is important to note that this directive is implemented as a high-priority "terminal" directive, and it eliminates the my-if attribute to ensure that directives are compiled only once.

View the DEMO on PLNKR.

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

Issues with the compatibility of the latest JSX Transform, featuring React 16.14, Typescript 4.1.0-beta, and react-scripts 4.0.0-next.98 have

Referencing the information from this source. Here is a snippet from my package.json file: "react": "^16.14.0", "react-dom": "^16.14.0", "react-scripts": "4.0.0-next.98", "typescript": ...

When you add the /deep/ selector in an Angular 4 component's CSS, it applies the same style to other components. Looking for a fix?

Note: I am using css with Angular 4, not scss. To clarify further, In my number.component.css file, I have: /deep/ .mat-drawer-content{ height:100vh; } Other component.css files do not have the .mat-drawer-content class, but it is common to all views ...

The 'push' property is not found within the 'Control' type

I am attempting to create an array that contains arrays within it. This array is intended for a dynamic form functionality, where the user can add a new section and push the array of control fields to the main array. Angular2 then generates this dynamical ...

The focus is on the last row that was selected

I've noticed that when I check and select a row in ui-grid, only the last selected row is focused with a background color. Should all rows be automatically painted by default? Thank you. ...

Is it possible for TypeScript to deduce the type of a discriminated union using "extracted" boolean logic?

Recently, I've been using discriminated unions (DU) more frequently and have really started to appreciate their benefits. However, I've encountered a challenge that I can't seem to resolve. When I include a boolean check inline for the DU, T ...

When I attempt to return an object from a function and pass the reference to a prop, TypeScript throws an error. However, the error does not occur if the object is directly placed in

Currently, I have the following code block: const getDataForChart = () => { const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; const test = { ...

Exploring the visitor design pattern with numerical enumerated types

I am exploring the use of the visitor pattern to ensure comprehensive handling when adding a new enum value. Here is an example of an enum: export enum ActionItemTypeEnum { AccountManager = 0, Affiliate = 4, } Currently, I have implemented the fol ...

Issue with Angular JS failing to trigger scroll event

As I embark on my first project using Angular 1.5.x, things have been going smoothly so far. However, I recently encountered a simple challenge of logging window position/event on scroll. Despite trying various methods like directives, event binding, and ...

Accessing the scope value in Angular JS beyond the HTTP call

I am faced with a situation where I have multiple select boxes, each requiring data from different URLs to populate them. I am trying to load the response data into these boxes using the following code: function getFilterDataUrl(category_url) { var filt ...

Presenting a ui-router modal while maintaining the parent state's refresh-free appearance

I have implemented a unique feature in my angular app called modalStateProvider. It allows me to easily have modals with their own URLs. // Implementing the modalStateProvider app.provider('modalState', [ '$stateProvider', function ...

My ng-view html is unexpectedly displaying as plain string. What steps should I take to resolve this issue?

Why is my ng-view HTML displaying as plain text? How can I resolve this issue? I have encountered an error, here is the screenshot for reference: Unfortunately, I am unable to upload images at the moment. ...

Troubleshooting the error message "TypeError: Cannot read property 'name' of undefined" when working with data binding in Angular 4

I am brand new to Angular and I have been working on creating a custom Component. Specifically, I am trying to display a list of Courses (objects) which consist of two properties: id and name. So far, this logic is functioning properly. However, when attem ...

The AngularJS directive that wraps the Kendo UI grid is unable to handle the kendoEvent properly

Our goal is to develop a displayBasket directive that will wrap kendoGrid and additional functionality. However, we are facing an issue where the gridDataBound function is not receiving kendoEvent. How can we resolve this problem? Here is an example in HT ...

Can someone please explain how I can extract and display information from a database in separate text boxes using Angular?

Working with two textboxes named AuthorizeRep1Fname and AuthorizeRep1Lname, I am combining them in typescript before storing them as AuthorizeRep1Name in the database. Refer to the image below for the result. This process is used to register and merge the ...

Guide to using express to render templates

Here is my current configuration: When I start the server and navigate to localhost, it directs me to home.ejs as specified in my front end routing: However, when I attempt to access localhost:3000/posts, the posts template does not get displayed on my i ...

A straightforward angular implementation of a non-complicated slider interface

I am working on a web page that needs to display a large list of items. To manage the size, I want to show only 3 items at a time and include next/previous buttons for navigation. Although I am new to Angular, I was able to retrieve and display all the it ...

Having trouble getting my AngularJS animations to work, hitting a roadblock

Here is the code I've put together for you to review, with no official purpose in mind. I just saved this code to use at a later time. <script> var apps = angular.module('myApp', ['ngAnimate']); //header apps.cont ...

Unlock the power of deep linking with the Branch SDK and integrate seamlessly with

Trying to utilize Branch's deep-linking features, particularly deferred deep-linking, in my Ionic project has been a challenge. The issue lies in the incomplete documentation provided for Cordova/Ionic integration by Branch. Despite installing their C ...

Steps for displaying an error message in a method that returns a ResponseEntity in Spring MVC using the @ControllerAdvice annotation

Currently, I am in the process of developing a web application using Spring MVC and AngularJS. For this project, I am creating a Rest API that returns ResponseEntities containing JSON strings. One issue I am facing is how to handle exceptions within my ap ...

Sharing a Directive across multiple AngularJS modules: Tips and Tricks

AngularJS has truly captured my interest with its powerful capabilities. I am delving deeper into the world of Angular and finding myself falling in love with it more each day. Despite my efforts, certain doubts continue to linger, leaving me eager for cla ...