Re-initializing Angular application on a specific event: Angular 5 - javascript

I'm using Angular 5 for building a web application and would like to know if I can re-initialize the entire application OR use something like:
ApplicationRef.tick();
to execute all the changes that happens after a specific event. The event is my scenario is authentication token renewal, because for some reason my application's change detection starts breaking unless I run each action inside
NgZone.run()
(I'm using ADAL for authentication in case anybody is interested), but when the token is renewed (using a hidden iframe) the application change detection, routing, etc starts breaking. But when the page is refreshed it starts working perfectly fine till the next time token expires and ADAL has to create an iFrame to renew the token. So I was thinking if at least I could re-initialize the application after the token is renewed so that user doesn't have to refresh the application manually (till I find a more solid solution).

You can call the change detection explictly like below.
constructor(private changeDetector: ChangeDetectorRef) {
this.someEvents.subscribe((data) => {
this.changeDetector.detectChanges();
} );
}
https://angular.io/api/core/ChangeDetectorRef

It's mandatory, if you are calling any third party API or executing third party library Codes. We need to manually call ngzone.run(), which will internally call ApplicationRef.tick() to notify angular to perform change detection from Application root component to the child component (i.e whole application).
ngZone.run(()=>{
// Adal callback Function
});
If you are need to trigger change detection only to the current component and their childrens (not whole application). You can use any one option.
1) setTimeout(()=>{}, 0);
2) this.cdr.detectChanges();
3) For Components with OnPush Change Detection Stratergy, you can call this.cdr.markForCheck() inside setTimeout();
setTimeout(()=>{
this.cdr.markForCheck();
}, 0);

Related

Rerun nuxt route middleware if store getter changes without reloading the page?

Given following middleware, whats the best way to rerun the logic when ever store.getters.authenticated changes, and not only on the initial load.
middleware/auth.js
export default function ({ store, redirect }) {
if (!store.getters.authenticated) {
return redirect({ name: "login" })
}
}
You asked how to rerun it inside of the middleware itself, which is the 2nd part of a possible middleware trigger (like if the user is not authenticated anymore while staying on the same page) and without any specific action, like when using polling or websockets I thought.
Meanwhile, the 1st part is the easiest: call the middleware globally (in nuxt.config.js) to trigger it on each page navigation.
If he stays on the same page, you can also move with the router as you did but at this point, checking if there is an error in your axios is maybe more appropriate since it's the initiator.
I also do like to use this.$nuxt.refresh() to trigger all the checks when switching accounts globally, helps re-running all those tasty fetch() hooks.

Subscribing to Angular router events from userscript

I am trying to write a Greasemonkey/Tampermonkey script which tracks URL changes. (similar to polling approach mentioned here)
However, I would like to extend a bit such that if the page has Angular I would rather subscribe the routing events instead of polling. (How to detect a route change in Angular?)
Is it possible to subscribe to Angular events from userscripts?
I am working with a script that looks like it is trying to do that in this block... but doesn't seem to properly detect the route.
const updateTragetOnState = (state) => {
if (state.vssNavigationState?.routeId !== "ms.vss-code-web.create-pull-request-route") {
// only work on create-pull-request-route
return;
}
For the record, that codeblock is not my own. It is a portion of a script sample submitted by Pei-Tang Huang for the purpose of working with modifying a pull request selection in Azure Devops. And in my case, it does not work.

Create-React-App - modify serviceWorker to poll for new updates?

I'm working on adding a requested feature to my SPA. We have some users who leave their tabs open to our application for long periods of time. We also push out frequent updates (sometimes 5x a day, as we're pre-revenue). I'm wondering if it's possible to modify the serviceWorker that comes installed with Create-React-App to run a polling loop (maybe every 10 minutes) to poll for new updates to the application, instead of only on initial page load.
This way, a user who leaves their tab open could receive update notifications without having to refresh.
Has anyone achieved something like this before, and know how I might implement that into the CRA serviceWorker?
Figured it out! In the registerServiceWorker.js file, I added a simple setInterval inside the callback for the navigator.serviceWorker.register() function:
// poll for live updates to the serviceWorker
pollingLoopInterval = setInterval(async () => {
await registration.update();
}, POLLING_LOOP_MS);
Easy!

angular ui-router - how to detect direct navigation to a state

I'm using $transitions to detect state changes and take some action based on the difference between some data defined in the 'from' and 'to' states. This is working great for me, but this code is not hit when the user navigates directly to a state via url. For example, browsing to mysite/search does not trigger this, but navigating within the site from the home page to the search page triggers this.
Is there any way to detect that the state was directly navigated to? That would allow me to execute the logic that I need to.
$transitions.onSuccess({}, trans => {
myFunc(trans.$from().data, trans.$to().data);
return true;
});
My problem was that I didn't register the transaction early enough; it was in a service that wasn't loaded until after transitions were handled for the initial launch of the app.

Backbone js prevent url hash change when back/forward

I am working on a very basic SPA using Backbone.js. My app has few routes. Among them there are 2 that give me issues: the index route ("/#index") and menu route ("/#mainmenu").
A simple workflow in my app is as follows: the user fills a form -> clicks to login -> trigger ajax request -> if login successful go to "/#mainmenu" route. if login failed, remain on "/#index" route.
On "/#mainmenu" if the user clicks on logout -> ajax request -> if logout success go to "/#index". if logout failed remain on "/#mainmenu".
The issues that I am struggling with are:
A clean way to trigger transition to "/#mainmenu" after successful login (I currently use router.navigate("mainmenu", {trigger: true}); but read that should avoid using this approach, in derrick bailey's article https://lostechies.com/derickbailey/2011/08/28/dont-execute-a-backbone-js-route-handler-from-your-code/ )
A clean way to prevent the user to go back to the "/#index" when pressing Back button in the browser from "/#mainmenu" route. I will also would like to preserve the url hash to reflect the current view.
Prevent the user to go forward to "/#mainmenu" after successful logout.
Is that even possible to prevent url hash change when clicking browsers back/forward buttons?
When I say "clean" I refer to "what are the best practices?". I partially solved some issues by saving url hashes and restore the appropriate hash (by router.navigate(currentRoute, {replace: true}); ) but I feel that it's a hacky approach.
Any feedback is welcome and much appreciated.
One way to solve this problem is by applying an async before filter on the routes that require an auth status check before the actual callback route is executed.
For example:
https://github.com/fantactuka/backbone-route-filter
The philosophy of avoiding {trigger: true} is based on the fact that when the router gets triggered with this flag, the entire initialization procedure for that route gets triggered. You will lose the benefit of having previously defined appstates because the app will have to re-initialize all content while this work had alrady been done before.
In practice, I think that it is useful to assess what your web app actually does. If losing appstate isn't an issue because the views you want to render are entirely new, then I don't see a problem with creating a client side redirect that re-inintializes your app.
If, on the other hand, your app has many views already rendered for which you want to maintain the same state as before, you can listen for an auth state event on each component that requires it, and make only those views re-render accordingly if they need to.
I don't think there's anything wrong with triggering routes, have been doing this without any issue for 2+ years. It all boils down to your requirements, read the article looks like a lot of work to me.
There are multiple ways to do this. First, you can disable back/forward buttons using window.history.forward(). Second, my favourite, is to do the processing in Router#execute. A sample might look like :
execute: function(callback, args, name) {
if (!loggedIn) {
goToLogin();
return false; //the privileged route won't trigger
}
if (callback) callback.apply(this, args);
}

Categories