2

I've read countless articles on this / questions on Stack Overflow, as well as the documentation, but I don't seem to be able to find an answer for this anywhere.

Basically I have the following directive:

angular.module('diDirectives', []).  
directive('ExampleElement', ['$rootScope', '$timeout', function($rootScope, $timeout) {

    return {
        priority: 0,
        restrict: 'C',
        template: '<div class="ExampleElement"></div>',
        link: function(scope, el, attrs) {

            function finish(){
                $('.ExampleElement').fadeOut(function(){
                    $(this).remove();
                });
            }

            //$('<div class="ExampleElement"></div>')
            //.appendTo('body')
            //.hide()
            //.fadeIn(function(){
                $timeout(finish, 10000);
            //});

        }
    }

}]);

That looks for an element called ExampleElement and then fades it out and removes it from the DOM after 10 seconds. The problem is that the element HAS to already exist on the page... what I want to do is make it so that the directive adds the element to the page for me (see the commented out jquery code to append it to the body).

But I can't seem to figure it out. I've read into $compile and other things, but almost all examples seem to deal with adding a directive to another directive or other template, rather than just adding it when the code is run...

Can anyone show an example of how to do this?

Update: One idea I had was doing this was:

diApp.run(function ($state, $rootScope, $log, $location) {

    $rootScope.$state = $state;

    $('body').append('<div class="loading-overlay"></div>')
    .hide()
    .fadeIn(function(){

        // CALL DIRECTIVE LINK FUNCTION???

    });

});
13
  • You mean that the directive should add itself to the DOM if it doesn't exist? The problem is that the link function won't run unless the directive exists in the DOM. If you want the directive to add itself to the body if it doesn't exist it's still solvable, is this the case? Commented Feb 22, 2015 at 15:07
  • Yes that's EXACTLY the case! Commented Feb 22, 2015 at 15:08
  • Is one of these elements enough or do you need multiple? Commented Feb 22, 2015 at 15:10
  • There should only ever be one of them. The directive basically runs adds the element and then removes it after the timeout, and then that's it. Commented Feb 22, 2015 at 15:11
  • The directive's template contains the directive again, which means there will be a infinite loop. I will post an example of what I hope you are looking for. Commented Feb 22, 2015 at 15:13

3 Answers 3

1

If I understand the question correctly, when your application starts, you want to add an element to the page that fades in (assuming while the application is loading), and then, after 10 seconds you want this element to fade out and remove itself from the DOM.

You're looking for the correct "angular way" to do this. In angular, in general, you only want to modify the DOM in a directive.

While you can inject a node into the DOM using $compile in the run() function, this is a bit overkill.

I would create a directive "splash" that you can apply to the body element in your HTML:

<body class="splash"></body>

angular.directive('splash', function($timeout) {
    return {
        restrict: "C",
        link: function(scope, element, attr) {
            //element is the element splash is applied to, in this case, "body"
            element.append('<div class="loading-overlay"></div>')
            .hide()
            .fadeIn(function(){
                 var self = $(this);
                 $timeout(function() {
                     self.fadeOut(function(){
                         $(this).remove();
                     });
                 }, 10000);
            });
        }
    }
})

Since the directive uses restrict: "C", you can use splash both as the directive and as a CSS class for styling purposes. You would target the loading overlay with:

.splash .loading-overlay
{
    //your CSS here
}

If you wanted the splash element itself to be able to run angular code, then this simple modification will do it:

angular.directive('splash', function($compile, $timeout) {
    return {
        restrict: "C",
        link: function(scope, element, attr) {
            //element is the element splash is applied to, in this case, "body"
            element.append($compile('<div class="loading-overlay"></div>')(scope))
            .hide()
            .fadeIn(function(){
                 var self = $(this);
                 $timeout(function() {
                     self.fadeOut(function(){
                         $(this).remove();
                     });
                 }, 10000);
            });
        }
    }
})

As written, the splash directive could be applied to any element (not just body). You could also get sophisticated and pass in a template to use instead of hardcoding the template in the directive.

angular.directive('splash', function($compile, $timeout) {
    return {
        restrict: "C",
        link: function(scope, element, attr) {
            //element is the element splash is applied to, in this case, "body"
            element.append($compile('<div ng-include="\'' + scope.$eval(attr.splashSrc) + '\'"></div>')(scope))
            .hide()
            .fadeIn(function(){
                 var self = $(this);
                 $timeout(function() {
                     self.fadeOut(function(){
                         $(this).remove();
                     });
                 }, 10000);
            });
        }
    }
})

usage:

<body class="splash" splash-src="'splash-template.html'"></body>
Sign up to request clarification or add additional context in comments.

3 Comments

"pass in a template to use instead of hardcoding the template in the directive." Could you show an example of this? Thanks.
What about using a templateUrl or template in the directive? So I don't have to have anything in the DOM.
Directives can do one of two things by default, depending on the value of "replace". If replace = false (the default), then the directive will replace the contents of the element with the template. If replace = true then the directive will replace the element itself. In both cases, your directive would essentially empty the contents of the body, which I don't think is what you want. There is no 'replace: 'append' (although I think that would be a cool addition).
0

an idea may be to use restrict E for your directive and either append your element to this or replace this element with your fading element. ex:

<myExampleTag></myExampleTag>

so that way when angular bootstraps to your page it will fire your directive, replace this tag/append to this tag and trigger your animation

2 Comments

That's no different to having the element already in the DOM. I want to not have ANY elements already in the DOM to replace or append to.
@Cameron may why you don't use a comment restriction. Its a simple solution.
0

You could use angular.element to create an element, e.g. your directive and then append it with angular.element('body').append(yourElement);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.