Chris
Chris

Reputation: 27384

Delay creation directive

I am looking to create a delayed creation directive such that I can simply add it to an object like so to allow it to be created some time later like so

<div delay-creation="1000">Theres lots of things in here </div>

The reason behind this is that my UI is quite complicated and lots of objects are rendered that arent initially seen. I see this as a nice reusable way to delay creation of off screen objects without having to mess about with custom code all the time.

I initially thought my new directive could conditionally adding ng-if="false" to the $element and then, after some time period, set the value to be true. Unfortunately this seems far more complicated than I first thought. Is there a better way to do this or can anyone help me in creating this directive?

** Edit: Based off of Bens code this now works **

export class DelayCreationDirective implements angular.IDirective {

    restrict = "A";

    public link: (scope: angular.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes) => void;

    constructor($timeout: angular.ITimeoutService) {

        DelayCreationDirective.prototype.link = ($scope: angular.IScope, $element: angular.IAugmentedJQuery, attrs: ng.IAttributes) => {

            var placeholder = angular.element(document.createComment("delayCreation placeholder"));

            $element.after(placeholder);
            $element.remove();

            $timeout(() => {
                $element.removeAttr("delay-creation");
                $element.attr("ng-if", $attrs["delayCreation"]);

                if (placeholder) {
                    placeholder.after($element);
                    placeholder.remove();
                }

                $compile($element)($scope);
            }, 1000);
        }
    }

    static factory(): ng.IDirectiveFactory {
        const directive = ($timeout: angular.ITimeoutService) => new DelayCreationDirective($timeout);

        directive.$inject = ["$timeout"];

        return directive;
    }
}

angular
    .module("app.directives")
    .directive("delayCreation", DelayCreationDirective.factory());

Upvotes: 0

Views: 748

Answers (2)

georgeawg
georgeawg

Reputation: 48948

One approach it to add a sibling directive that delays setting the ng-if.

  <div  delay-expn="show1=true" delay-time="2000" ng-if="show1">
       This delayed 2 seconds
  </div>

The directive:

app.directive("delayExpn", function($timeout) {
    return {
         //set priority higher than ng-if (600)
        priority: 1000,
        link: function linkFn(scope,elem,attrs) {
            $timeout(angular.noop, attrs.delayTime).then(function() {
                scope.$eval(attrs.delayExpn);
            });
        }
    };
});

By setting the directive's priority higher than the ng-if directive, the $timeout gets started before the element is replaced by ng-if.

The DEMO on PLNKR

Upvotes: 1

Ben Bracha
Ben Bracha

Reputation: 1397

I think that using ng-if won't help you because Angular's ng-if DOM sub-tree always gets complied, then removed from DOM if needed. So it takes the time anyway.. We implemented in the past a "lazy-ng-if" directive, to prevent that complication, maybe it can be used in your UC?

https://github.com/ravello/lazy-ng-if

BTW, this capability was added to Angular1.5 as well AFAIK

Upvotes: 3

Related Questions