How to preload Ionic components in v5 - ionic-framework

We have an Ionic5-Angular app that is also being deployed as a web app. It’s nice that Ionic lazy loads all of its components - it greatly reduces the bundle size. However, we’re running into issues when it comes to user interactions that trigger lazy-loaded components.
As an example, we have a button that triggers a Dialog. When deployed, there is a noticeable delay between tapping the button and the dialog being displayed. When tested on a slow 2G internet connection, it took nearly a minute for the dialog to display. Once it has loaded once everything is fine but we are finding that the more impatient users are tapping the button several times because it looks broken.
I want the web browser to download the Ionic component together in advance while downloading the web page not when it’s requested.

I don't think you can preload individual components, but you can preload modules. Use Angular's PreloadAllModules like this:
import { RouterModule, PreloadAllModules } from '#angular/router';
...
RouterModule.forRoot(
appRoutes,
{
preloadingStrategy: PreloadAllModules
}
)

Related

How to calculate page loading time in Ionic 3 (single page app)?

I am creating a function that calculates a page loading time for each page of my Ionic 3 App (I use lazy loading). However, I am currently stuck in issues:
When does the page start creating HTML?
When does the page finish creating HTML?
When does the page complete downloading all resources on the page (image, etc …)?
Can anyone give me advice?
One thing to look at is https://blog.ionicframework.com/navigating-lifecycle-events/ this contains the ionic life-cycle eg. ionViewDidLoad(): Fired only when a view is stored in memory. This event is NOT fired on entering a view that is already cached. It’s a nice place for init related tasks.
Ionic 3's pages are also angular components so I'd imagine the another thing to look at is the component hooks. These methods are fired when in the stages of the component life cycle.
https://angular.io/guide/lifecycle-hooks
https://www.intertech.com/Blog/angular-component-lifecycle/
eg. ngAfterViewInit(){ stopTimer() } //this method is fired once Angular initializes component and child component content
To achive what you want you could have a provider that both pages link to. When you change page start a timer and stop it using ngAfterViewInit() or other more appropriate hook.

Ionic 4, Angular Navigation and Android Back Button

How do I implement Ionic 4/Angular navigation in such a way that the user CANNOT navigate backwards though their entire experience (screens) on the application?
I've ported my Ionic 2 application to Ionic 4, and feel like I've lost some critical navigation functionality.
Specifically: as a user moves forward in the application, and bounces around the different areas of my application, they are now able use the Android back button to navigate backwards through the FULL HISTORY of their previous screes. Whereas previously Ionic would STOP them moving backwards once the user hit a root page.
For example, a user would navigate from the main Welcome Page, then to the main Products page, then to Product Details page, then to the main Orders page, and then Order Details page. Then, if they start to use the Android back button, they're allowed to navigate through the entire history of screens, all the way back to the Welcome Page.
Previously, they would be force stopped at the last root/main page (e.g. the Orders page).
I don't think I had to use any application specific logic to dynamically disable the Android back on the main pages. I think the previous versions of the Ionic framework was smart enough to stop going backwards too far.
How do I implement Ionic 4/Angular navigation in such a way that the user CANNOT navigate backwards though their entire experience (screens) on the application?
I understand that ionic 4 uses angular's routing.
I am NOT asking to disable the Android back button.
This is a much simpler solution that has been working for me. Essentially you just have to tell ionic/angular when you are about to navigate to a root page and then it will stop the back button taking you past it.
import { Router } from '#angular/router';
import { NavController } from '#ionic/angular';
...
constructor(private navCtrl: NavController, private router: Router) { }
...
this.navCtrl.setDirection('root');
this.router.navigateByUrl('/new-root-page');
In ionic v4 this seems to work fine:
in app.component.ts inside initializeApp() function add the following:
initializeApp() {
this.platform.ready().then(() => {
this.platform.backButton.subscribeWithPriority(9999, () => {
document.addEventListener('backbutton', function (event) {
event.preventDefault();
event.stopPropagation();
console.log('hello');
}, false);
});
// here put instructions for splashScreen, statusBar, etc.
});
}

Global component Ionic 3

I'm developing a PWA on ionic 3 with Angular 4 and I've failed multiple times trying to make a nice UI that show's in-app notifications about events.
I have a NotificationsService that is responsable for everything that has to do with getting the notification from Firebase.
My initial approach was to define a UI component (a.k.a notification-box) which would observe a property in the Notification Service and consume the notification provided by the service and display them nicely on top of the screen.
This sounds all nice and good but I created this component and had 3 issues:
Ionic 3 doesn't allow (AFAIK) a component to be 'global' and present in all app pages.
Including the tag of my component <notification-box></notification-box> on top of every page it's not a very good idea because components get instantiated and destroyed multiple times making it difficult to keep Subscriptions to the Observable notification property in the Service, and this could lead to a notification not arriving in between switching of pages.
If a notification where to arrive with a modal open, the notification would display behind the modal and my intent is to show notifications always on top.
I ended up using ToastController from ionic-angular which always displays on top no matter what (although it's a bit ugly and I want to switch to something like angular2-notifications).
How did Ionic achieve this "always on top" behaviour? Is there any way I can replicate that with a class of my own or Extend the ToastCtrl?
You can achieve what you want via provider and yes you will still need to inject such provider into every page that you want to see notifications in. You don't need to modify those pages' view (html templates) though.
I had similar need (to present "toast" inside of the app regardless of pages).
I solved this by making this provider a singleton provider (means we declare it at the app.module.ts in providers section) that is injected into every page (import and add to constructor):
import { Injectable } from '#angular/core';
import { ToastController } from 'ionic-angular'
#Injectable()
export class Toaster {
constructor (private toastCtrl: ToastController) {
}
presentToast(message, position, cssclass) {
let toast = this.toastCtrl.create({
message: message,
closeButtonText: "OK",
showCloseButton: true,
cssClass: cssclass,
position: position
});
toast.present();
}
presentSimpleToast(message, position) {
let toast = this.toastCtrl.create({
message: message,
duration: 3000,
position: position
});
toast.present();
}
}

Reduce initial load time - google web designer

We are developing some ads using google web designer tool
so far its good but one main issue with it is, slow loading.
its taking almost 3 seconds to load and we feel very bad about that.
can anyone know how to optimize it?
thanks.
In developing html5 banners, by default the 'polite load' is checked.
Which means you banner will not be visible and will not load until the page is loaded.
And when testing your banner, there is some moments before showing the banner to simulate the webpage load.
Why?
Because no publisher(Website) allows you to make their website slow. That is the rule. There is no way for you to force yourself to show first on a publisher website.
If you want this option. You should directly talk to the publisher/ when you get approval from them, you can uncheck 'Polite Load' when you are publishing your ad. Then your banner will show faster without any delay.
#cnu - I have experienced the same issue. The only workaround I have at the moment is to set an initial loading image - while the Ad is loading
Try adding a div with an ID of 'loading' immediately after your opening body tag.
<div id="loading" class="loading-image">
<img src="default.png"/>
</div>
Then find the following function, and set the div to block display
function handleDomContentLoaded(event) {
// This is a good place to show a loading or branding image while
// the ad loads.
document.getElementById('loading').style.display = 'block';
}
Then find the following function, and set the div to none - to hide the image after loading
function handleAdInitialized(event) {
// This marks the end of the polite load phase of the Ad. If a
// loading image was shown to the user, this is a good place to
// remove it.
document.getElementById('loading').style.display = 'none';
}
The official GWD instructions don’t match the functions actually generated in the source, which initially made this setup confusing. The code comments in the source indicate these are the correct functions to use. You can use the first frame of the Ad as the loading image, rather than a loading gif - so the user experience isn't affected too much.
Hope this helps.

Prevent cached iPhone webapp from reloading (scrolling to top)

I have an iPhone webapp that uses a cache manifest to work offline. I add the webapp to my home screen, use it (say scroll to a certain location on a page), then go back to homescreen.
When I open the app again, for a brief moment I see where I used to be (at that scrolled location on that page), but then the app "reloads" and I get scrolled to the top of the mainpage. Is there a way to prevent this "reloading"? This happens even in airplane mode (ie everything is working off the cache).
You're just seeing the default startup image, which is just a screenshot of the last place you were at. It's not "reloading"; the app wasn't loaded to begin with.
Search for "apple-touch-startup-image" to set a real loading image.
What I'm struggling with here is that the app actually seems to stay "in memory" longer if I use regular Safari as opposed to running in "apple-mobile-web-app-capable" mode. In the later case something as simple as pressing the home button, then task-switching back to the app causes a reload. Doing the same thing just in Safari often does not reload. So I'm worse off by using "apple-mobile-web-app-capable".
I don't believe there is a real 'reload' event. onload and onunload are all we get.
the onload handler starts up as if it is your first time coming to the page.
the onunload handler is the key to clearing out old content.
I like to provide alternate content for people who are coming back to my web app.
window.onunload=function(){
document.getElementsByTagName('body')[0].className+=' unloading'
}
And let the CSS do the dirty work to hide most of the body and show alternate content.
(this answer does not rely on jQuery or other frameworks)
// on load
window.scroll(0,0);
To ensure no old content is displayed while launching I use this in my page:
window.addEventListener('unload', function() { $('body').hide(); } );
Thus the last state of the page is empty and is what is shown to the user when the page is opened again.