0

In the following directive, I do a pretty long running operation, so I want to display a loading spin during that time. I've used ng-show and a isLoading variable on the scope of the directive. However the spinner never shows although isLoading is set to true.

What's wrong with my code ?

angular.module('shared.directives').directive("xmlVisualizer", ['$rootScope', function ($rootScope) {
return {
    restrict: 'E',
    template: '<div ng-show="isLoading" class="center span10"><i class="icon-spinner icon-6x">chargement du fichier...</i>  </div> <div class="center span10" ng-show="!isLoading"> <h4>Détail du fichier {{title}}</h4> <pre id="test" class="prettyprint"></pre></div>',
    scope: {
        model: '=',
        title: '='
    },
    link: function (scope, element, attrs) {
        if (scope.model) {
            scope.isLoading = true;

            scope.xml = vkbeautify.xml(scope.model);
            $("#test").text(scope.xml);
            $("#test").html(prettyPrintOne($("#test").html(), 'xml'));

            scope.isLoading = false;
        }
    }
}
}]);
0

2 Answers 2

1

I think that your problem is actually that isLoading in the template is not the isLoading within the directive, rather it's looking for it in the parent scope. Hence, as it is undefined (and stays undefined, because you're only changing the isLoading inside the directive), it always shows the !isLoading block.

You could try to do

 template: '<div is-loading="isLoading" ng-show="isLoading" class="center span10"><i class="icon-spinner icon-6x">chargement du fichier...</i>  </div> <div class="center span10" ng-show="!isLoading"> <h4>Détail du fichier {{title}}</h4> <pre id="test" class="prettyprint"></pre></div>',
    scope: {
        model: '=',
        title: '=',
        isLoading: '='
    },

but I'm not sure if it would work with a primitive. If not, perhaps try an object $scope.isLoading = {value: true}; (on the parent scope -- probably the controller) and is-loading="isLoading.value" (on the template).

That way, the spinner flag on your controller will get updated through the bi-directional binding, and your directive will be able to use it in its template.

Sign up to request clarification or add additional context in comments.

Comments

0

You need to watch the scope

Try this

    angular.module('shared.directives').directive("xmlVisualizer", ['$rootScope',        function ($rootScope) {
    return {
        restrict: 'E',
        template: '<div ng-show="isLoading" class="center span10"><i class="icon-spinner icon-6x">chargement du fichier...</i>  </div> <div class="center span10" ng-show="!isLoading"> <h4>Détail du fichier {{title}}</h4> <pre id="test" class="prettyprint"></pre></div>',
        scope: {
            model: '=',
            title: '='
        },
        link: function (scope, element, attrs) {
            scope.$watch(function(scope){return scope.model}, function(model){
                if (model) {
                    scope.isLoading = true;

                    scope.xml = vkbeautify.xml(scope.model);
                    $("#test").text(scope.xml);
                    $("#test").html(prettyPrintOne($("#test").html(), 'xml'));

                    scope.isLoading = false;
                }
            })
        }
    }
}]);

PS: I am not very well versed with angular myself. Hope this works for you.

5 Comments

that does not seem right to me. Why would I watch the entire scope ? and that's not going to update the UI. I've tried scope.$apply() though and it didn't work as there is a digestion in progress already.
Guess is that you need to watch the scope from inside the link function explicitly. U might consider logging the arguments of your link function to see how many times it's called. Logic would have it that it will be called every single time there is a change in scope but it is actually called only on init or change in the particular html in DOM. No change in scope actually triggers the link function you have written. Also every change in scope will not trigger the second function inside $watch argument. I have deduced all this through console logging. May be not 100% right. Trying to help
@Sam he's not watching the entire scope, just the model. function(scope){return scope.model} is equivalent to 'model'
Also I have assumed that change in scope.model needs to trigger everything here. Change if necessary
@RanjithR, I think using the '=' binding for the model scope variable is enough. I don't need to watch it too. AMOF, my binding works fine. Whenever the model is changed, the UI updates itself. But the loading spinner never shows up, and that I don't understand why. thanks for helping

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.