Before I dive in too deep any guidelines on best practice for UI flows where the response is delayed from request? Ie, submit job, wait 10 - 45 seconds, get job response back?
Job would be calling out to a REST endpoint, I'd love to have a UI update when job is done.
With firebase for example you can surface job status asynchronously to let user know when report is ready. I see the binding to Cloud SQL, but not clear on how updates on Cloud SQL job record flow back to UI.
There is high probability that user will leave the app by the time when job is done, so you can consider notifying user by email with job result. For patient users you can show snackbar popup:
google.script.run
.withSuccessHandler(function() {
// set snackbar success text
app.popups.Snackbar.visible = true;
})
.withFailureHandler(function(error) {
// set snackbar error text
app.popups.Snackbar.visible = true;
})
.doLooongJob();
It seems that this article by material design appears to be relevant - https://material.io/design/communication/confirmation-acknowledgement.html#acknowledgement
Related
I am using the firebase-js-sdk and the stateChanges function to detect incoming changes.
In my database I store messages. After subscribing the first time to stateChanges the observer is fired for each message, and at the moment I reload the UI after each update. Is there a way to prevent unnecessary UI updates?
this.firebaseMessagesObservable$.subscribe((message: any) => {
this.update(message);
this.refreshUi();
});
i've been battling for a few days with an autorun function that renders elements on a canvas for two players in a board game. the whole process from when 1 player places a move until its visible for the other player took too long. i managed to cut alot by optimizing the code i have written as a meteor beginner, and also by placing the method that updates the game move inside a (meteor.isServer) so it won't first run the method in the move maker's client (it was already just inside the server's folder).
one delay in time which is beyond my understanding, happens from the moment the server finishes with the move making method until the client's autorun begin to run(about 60 ms delay for chrome, and 150(!) for firefox). i've ran some tests to try and narrow down the options for why it happens, the last one was to subscribe to the games collection from a different page, and see if the response time is slow there too. this is the code:
Template.Watch.onCreated(function(){
this.subscribe('activeGames');
this.autorun(()=>{
if(this.subscriptionsReady()){
console.log(Games.findOne().turn + " " + (new Date).getTime());
}
});
});
Template.Watch.helpers({
games: ()=> {
console.log(Games.findOne().turn + " " + (new Date).getTime());
return Games.find({result: false});
}
});
now, on the client both console.logs appeared whenever a move was played, the weird thing is that the helper's console.log was fired with no delay, 50 ms before the autorun's console.log which had the same delay as in the game page.
by my poor understanding, if the client knows a change was made to the database, the autorun should simply run, just like the helper simply runs.
i would be very grateful to whoever explains to me the behavior of the autorun that causes that delay, and if there is a way to cancel it.
Thanks in advance!
When you call a method on the client using Meteor.call, two things happen in parallel:
The client sends a request to the server to run the method in a secure
environment, just like an AJAX request would work A simulation of the
Method runs directly on the client to attempt to predict the outcome
of the server call using the available information.
So here is the reason why your Helper console print before the autorun.
Your mini-mongo(client side DB) get updated before the server data update according to point number 2.
According to point number 1, the client sends a request to the server, then server updates the server database. Server re-publish the data to the client and autorun reinitialize in your case.
So the point is your mini mongo(client side DB) updated before the subscription ready. that's why you got console log in helper before your autorun.
One more thing happen when your server data to client::
If the result from the server comes back and is consistent with the
simulation on the client, everything remains as is. If the result on
the server is different from the result of the simulation on the
client, the UI is patched to reflect the actual state of the server.
I'm trying to make a watchOS 3 app, and I want to update my complication in a background task.
First, I get new data from a server in a background task within handle(). After that, I update my active complications by calling complicationServer.reloadTimeline(for:).
In the console I do see the message "UPDATE COMPLICATION," so the code is executed.
Yet after reloading, the complication still shows the old data. If I switch the watch face and switch back, then the complication sometimes reloads. Do I have to do something else to reload the complication from the background task?
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
for task : WKRefreshBackgroundTask in backgroundTasks {
if (WKExtension.shared().applicationState == .background) {
if task is WKApplicationRefreshBackgroundTask {
let dataProvider = DataProvider()
dataProvider.getData(station: "Name", completion: { (data, error) in
self.updateComplication()
self.scheduleNextBackgroundRefresh()
task.setTaskCompleted()
})
}
} else {
task.setTaskCompleted()
}
}
}
func updateComplication() {
let complicationServer = CLKComplicationServer.sharedInstance()
for complication in complicationServer.activeComplications! {
print("UPDATE COMPLICATION")
complicationServer.reloadTimeline(for: complication)
}
}
Your current approach:
You've got a mix of watchOS 2 and watchOS 3 approaches there.
WKApplicationRefreshBackgroundTask (new watchOS 3 approach)
DataProvider starts asynchronous transfer (old watchOS 2 approach which assumes it's in the foreground, not the background).
That background thread (of a background task which may or may not be suspended yet not completed) expects to have the background task handle its completion, once the asynchronous transfer completes.
In short, you've expected your background refresh task to wait in the background for an asynchronous transfer. This is bit convoluted (since the refresh task is supposed to be doing work in the background, not waiting on other work to complete).
A better way for watchOS 3:
Since an asynchronous transfer can be suspended, you would be better off using a URLSession background transfer.
Always upload and download data using an URLSession background transfer. Background transfers occur in a separate process. They continue to transfer the data even after your app has terminated. Asynchronous uploads and downloads, on the other hand, are suspended with your app. Given the short run time of watchOS apps, you cannot guarantee that an asynchronous transfer will finish before the app is suspended.
By letting a WKURLSessionRefreshBackgroundTask respond to the background transfer, your extension can be woken in the background once the session completes, hand off that session's data to the data provider, and then update the complication.
An suggestion about the data provider:
It seems to have the responsibility of both transferring data, and providing data. You may want to consider splitting off the network portion into a separate component, and simply let it be a repository of data.
I get the impression that it's meant to be some manner of singleton (behind the scenes) yet you initialize an instance as a DataProvider().
From a readability viewpoint, it's not apparent from the provided code that the complication data source will be using the same data provider as the one who received the data.
You should avoid force unwrapping optionals:
When activeComplications is nil (such as when the complication had been removed from the watch face between the last update and this update), your code will ungraciously crash.
You should use a guard or if let to first check that you still have an active complication.
Hello I'm trying to learn Meteor Js and i started building a simple task manager app.
I want to add a notification (using the notifications api), when a user adds a task from an input. My problem is that I cant find a way to send the notifications between users from the server side.
What i have so far :
Template.listPage.events({
'submit #newItem':function(e){
e.preventDefault();
//variables to insert here here. i dont post for space issues.
// Call server method for insert into db
Meteor.call('addItem',item,d,user,datestring,currentList,listName,assign);
// This is what i m trying to implement
var items = todos.find({name:item}).observe({
added:function() {
var n = new Notification("hello new task added")
}
})
},
The above works as :
The notification is shown only to the user that adds the task (not really useful).
How can I use this in server side, In order to:
Show the notification to all users using the app? Is this possible or I have to use a push notification package?
PS: I ask for users permition to receive notifications on Meteor.startup.
The problem is that you specify the observe within the click event. Therefore, only users who have triggered the event (i.e. clicked the button) will get the notification.
In order to activate the observer for everyone do the following:
Template.listPage.rendered = function(){
todos.find().observe({
added: function() {
... do whatever you want to do here
}
})
};
To add notifications, you could use a package such as yogiben:notifications:
https://atmospherejs.com/yogiben/notifications
(There might be better packages for this nowadays. Search on Atmosphere.)
Alternatively, you can roll your own solution. The basic idea would be add create a collection called Notifications. Then add notifications whenever you feel like it and publish the relevant notifications to whichever user(s) you'd like.
The code in your question will also work as long as you're publishing the relevant todos to different users.
I want to use Stuart's messenger plugin to give instant user messages when a business process is done. eg. in my BL class I have the code:
var message = new UserMessages(this, "STARTING PROCESS");
_messenger.Publish<UserMessages>(message );
//PROCESS START
message = new UserMessages(this, "READING FILE 1");
_messenger.Publish<UserMessages>(message);
//READING FILE 1 PROCESS
message = new UserMessages(this, "ENDING PROCESS");
_messenger.Publish<UserMessages>(message);
//END PROCESS
I want my subscriber to show the message asynchronously (instantly in the gui). I have tried to use
_token = messenger.SubscribeOnThreadPoolThread<UserMessages>(OnImportMessage);
inside my viewmodel because I thought that this is what SubscribeOnThreadPoolThread is supposed to do but it didn't show me the expected outcome meaning:
1.The user clicks a button and based on my messaging service above the user must see inside the textedit control:
1.STARTING PROCESS
2.READING FILE1
3.ENDING PROCESS
What I finally displayed on the screen was the last message "ENDING PROCESS" because eventually the whole process was part of the Main Thread.
I want to understand how to do this asynchronously with the messenger plugin.
Do I need to use additional async/await operations?
I hope this makes sense to you.
Thanks in advance