The expression {{heading + message}} in my html should render, as per my code, as Message: .
It does render the values of the variables heading and message when I input the values and click the button.
So the intended functionality is working.
But the question is about the initial load where the expression should
render as Message: in place of the expression itself as in
{{heading + message}}.
I am accessing the page via http://localhost:8080/examples/first.html, and I have tried on safari and chrome.
Nature of the problem:
The expression renders as is: {{heading + message}} for few seconds on the first load (unless I refresh the page).
It is eventually rendered but my question is why would it take a bit to render the title Message: in my .js file.
I am not certain, it couldn't be the processor because I am running it on Node.js / Express server on osx with 2.4 GHz Intel Core i5
The HTML:
<!DOCTYPE html>
<html ng-app="firstApp">
<head>
<title>First AngularJS App</title>
</head>
<body>
<div ng-controller="FirstController">
<span>Name:</span>
<input type="text" ng-model="first" />
<input type="text" ng-model="last" />
<button ng-click="updateMessage()">Message</button>
<hr>
{{heading + message}}
</div>
<script src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="https://code.angularjs.org/1.3.9/angular.min.js"></script>
<script src="js/first.js"></script>
</body>
</html>
The .js:
var firstApp = angular.module('firstApp', []);
firstApp.controller('FirstController', function ($scope) {
$scope.first = '';
$scope.last = '';
$scope.heading = 'Message: ';
$scope.updateMessage = function () {
$scope.message = 'Hello ' + $scope.first + ' ' + $scope.last + ' !';
};
});
Any pointers would be helpful. Following are the screen shots of what it looks like initially for a moment vs. after a few seconds:
vs.
EDIT: It isn't so just on the the first load. This happens on subsequent loads on new tabs as well, not as slow as the first load but it does happen.
Anything you think I should try different?
I think as per the ngCloak doc ,which will get rid of the flickering issue https://docs.angularjs.org/api/ng/directive/ngCloak
, ng-cloak works is it adds display: none !important to items using it.
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
This directive can be applied to the body element, but the preferred usage is to apply multiple ngCloak
<span ng-cloak>{{heading + message}}</span>
as per the doc of ng-cloak , make sure angular.js script must be loaded in the head section of the html file for the better results,
Instead of using AngularJS directive ngCloak, use class="ng-cloak", Angular will automatically remove it once it has loaded all of the module's dependencies.
You will have to add this line to your CSS file:
.ng-cloak {
display:none;
}
Add the class to your body tag:
<body class="ng-cloak">
Here's a working plunkr: http://plnkr.co/edit/v3DnDb2dJIqMAvxkEsO2?p=preview
This is most likely attributed to the fact that your scripts are being called from a remote server instead of from your testing server's local file system (I am thinking this due to the face that you stated it hangs while only rendering 2 variables which would not cause any real delay in rendering - to the naked eye), so while the get happens your browser does not know what to do with the Angular code until the library is downloaded, parsed and executed.
I would download a copy of AngularJS along with any other dependencies that nG may be using into your projects public scripts directory and then retest. I am willing to be that this solves your latency issues. The only other obvious thing it could be is the amount of data-binding expressions this view has - although if this the code above is the only angular you have on this page, then you can rule the amount of bindings out as a problem. I think one doesn't experience real latency issues until about roughly 10,000 data bindings (basically AngularJS is known for a ton of things - rendering speed is not one of them).
Also you can avoid the "expression flicker" by using ng-bind in place of the {{ ngExpressions }}.
You may also use <div ng-show="heading && message"> {{ heading }} {{ message }}</div>
or ngCloak. These techniques are are covered in this thread: In Angular, is there a way to prevent flicker in expressions that contain concatenated values?
Related
We have an AngularJS app (not a SPA). We face this problem where some part of uncompiled template is displayed for brief moments, so I am applying ngCloak directive to the app.
I'm not sure of where exactly should this directive be used - every single, small element or large sections (or somewhere else). What I'm currently doing is throttling connection via Chrome dev tools to a very slow speed and then checking which parts of template show up in raw state. But I feel this is not a very deterministic approach.
So I would like to know the where exactly to use ngCloak.
Thank You.
Applying ngCloak to every small element is certainly the wrong way to go.
You would typically want to apply it either to large sections, or to the entire portion of your page that uses Angular. The objective is to hide these parts of the page until Angular is ready to use.
This is what the official documentation says:
The directive can be applied to the <body> element, but the preferred usage is to apply multiple ngCloak directives to small portions of the page to permit progressive rendering of the browser view.
If you don't want your users to be looking at blank space, you can show a loading animation until Angular finishes loading. You can do this by giving the element an ng-show="false" directive:
<img src='/images/loading.gif' ng-show='false' />
Please add following code into head section of index.html
<style>
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
</style>
And you can add same code into your css file
Thanks
Without [ng-cloak] when you run your application before angularJs rendering you will see some angular codes like "{{myngModel}} or something like this, when you put [ng-cloak] in your project on run you didn't see those codes until rendering complete .
[ng\:cloak],
[ng-cloak],
[data-ng-cloak],
[x-ng-cloak],
.ng-cloak,
.x-ng-cloak {
display: none !important;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>app</title>
</head>
<body ng-cloak>
</body>
</html>
I know that due to backwards compatibility with IE, Angular allows the use of an xmlns and using ng: instead of ng-, however it doesn't appear to be working with all directives in xhtml
<?xml version="1.0"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ng="http://angularjs.org">
<head>
<title>Test</title>
</head>
<body ng:app="MyApp">
<div ng:controller="FooController as foo">
<p>{{foo.text}}</p>
</div>
<script src="angular.min.js" />
<script>
var app = angular.module("MyApp", []);
app.controller("FooController", function () {
this.text = "Hello Angular!";
});
</script>
</body>
</html>
The above will just produce {{foo.text}}, but if I replace ng:app with ng-app (leaving ng:controller the way it is) everything works fine. I really like the consistency of using namespaces, so why doesn't ng:app work?
The ng:app syntax doesn't work due to the following:
The elements contained within the template are always created in the HTML namespace. Whilst this is probably fine for the fast majority of cases if someone ever uses AngularJS with another XML document like SVG this could cause some problems.
References
Directive templates are always created in the HTML namespace
XHTML pages with fail to load in Opera
AngularJS Developer Guide: Internet Explorer Compatibility
Your example works fine. Have a look here: http://plnkr.co/edit/mgUMZe09FSr1aALE6ddd?p=preview
Maybe your angular script is not included properly
<script/> should be <script></script> its not self closing html tag
I am trying to use ng-mousedown and ng-mouseup in concert, however ng-mousedown is firing twice and ng-mouseup is not firing at all. For example, the following code causes count to increment by two instead of going up on press and down on release:
<!DOCTYPE html>
<html>
<body ng-app>
<div>
<div style="background-color: blue; width: 80px;" ng-mousedown="count = count + 1" ng-mouseup="count = count - 1" ng-init="count=0">Click Me</div>
<div>{{count}}</div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
</body>
</html>
If I change the Angular version to 1.1.1 it works as expected. Am I doing something wrong or is this a bug in Angular? I've tested in Chrome and Firefox. It works in Firefox, but not Chrome.
Update: After further testing it appears that this may only fail to work in Chrome on Linux 64. So it might be a bug in Chrome.
I loaded the test file into Chrome directly and found it worked as expect. When I compared it to the one loaded via my local webserver, I found the following line injected into my HTML:
<div id="__ngBatarangElement" style="display: none;">{"id":1,"time":18.12599998083897,"event":"scope:apply"}</div>
That made me suspect the AngularJS tab in dev tools. Sure enough, disabling it "fixed" the page:
What is more disconcerting is the fact that I distinctly remember choosing not to install Batarang due to the nearly universal negative reviews. I guess I will have to add mine to the pile.
Update: Found that the issue has been reported https://github.com/angular/angularjs-batarang/issues/205
I am displaying an image with ng-src:
<img style="width: 100px" ng-src="{{absolutePath}}customImages/{{currentBook.idcode}}.png"/>
which is found and displays fine, however in Firebug console, I am getting this error:
NetworkError: 404 Not Found - http://localhost/learntracker/customImages/.png"
as if this is being executed before the variables exist.
This HTML code exists inside a <div ng-cloak ng-app="mainModule"> and ng-cloak I understand to stop any executing before the variables exist.
Why is this error occurring and how can I suppress it?
Looks like you might be loading the data which populates currentBook object asynchronously. So during the previous digest cycle, ng-src directive would have rendered the src for the image with no value for currentBook.idcode and once it gets populated on the scope, another digest cycle runs updating the image. So the previous causes the 404. You could place an ng-if on the image.
ex:-
<img style="width: 100px" ng-if="currentBook.idcode"
ng-src="{{absolutePath}}customImages/{{currentBook.idcode}}.png"/>
You could see an small demo implementation here
But this seems to have been fixed with 1.3.x version of angular, in-order to prevent rendering of image src before all the interpolations are expanded to get values. Plnkr
ng-cloak is only helpful not to expose interpolation expression briefly while the angular is loading.
Some additional info (Courtesy #zeroflagL ) :
With angular version 1.3.x ng-src makes use of all or nothing interpolation (feature addition to interpolateProvider), meaning it will not expand the directive unless all the bound interpolations are resolved. You can see this mapping in the compile provider source.
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
What you might want to do in this case is to actually have a function on scope that creates the ULR for the image path:
<img style="width: 100px" ng-if="currentBook.idcode" ng-src="getImagePath(currentBook.idcode)">
var absolutePath = 'somepath/';
$scope.getImagePath = function(idcode) {
return absolutePath + 'customImages/' + idcode + '.png';
}
I am attempting to create a SPA using AngularJS as the main view for my website. I'm using ServiceStack on the server-side and can therefore cleanly serve HTML or JSON requests depending on what's accessing it. My main concern is the use of script blockers, preventing AngularJS from rendering the page properly. So far my main way of working is to render static pages, and inject a small script that redirects to the AngularJS-powered pages if it detects if Javascript is enabled. This works great since every URL works fine when the user begins at the static pages, but I've ran into a couple of snags.
Browsing to a link which includes the "?View=SPA" breaks the page if JavaScript is disabled
This causes the first page loaded to be loaded twice.
I'm looking for an alternative, but so far I haven't found any clean solutions. I was thinking about including the "?View=SPA" as a POST variable, but I'm still iffy on that implementation.
Any thoughts?
Instead of redirecting to an other page, I would implement both cases in the same HTML File as follows:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<style>.hideIfNoScript {display: none}</style>
</head>
<body ng-app ng-init="msg = 'hello world'">
<input class="hideIfNoScript" ng-model="msg" />
<p class="hideIfNoScript">{{msg}}</p>
<noscript>
<p>Content without javascript</p>
</noscript>
<script type="text/javascript">
var myEl = angular.element( document.querySelectorAll( '.hideIfNoScript' ) );
myEl.removeClass('hideIfNoScript');
</script>
</body>
</html>
The CSS Class hideIfNoScript in the head section makes sure that all HTML Tags with this class are never shown to the user, if javascript is disabled.
The noscript tag shows the alternative content.
If javascript is enabled, the little script at the end of the body section makes those elements visible. And in this case, the contents of the noscript tag are hidden.
Browsing to a link which includes the "?View=SPA" breaks the page if JavaScript is disabled
Hide those links by default:
a[href*='SPA'] { display: none; }
This causes the first page loaded to be loaded twice
Use a cookie on a browser-check page which loads the first page in an iframe or redirects to it to avoid this.
References
Track Non-JavaScript Visits In Google Analytics