Cameron
Cameron

Reputation: 28803

Append directive to DOM using AngularJS

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???

    });

});

Upvotes: 2

Views: 2318

Answers (3)

Joe Enzminger
Joe Enzminger

Reputation: 11190

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>

Upvotes: 1

Dani&#235;l Smink
Dani&#235;l Smink

Reputation: 368

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

Upvotes: 0

Ryan
Ryan

Reputation: 107

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

Upvotes: 0

Related Questions