6

This concerns a MEAN.js environment. I have if-statements in my Angular view to check if I have any results from my database. If there are results then I show them, if not then I show an error message.

I have an issue with Angular code blinking: when the page loads, for a split-second I see the error message, and then it immediately shows the results from my database. The ng-cloak directive does not work.

Code

Below I have included very basic Angular code that should make clear what I am doing.

Controller:

// Return a specific person from the database.
this.person = Persons.get({
    personId: $stateParams.personId
});

View:

<div ng-if="personCtrl.person.length">
    <!-- Show person's details here... -->
</div>

<div ng-if="!personCtrl.person.length" ng-cloak>
    <p>Sorry, person could not be found.</p>
</div>

I tried adding the ng-cloak directive, which does not work. MEAN.js also uses Bootstrap and provides a few CSS classes, but no matter which ones I add, none of them work:

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
    display: none !important;
}

In short: I can add the ng-cloak directive AND the ng-cloak CSS class, but they do not work. I can add style="display:none;" but that hides the error message even if it is supposed to be shown.

Community
  • 1
  • 1
Tom
  • 734
  • 2
  • 7
  • 27
  • 1
    I find it easier to use ng-bind and ng-bind-html. – Kevin B Apr 28 '15 at 20:19
  • seems like before making an ajax you set `personCtrl.person=[]` then ajax call response making it null – Pankaj Parkar Apr 28 '15 at 20:19
  • 1
    It looks like the problem is that personCtrl.person.length IS actually false for a split second before the Persons.get promise completes. Using ng-cloak won't fix that. You could initially set personCtrl.person.length to false before you do the get. – ribsies Apr 28 '15 at 20:19
  • How early is your angular.js loaded? If you load angular at the bottom of your index page, html will render normally because ng-cloak simply isn't a thing yet. Try moving angular higher in the load order, i.e. in the head. Also, I run ng-cloak on the html tag instead of individually, but that's just preference. – Owen Apr 28 '15 at 20:25
  • @Owen: AngularJS is the very first script loaded in my ``. I also have `ng-cloak` added to my `` tag. – Tom Apr 28 '15 at 20:29
  • Another option is to create a loading tag that starts on the request and completes when the promise is returned. I use this in conjunction with ngProgress for a great visual loading indicator. – Owen Apr 28 '15 at 20:29
  • Again, your issue has nothing to do with ng-cloak. It's a variable issue. ng-cloak prevents things like {{someVariable}} being seen exactly like that before it's compiled. Your code is working properly the way you have it written. – ribsies Apr 28 '15 at 20:30
  • 1
    @ribsies: ng-cloak also prevents page display before things like ng-if can evaluate. This is why I was trying to get all of the information to make an informed response. – Owen Apr 28 '15 at 20:33
  • @ribsies regarding your first comment, do you mean set it to true before I do the get, instead of setting it to false? Because that makes sense, and I just tried it (tried both ways), but it doesn't work unfortunately. It is as if the code in my controller isn't processed quickly enough, and I have no idea how to fix this in a MEAN.js application. – Tom Apr 28 '15 at 20:45
  • 1
    `ng-cloak` prevents *raw* expressions from being output. it could not stop your false `ng-if` statement from being displayed; if it did, how would it know when it is correct to display it and when it is not correct to display it? in your code, the expression evaluated, it just didn't evaluate to the result you expected. `ng-cloak` does not interact with promises or `$http` / `$resource` to determine that the result might change later.... – Claies Apr 28 '15 at 21:11
  • 1
    the issue here is the fact that you are returning a promise, and you aren't accounting for that fact in your code. – Claies Apr 28 '15 at 21:14
  • Try switching to ng-show instead. – c0deNinja Apr 29 '15 at 06:58

2 Answers2

3

Is this maybe what you are looking for?

<div ng-show="personCtrl.person.length">
    <!-- Show person's details here... -->
</div>

<div ng-hide="personCtrl.person.length" ng-cloak>
    <p>Sorry, person could not be found.</p>
</div>
0

Your issue isn't with ng-cloak, it is with latency from the server.

The solutions are to manage the states either with jQuery inside a directive (recommended) or within the controller.

Here I have demostrated the principle in very rough form http://plnkr.co/edit/sSVHl5AXkltjvBrpKR4s

app.controller('HomePage', function($scope, $timeout){
    $scope.user = false;
    var el = angular.element('#user-data-loading-zone');
    // modelling 1000ms latency from the server
    $timeout(function(){
        $scope.user = {name: 'John'};
        if($scope.user) {
            el.removeClass('loading');
            el.addClass('success');
            el.html('Success data was loaded => ' + $scope.user.name);
        } else {
            $scope.state = 'Error unable to load';
        }
    }, 1000);
});

The states are typically...

  1. Loading...
  2. Success! or Error!

Use jquery and css to smooth out the experience with animations. Use directives to factor out the above code and make it reusable.

Mwayi
  • 1,623
  • 15
  • 13