I'm working on a page that has to run on an embedded android system (in the system webview), and this thing is tragically slow. So slow in fact, that when you load a page, somtimes the model text is still on the page for a good half second before AngularJS gets around to updating all of the bindings. This is annoying and clearly undesirable.
I've added ng-cloak to endless permutations of elements of the page. I've also added the following style to the style sheet:
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
It just doesn't want to cloak the contents, and I think ionic is to blame. Not knowing a lot about AngularJS, I tried writing a directive my-cloak that added a class to the element on compile and pre-link and removed it on post link. It worked better, but it didn't work always.
I've read about some more things I could do like "decorating" the interpolation function (getting out of my depth) and maybe one of the various suggestions listed here (like evalAsync or something like that) but I don't know enough about Angular to understand what those solutions actually do. Coming from a jQuery background is very hard when transitioning to AngularJS.
So any help would be really appreciated. I just want to prevent the undigested text from ever showing on the screen, basically doing what ng-cloak is supposed to do but for slower systems. Thanks!
This is not an answer you are looking for, but there is a good practice to write
<span ng-bind="data"> </span>
(so no {{data}} blinking).
ng-cloak styles already on the page. Look in the header of rendered page with angular app.
you can do something like:
<body ng-show="loaded"></body> and set scope.loaded = true in controller, after data is loaded.
Related
My first attempt at a PWA is here:
https://flowster.app/calculators/freight-class-calculator/
And I'm trying to get 100% in Lighthouse for all the categories :)
I read the "Learn More" page but couldn't understand how to deliver Bootstrap CSS inline, for example.
Any suggestions?
What this means
“Eliminate render-blocking resources” means that all resources (CSS/JS) which are required for the first view (top fold) should be part of the html itself (inline or script or style block); all the other CSS/JS (which is used somewhere below) can go to their other separate files;
This way, the browser will be able to paint/render the first view quickly and then go on to load the other CSS/JS files;
How to go about it
I went through this myself and realized that within the bootstrap.css i was hardly using 15% of the classes... you may also get the hint of unused css classes within lighthouse also. So this is where you can selectively include only relevant classes in your HTML;
JS will be trickier. Going on, to make this first view functional, you can insert vanilla Javascript (inside the HTML) for the navigation, carousel etc. which is better/faster than bootstrap.js;
hope it helps... Good luck
You should only load the CSS and JS in the head that are actually required to load the current 'view' (I deliberately did NOT say 'page'). This does NOT mean that you should inline them. You can perfectly load them from a CSS or JS file. You should load the rest of the CSS and JS in the footer (CSS or JS files are fine here too).
In the case of a single page application (SPA) that is also a progressive web app (PWA), this is only your opening/splash screen... easy enough. It should be very easy to get a 100% score on that. But, when you are talking about a website in which it is unclear what the 'first page' is... it becomes an almost impossible task. A clever CSS in JS or inline solution could do the trick, but would be quite difficult to build.
There is however a much easier solution for websites. I wrote how to get a 100% Google Lighthouse score, which focusses on websites only. TLDR: just omit the frameworks. It might not be a solution for every case, but for those situations where it is possible, it is definitely the way to go.
We have a complex AngularJS-based application with different loaded stylesheets. I need to print the separate page with nice styling, exactly how it looks in the browser, plus several elements need to be opened via ng-show for the print.
Looking for potential existing solutions, I've found the following AngularJS directive: https://dzone.com/articles/building-simple-angularjs. I had to slightly update it to load css stylesheets. Eventually, when I click the Print button, I can generate the huge HTML file with css references in <head/>. Being posted directly into browser, it looks more or less nice, but:
Ng-show /ng-hide are fully ignored, and that is expectable. How to deal with it?
Mostly important - when I try to Ctrl-P this HTML, it doesn't looks nice in preview at all. What I'm doing wrong?
I am working on a simple Cordova app with about 4 page types and I am trying to think through which is the better way to handle the inner HTML templates.
Hidden HTML hard coded into the HTML files that is hidden and populated/revealed by my JS.
Using a JS template system and appending and removing from the DOM.
I feel that appending all that to the DOM for a page is inefficient when I could just update the sections that change. But perhaps an append is lightweight enough where I shouldn't worry about it.
There are a number of ways you can do it. In terms of load on the browser. That is hard to say. From your question it is hard to know what is in these pages, what are you displaying, is it live data, static html etc.
When you first plot out an app, if you are from the old class of building multiple page websites, it can be a little concerning as to how well your app/page will run with all those pages crammed in to one, and all that data plus code.
The answer is, amazingly well. If done properly in modern browsers, and for example Ipads the app will run to near native performance.
The options you have are
Map all the pages into one HTML document. Hide each page content using css display:none, flip them into view using css animation, fading or just display:block.
Use a javascript routing library to map urls to blocks of code that deal with each page, this makes mapping out your app much easier, and means that buttons can just link to your pages, like a real website. see http://projects.jga.me/routie/
Building all the page templates into one page can make it hard to code, as the page becomes enormous, consider breaking the inner content of each page into separate files, you can then give each page holder a url and use a small xhr request to load the page on-the fly, once loaded you can cache it into memory or even local-storage, depending on whether you remove it when it is closed or keep it hidden.
In my experience you can put an enormous number or nodes into one page and have very little speed drop, bear in mind if you use something like jquery and do a lot of $(".page > .page1 > .items li") your going to have a slow app.
Tips
Use element ID's everywhere document.getElementById(..) is 100's of times faster in a loop that $(...)
cache elements when you find them, if you need them later store them in a memory cache.
keep for loop inner code to a minimum.
use a decent click touch libary like http://hammerjs.github.io/ and delegate all the events of the body tag or at least on each page.
If you need to touch the server, load data, think dom first, device second server later. A good app is a responsive app, that responds to the user instantly.
I know this has been posted a while ago, but for the sake of the users I am going to add my answer.
I completely agree with MartinWebb but my answer will shed some light on the results of his options. I am currently working on a similar project. Please note that this answer pertains to cordova (previously called phonegap) specifically. My app has about 5 pages with +-20 different components (input's, div's, h1's, p's, etc.). This is what i tried and the result of each:
jQuery was my first option, mainly because it is easy to use and reduces the amount of code required to accomplish a said goal. Result: First time I tried this approach I though I would spice it up with animations and transformations. The result of this was a very unresponsive app. I removed the animation and transformation, however due to the nature of my application I required multiple dynamically added components and jQuery just wasn't up for the task.
Css display:none and visible:hidden was my next option. I used javascript's dom to display certain div's. Result: This works if your not planning on switching many div shortly after one another eg. a simple menu. It quickly became apparent that this wasn't going to work. Also this does not eliminate my need for the dom. Remember document.getElementById('menu').style.display = "none"; is still part of the dom. This as a solution, for me, is poor. There is a reason that var menu= document.createElement('div'); is part of the language. Which brings me to my last option.
Building a page 90% on javascript's dom was my last option. Logically I could not see how 600 lines of code cold trump one .innerHTML or .style.display = "block"; but it did. Result: It was by far the most responsive of all the solutions.
I'm not saying that all webpages should be coded with dom appending, but as I stated previously, for a cordova app of a few pages (<6), with a few components a javascript dom appending approach would be best. It takes longer to code, but you will be rewarded with control and efficiency. I would suggest coding the backbone of your app in html and populating and controlling with javascript's dom.
Best of luck.
The first option, <div>s with display:none; would be more efficient by a small margin, but you can get the best of both worlds by compiling your JavaScript and templates together into a single file using something like browserify or require.js.
We just updated portions of our website with AngularJS - particularly the login page. When I look at the search results in Google, the cached page and the small snippet it displays automatically is the raw Angular markup. So, lots of {{model.username}}, {{model.errorMessage}}, etc.
I won't link the results since it's too embarrassing.
Any idea of how do get Google to actually store the page as rendered vs. the raw HTML?
It would be wonderful if you would convert your embarrassment into a community service for all of us by testing something, since you are seeing a condition few people admit to or want to reproduce themselves. :)
Google is known to be relatively (or very, depending on who you ask) good at ignoring hidden content. They implemented this way back when people used to keyword-stuff content by using blocks that were either set to "display: none" or had a tiny/unreadable/white-on-white font.
What you're seeing is a problem for more than just SEO, so I'm suggesting this because things like prerender.io are great but they only solve that one piece. What about users who simply have slow browsers? Well, it turns out Angular has a great solution for this called ngCloak. It hides things like template content fields (ngModel mappings and bindings, expressions, etc) until Angular is ready to fill them in itself.
It's very easy to implement this; you just need a small block of CSS (in an early-loaded file, or embedded directly into your HTML page):
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
and then you apply the ngCloak directive to items that are affected, or to a high-level parent (like your ng-view DIV):
<div id="wrapper" ng-cloak>
<!-- Page content here -->
</div>
This works kind of like a no-js target, but specifically for AngularJS.
You'll still want something specific to give Google that is actually good material, but at least with the above you can filter out everything else.
SEO for angular is a really big question/issue depending on your perspective. I would start by reading http://www.ng-newsletter.com/posts/serious-angular-seo.html and http://www.yearofmoo.com/2012/11/angularjs-and-seo.html to get you started.
To sum up your primary options:
change your routing system to use the hashbang (#!). Then sites like google and facebook will convert the hashbang to _escaped_fragment_ before querying your page. This gives your server an opportunity to return different html.
use a service like http://prerender.io which will pre render and cache rendered versions of your site for you, which will be provided to google in place of your site.
There are still issues with things like sharing to reddit and stumbleupon for example, as they are lazy and don't want to develop to cater to angular based sites. So for certain circumstances you will have to get creative.
Update: One thing we have done on a recent project is look at the various user agents to determine if crawling systems are asking for page information. This way we can serve what ever we like.
I'm trying to adapt a jquery-ui codebase to use RequireJs, and I'm deploying it on a much slower (but scalable) virtualized cloud service than the dedicated host I was using before.
My pages are by default an ugly catastrophe of vanilla HTML. The only thing that brings this mess to life are calls to JavaScript functions, which give it the appropriate tab controls and layout. In fact, the page is laid out long and vertical...one section after another...before I call the .tabs() function which folds them up into a single unit with a horizontal control.
(Fairly confident I'm "doing it right" in the jQuery UI mindset. By not building the whole UI through code to start with, it can be at least looked at with JavaScript disabled. Though I doubt anyone is still using Lynx, there are issues of accessibility...or making sure your content is analyzable by search engines. I'll spare you my old man speech about how this is an absurdist way of achieving content/UI separation. :-/)
When I was using <script> tags to load my 3rd party library dependencies and the $(document).ready to run the jQuery UI voodoo, the user never saw the vanilla ugly HTML. Now that I'm using RequireJs, the page.js file lags and loads asynchronously after the HTML...waiting for libraries that aren't really needed for the DOMready handling. The slower server makes this look really awful.
I could of course use CSS styling to hide the ugliness at the outset, and overlay with a "Loading..." graphic until the UI was ready. That's what came to mind first, and a similar approach is suggested here:
Jquery UI interface looks ugly before document.ready
(Note: It seems like such a common problem that I'd almost think there'd be a RequireJs plugin that went ahead and did this. Is there?)
In any case, I didn't seem to have to worry about this before...and I'm wondering if I'm missing some simpler solution. How do you keep users from seeing "ugly" HTML if you're using RequireJs?
I'm with you that you should do some CSS wizardry and then in RequireJs's "kick it off" script, hide it. You should also consider SEO impact and JavaScript disabled scenarios.
Remember, at the end of the day, it's just HTML, CSS, and JavaScript. What ever templating / code generation system you use to get you there, at the end of the day, it's just HTML content, styled with CSS, and animated with JavaScript.
I'd argue that it makes more sense to use something like node-browserify to do all of your Javascript module requires and then stream down the single JS file to the end-user.
Why go through all of the TCP handshakes and HTTP headers to get the same thing at a much lower performance when the client is obviously not intended to be run in an offline mode?
Hey Doc, it hurts when I do this.
Well, then don't do that!
I'm having the same issue with Jquery Mobile and RequireJS.
I first tried following this tip and hid the "ugly HTML" by adding CSS:
.requireJS-init { visibility: hidden;}
.requireJS-init.done { visibility: visible;}
and assiging .requireJS-init when the page fires up and removing it once everything has been loaded by adding another class done (you could remove the initial class, too I guess).
However this causes two problems:
1. Users might have a blank page for a while depending on your content being loaded
2. IE8 fails, because (in my case) Jquery Mobile tries to focus on elements while they are still hidden.
I tried moving around the class form HTML to BODY to elements holding the page content, but nothing really worked.
A much easier CSS-only solution is this:
.ui-mobile-rendering:before {
width: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: block;
height: 100%;
z-index: 0;
background:#fff url(../images/ajax-loader.gif) no-repeat center center;
content: ""
}
The ui-mobile-rendering class is on the body while JQM does it's widget enhnacements. Once the page is done, the class is removed. By adding a fullscreen :before - in this case with the JQM loader as background image - you hide everything on the page until it's rendered. No need for visibility:hidden, IE8 doesn't complain (thank good, IE8 and FF3.6 know :before).