Socket.io doesn't close connection on linking with reacter-router-dom - reactjs

As I have understood, Socket.io automatically disconnects on page refresh. However, when using react-router-dom, a disconnect message is not sent to the backend, how would one implement this? I don't think code is needed, however feel free to ask!

Try to handle the disconnection on window unload event in this way:
window.addEventListener('beforeunload', function (e) {
e.preventDefault();
e.returnValue = ' ';
});
window.addEventListener('unload', function (e) {
socket.emit('disconnection message', {data to be sent});
});

In that case you will have to handle it manually in your component using socket.disconnect(). react-router provides a SPA functionality and in that context, the page doesn't actually reload, otherwise you lose the current state and everything starts from scratch.

Related

Detect mobile browser close event for a mobile

I want to perform some operation when my application gets killed. Which method can be used for this? I am working on React Js.
Preventing the whole browser from being killed isn't possible, as that behaviour could easily be exploited by malicious scripts. You can, however, detect when the tab is closed.
Try the window: beforeunload event
window.addEventListener('beforeunload', function (e) {
// Cancel the event
e.preventDefault();
// Chrome requires returnValue to be set
e.returnValue = '';
});

Test fails because AngularJS has not initialized in time

I'm trying out TestCafe for an AngularJS (v1.6) application.
I have a button then when clicked, opens a modal (from UI bootstrap). This works fine when I try myself in Chrome.
<button class="btn" ng-click="open()">Open</button>
Our application requires user authentication, and the login page is not Angular-based. That phase of my test works fine.
However, when the actual test runs, it "clicks" the button but nothing happens.
I suspect, but can't prove, that it's clicked before AngularJS has properly initialized on the page.
With some research, I found the testcafe-angular-selectors project and a waitForAngular method but that appears to apply only to Angular2+.
import { Role, Selector } from 'testcafe';
const regularAccUser = Role('http://127.0.0.1:8080', async t => {
await t
.typeText('[name=username]', 'abc')
.typeText('[name=password]', '123')
.click('.btn-primary');
});
fixture`Characters Modal`;
test('modal title', async t => {
await t
.useRole(regularAccUser)
.navigateTo('http://127.0.0.1:8080/fake/page')
.click('.btn')
.expect(Selector('.modal-title').innerText).eql('Insert Symbol');
});
Adding .wait(1000) before the click solves the issue. It's not waiting for Angular to load. I'd rather not have waits in every test - is there some other technique I can use?
You can use TestCafe assertions as a mechanism to wait until an element is ready before acting on it.
A typical waiting mechanism would be:
const button = Selector('button.btn')
.with({visibilityCheck: true});
await t
.expect(button.exists) // wait until component is mounted in DOM
.ok({timeout: 10000}) // wait enough time
.hover(button) // move TestCafe cursor over the component
.expect(button.hasAttribute('disabled'))
.notOk({timeout: 10000}) // wait until the button is enabled
.click(button); // now we are sure the button is there and is clickable
This article may also help you in managing all those waiting mechanisms.
As you correctly mentioned, the waitForAngular method is intended for Angular only, not for AngularJS.
I recommend you create your own waitForAngularJS function and call it on the beforeEach hook and after the role was initialized.
In the simplest case, it can be implemented as follows:
function waitForAngularJS (t) {
await t.wait(1000);
}
fixture `App tests`
.page('page with angularjs')
.beforeEach(async t => {
await waitForAngularJS(t);
});
However, the use of the wait method is not a solid solution. I recommend you find a way to detect if AngularJS is loaded on a page on the client side. If it is possible, you can implement the waitForAngularJS method using the TestCafe ClientFunctions mechanism.
This post can be usefulĀ as well: How to check if angular is loaded correctly

Get user's response for beforeunload event if the user leaves the domain

I have an AngularJS app and use the following code to let the user confirm if s/he really wants to leave the page and might loose unsaved data:
window.addEventListener('beforeunload', function (e) {
e.preventDefault();
e.returnValue = '';
return 'Do you really want to leave?'
});
window.addEventListener('unload', function (e) {
console.log('unload');
myRestService.close();
e.preventDefault();
e.returnValue = '';
});
This works well and the browser displays the message box where the user has to decide to leave or to stay on the page. However, if the user really wants to leave the page, I have to make a call to a rest backend. For that I thought that I can also register for the unload event that is fired when the user actually leaves the back. That works if the user reloads the back or navigates to a different url within the app. However, the event is not fired, or at least I can't see it, when the user navigates to anthoer page or closes the browser.
How can I also catch these events and make sure that my rest call still goes through?
You can call a function before tab close like this:
$window.onbeforeunload = function (arg) {
$scope.onclose();
}
and now you can all your rest api in close function
for more detail and other methods follow this link

cordova back button event conflicting with browser history

I am making a cordova app, using angularjs and ui-router , the problem is when i use the cordova back button event ,my app doesn't go to the previous page, but if i comment the back button event everything works fine , i want to track the back button event but its seems not to work for me , i tried the below code also doesn't seems to help me.
document.addEventListener("backbutton", (e) => {
e.preventDefault();
e.stopPropagation();
}, true);
please help me with the issue
e.preventDefault() as it's name suggests prevents the default behaviour. Therefore you stay on the same page.
If you want to control route switches / state switches imho it's better to listen for the stateChangeStart event. There you can also prevent state changes and you have the extra bonus of knowing which state it came from and where it's going.

Preventing page navigation inside a Backbone-driven SPA

The justification
In my BB app, I allow rapid input from users which gets queued & sent off periodically in the background to the server. The problem I currently have is if a user leaves the page they effectively discard any pending changes sitting in the queue.
So basically what I want to do is inform the user before they leave to give them the opportunity to wait for the changes to be saved rather than just exiting & discarding.
The nitty gritty
So for the general cases where the user refreshes or attempts to navigate to an external URL we can handle the onbeforeunload event. Where it becomes slightly tricky is when we are in the context of an SPA whereby switching between pages does not cause a page refresh.
My immediate thought was to use a global click event handler for all anchors and validate whether or not I want to allow the click, which would work for in-site link navigation. However, where this falls over is navigating via the browsers Back/Forward buttons.
I also had a look at Backbone.routefilter, which at first glance appeared to do exactly what I needed. However, using the simple case as described in the docs, the route was still being executed.
The question
How do we intercept navigation for all scenarios within a Backbone SPA?
Direct link navigation
Use a global event handler to capture all click events
$(document).on('click', 'a[href^="/"]', function (e) {
var href = $(e.currentTarget).attr('href');
e.preventDefault();
if (doSomeValidation()) {
router.navigate(href, { trigger: true });
}
});
Page refreshing / external URL navigation
Handle the onbeforeunload event on the window
$(window).on('beforeunload', function (e) {
if (!doSomeValidation()) {
return 'Leaving now will may result in data loss';
}
});
Browser back/forward button navigation
Behind the scenes Backbone.Router uses the Backbone.history which ultimately leverages the HTML5 pushstate API. Depending on what options you pass to Backbone.history.start, and what your browser is capable of, the API will hook into either the onhashchange event or the onpopstate event.
Delving into the source for Backbone.history.start it becomes apparent that regardless of whether you are using push state or not, the same event handler is used i.e. checkUrl.
if (this._hasPushState) {
addEventListener('popstate', this.checkUrl, false);
} else if (this._wantsHashChange && this._hasHashChange && !this.iframe) {
addEventListener('hashchange', this.checkUrl, false);
} else if (this._wantsHashChange) {
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
}
Therefore, we can override this method & perform our validation in there
var originalCheckUrl = Backbone.history.checkUrl;
Backbone.history.checkUrl = function (e) {
if (doSomeValidation()) {
return originalCheckUrl.call(this, e);
} else {
// re-push the current page into the history (at this stage it's been popped)
window.history.pushState({}, document.title, Backbone.history.fragment);
// cancel the original event
return false;
}
};

Resources