How does a publication onStop callback work in Meteor? - meteor

Following the Meteor documentation, the onStop() function do:
Registers a callback function to run when the subscription is stopped.
Right now, I try to keep track of a user leaving a page using this onStop() function within my publication.
I expected it to work directly since the subscription is called in the template route controller and my published collection isn't available once the page is left. But I am here because even if the publication is no longer active on client, the onStop() isn't triggered. I am not sure to understand how it works, so here are the questions:
Is a publication onStop() triggered if the user leave the route it is attached to?
If not, is there a built-in Meteor mechanism to stop unused pub/subs? If yes, how does it work? Is it a timeout?
Is it necessary to use a Cursor.observe() or a Cursor.observeChanges() to use/trigger the onStop() callback?
Why is the onStop() callback not triggered when I close the browser or the tab, or logout from my current user account?

I discovered that it didn't trigger the onStop() because I had to move my publication query after the onStop() (since the query is behind a return).
However, since my questions might interested some people, here are the answers:
Is a publication onStop() triggered if the user leave the route it is attached to?
Yes. It stays true whether the user goes to another route of the website, close his browser tab or runs out of battery.
Is it necessary to use a Cursor.observe() or a
Cursor.observeChanges() to use/trigger the onStop() callback?
No
Why is the onStop() callback not triggered when I close the browser or
the tab, or logout from my current user account?
The fact is that is is triggered in all these cases. Here is how could look a basic publication with onStop() that I use to handle uploaded files deletion when the user does not fill up the related form and leave the page without submitting:
Meteor.publish("files", function(sessionId) {
var self = this;
// Here I clean all the files I need to remove because the user has
// not submitted the current form.
self.onStop(function () {
console.log (sessionId + " is cleaning...");
cleanFiles(sessionId)
});
// I look for files related to the current upload session only
if(Users.isInRoles(this.userId, ["user"])) {
return Files.find({"session_id":sessionId, "owner":this.userId}, {});
}
//and I make my publication available in case the if failed
return self.ready();
});

Related

Testcafe-redirecting issue

We are trying to test a page which at one point redirects the execution to another page for login credentials. After this we need to go back to initial page and continue from where it stopped before redirection.
How can I achieve this?
I tried with roles but this wouldn't keep the data on the initial page and instead reloads the page which then is empty. Also with roles you always go back to same page.
Any suggestions?
Using the roles mechanism is the only built-in way to save and restore cookies/storages. Each role has its role constructor with the initialization function. Cookies and storages are saved only after a role is initialized. It means that you can try to use a role for the first part of your test and save the page state:
const role1 = Role(basePage, {
// do smth
});
const role2 = Role(loginPage, {
// login
});
test('test', async t => {
await t.useRole(role1); // state is saved
await t.useRole(role2); //
await t.useRole(role1); // state is restored
})
If this approach does not meet your needs, you can try writing some custom logic to save/restore the state. Please follow this link https://github.com/DevExpress/testcafe/issues/2142 to see an example of a custom solution of how to save/restore localStorage via CustomFunctions.
 
There may be some design considerations worth making in the app itself, perhaps some usage of local or session storage is in order. Testing aside, wouldn't the user also experience this disappearing data if they manually reloaded, for whatever reason?
In my experience with TestCafe, there were instances where I had to do more in each test than I cared to, to workaround similar issues, including times I couldn't use roles and simply cooked up my own reusable login function that I called here and there.
That seems to be one of the limitations with TestCafe in conjunction with testing such functionality (the SPA paradigm, which perhaps this is). It's going to reload pages, but if I remember correctly there was a discussion about it in their issue tracker, so it may be worth browsing there as well if you haven't already.

Meteor - Execute code on every page load

I want to execute a function when any page loads.
Things like Meteor.startup() and Template.myTemplate.onRendered() are not what I want because they are triggered only once, when the app is loaded.
Basically I need an event that is triggered every time the URL changes, is there one?
You can use onRun or onBeforeAction to run arbitrary code on every route change.
Router.onRun(function(){
console.log('onRun', this.current().route.getName());
this.next();
});
Router.onBeforeAction(function(){
console.log('onBeforeAction', this.current().route.getName());
this.next();
});
Use this placeholder code to detect when this code will actually run.
onRun will run only once on every route change. (good for analytics related stuff)
onBeforeAction will reactively rerun when the current route data context is modified.

Capture cancelling event for Google Sign-in web

I am implementing google Sign in for my web application as describe in https://developers.google.com/identity/sign-in/web/sign-in. Instead of embedded "Google Sign-In button", I made a custom button which trigger a click event to this function "GoogleAuth.signIn()" as stated in Reference. Everything working fine, if user click the button and proceed with the sigin flow. However, the problem was after the button is clicked and the singin window is shown. User now decided to cancel the singin, but no api function call can be use to capture this event and response accordingly to this user action.
https://developers.google.com/identity/sign-in/web/reference#googleauthsignin
You can check whether Promise returned by GoogleAuth.signIn() has been resolved (which means successful sign-in) or rejected (one option is user clicked cancel).
function onFailure(error) {
alert(error);
}
function onSignIn(googleUser) {
alert(googleUser);
}
auth2.signIn().then(onSignIn, onFailure);

How to reset Meteor AutoForm validation when leaving form page?

We have a site with several AutoForms on different pages / routes. If a user triggers validation on a particular form and triggers some validation errors, and then leaves the page with that form, when they return to that page later on the data they have entered is gone, but any validation errors remain (fields are highlighted and validation error messages are shown).
How can we reset the form validation when a user leaves the form page?
I know we can use AutoForm.resetForm('our-form-id') to do the reset, and this works in the console, but I can't find the proper hook to hang it on. The onStop IronRouter hook for the page would seem to be the right place, but that triggers an error Can't call Tracker.flush while flushing. If I wrap it in a setTimeout with timeout 0, so it doesn't run until the next tick, it has no effect (presumably the template is destroyed by that point).
I would think when the template is destroyed the error state would be, too, but its not. Is there an undocumented way to "hard" reset errors even if an active template no longer exists?
We are using AutoForm 4.2.2.
You can reset the validations using
AutoForm.getValidationContext('form-id').resetValidation();
You need to use your router's exit hook to resetValidation, but you have to first get the context for your form. Here is how it is done in FlowRouter:
FlowRouter.route('/edit/:_id', {
name: 'editPage',
action: function() {
BlazeLayout.render('appLayout', {main: 'editPage'});
},
triggersExit: [function() {
AutoForm.getValidationContext('edit-form-id').resetValidation();
}]
});
For more information on flowRouter triggers see https://github.com/kadirahq/flow-router#triggers

Showing page load progress with JavaScript

I am retrieving a list of files from a web service and displaying them as links. When someone clicks on the link, the file should start downloading. The problem is that no direct access to the file exists. Here is the process to download a file:
User clicks on link
Server calls web service to retrieve file
Browser is loading for as long as it takes to bring the file back from the web service
Browser finally offers file to user for download
To counter the unfavorable user experience of having to wait for the web service before the download starts, I would like to display a "Loading..." feedback dialog when a link is clicked, and have the dialog go away when the file is ready.
I am using jQuery, and have been playing around with adding an iframe to the page to load the file, but the problem I am having is I don't know how to determine that the file is ready.
I am looking for tips, not only on the client side to give ample feedback, but perhaps also on the server side (using ASP.Net), just in case I can do something to streamline the process. Thank you.
Update: To clarify, this is for downloading a file to a user's machine. What I'm specifically looking for is a way to determine when the file is ready for download. So, when step #4 above takes place, I'd like to remove the "Loading..." message.
It sounds like you need to expose a new request URL on your server, whose only job is to reply whether the web-service-retrieval has completed (or if not, how far it has got).
Have AJAX poll that service every few seconds, and remove the "Loading..." message when it replied that the file is ready.
The client should send the session ID (maybe also a file ID), so that the server knows which file is being asked about. The server side will need to be able to contact the running web-service-retrieval process/thread to ask it how far it got. (If it can't find the thread then presumably it has finished.)
you can use the complete option for $.ajax function in jquery which should get called when the request completes
You can have jQuery to wait for the click of the link and when the link is clicked show the display loading message.
Example that shows how to 'Loading - Please wait' Message Display Script you can follow.
EDIT-
Basically you want a progress bar monitor, which I have never seen it done with just javascript, but with flash or ajax.
Here is a File Upload Demo that should help.
If you're linking to an ASHX that is grabbing the file and writing it back to a stream, you can modify the links click event to display a message.
$(function () {
$("a.someClass").click(function () {
$("div.message").fadeIn(); // show a loading message
return true; // make sure the link still gets followed
});
});
The loading message can just be a spinner or something while waiting for the ASHX to write the response back.
Edit: Since you're not directly linking to the ASHX:
$(function () {
var ashxCallback = function (data, textStatus) {
// data could be: xmlDoc, jsonObj, html, text, etc...
this; // the options for this ajax request
// textStatus can be one of: "timeout", "error", "notmodified", "success", "parsererror"
alert(textStatus);
};
$("a.someClass").click(function () {
$("div.message").fadeIn(); // show a loading message
$.get("some.ashx?id=1234", "", ashxCallback);
return false;
});
});
Using jQuery.get() and jQuery.post().
Edit #2: I just had another thought. What if the Loading... message was in an iframe that redirected to the file? So you would display the iframe with jQuery, it would have the default message of Loading... and a little spinner animation, then set the iframe's src/location to the ASHX that takes forever to load. You could then give it an onload handler from the iframe's parent page that would hide/remove it. Let me know if you need sample code.
If preparation for the file takes less than default timeout of AJAX request, you may start AJAX request, displaying "Loading..." message to user. AJAX call then checks for file's availability, and when it becomes available - returns with the message (success or not) and gives a link for the file. AJAX request can even do file download, but that's for your option.

Resources