0

If I have a standard factory, creating a person, say:

      $scope.person = Person.get({person: $routeParams.person},function () {
  },function (httpResponse) {
  });

My HTML is:

<div>Person is: {{person}}</div>

Fairly straightforward. My issue is with rendering. My understanding is that when this runs, it immediately returns an empty object; when the async get finally returns, it will fill in $scope.person, and then re-render.

  1. What prevents this from just rendering as Person is: and then rerendering as Person is: John? I don't want that blank, if anything, I want to show some "loading" and then change it when render is complete.
  2. How do I handle errors? If I get a 404 - say the person ID is non-existent - I want to show some form of "sorry, the user you requested doesn't exist". But I want to be sure that shows only after I actually tried, not accidentally render it while waiting for the person to load.
3
  • Regarding your first question, take a look at ngCloak Commented Sep 28, 2013 at 18:22
  • Also please show the code for the get function. Commented Sep 28, 2013 at 18:23
  • @MKSafi that is great, exactly what I was looking for. Can you post this as an answer, so I can choose it? Commented Sep 28, 2013 at 18:36

2 Answers 2

3

How we have handled this:

  • Implemented a busy directive. In your case it would be applied as:

    <div busy="!person.$resolved">Person is: {{person.name}}</div>
    

    (Note also that I have changed person a bit, to be an object)

  • The busy directive implementation is more or less as (we are using jQuery):

    app.directive("busy", function() {
        return {
            restrict: "A",
            link: function(scope,element,attrs) {
                var wrapper = element.wrap("<div class="busy-wrapper"></div>");
                scope.$watch(attrs.busy, function(busy) {
                    if( busy ) wrapper.addClass("busy");
                    else wrapper.removeClass("busy");
                });
            }
        });
    });
    
  • And then the CSS:

    .busy-wrapper.busy * {
        display: none; /* we hide the content when busy */
    }
    .busy-wrapper.busy {
        /* display a spinner */
        background: white url("my-busy-spinner.gif") no-repeat center;
        height: 50px; /* Depends... */
    }
    
  • When we catch an error, we mark the resource object (here the person) with an $error=true attribute:

    $scope.person = Person.get(...,
        function() { /* success */ },
        function(response) {
            $scope.person.$error = true; // and maybe more stuff from the response, e.g. a $message attribute
        }
    );
    

    How we handle the $error attribute depends on the context; sometimes we hide the output and display a "retry" link, e.g.:

    <div ng-if="!person.$error" busy="!person.$resolved">Person is: {{person.name}}</div>
    <div ng-if="person.$error">Something bad happened. <a ng-click="retry()">Retry!</a></div>
    

This is not the exact code, but I think it gives you a general idea. Also this is not the only correct approach (I am interested in others), just how we are doing it. Oh and you can do all sorts of nice stuff to busy, like adding animations/transitions.

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

1 Comment

Oh, Nikos, I like that. I already selected the other as an answer, but this is great. It is a pity that this isn't built right into Angular, it is really nicely done
1

You can use ngCloak.

From AngularJS

The ngCloak directive is used to prevent the Angular html template from being briefly displayed by the browser in its raw (uncompiled) form while your application is loading. Use this directive to avoid the undesirable flicker effect caused by the html template display.

Comments

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.