I'm performing a database count through a server method. Users can select how they want the count to be performed and then invoke the method.
My problem is that the count can take some time and a user might change their mind while the method is running and request a different count. Is there any way for me to cancel the invoked method and run a new count?
I've thought this.unblock() might work; it will allow a new method to be run, but it won't cancel the old method. I've also considered pre-counting and then just using a lookup, but there are too many selector combinations.
Here's my code, it's fairly simple:
//Server
Meteor.methods({
getFilterCount: function(oFilterSelector) {
return clMaBldgs.find(oFilterSelector, {}).count();
}
});
//Client
Meteor.call('getFilterCount', oFilterSelector, function (error, result) {
//do some stuff
});
Cancelling an already-made method call to server from client is not possible.
But if your method are called multiple times in a short interval, and you only care about the last call's result. You could use debounce to delay execution for some times. This will help reduce unnecessary calls to server.
More of a work around, but if you had a reactive variable (could be an entry in the DB) that is a status of the method, and in the method itself, you check for that flag every chance you get for the status.
{
_id: "some id for the method", running: true
}
Pseudocode for method
Meteor.methods({
method: (_id) => {
status = getStatusForId(_id);
while(status) {
status = getStatusForId(_id);
}
}
});
Then to stop it, you just update that flag to be false and the method will stop as soon as it can.
Related
Im trying to make throttleTime take effect, but for some reason it does not kick in. I have the following:
// Class Properties
private calendarPeriodSubject: Subject<x> = new Subject<x>();
private calendarPeriodObservable$ = this.calendarPeriodSubject.asObservable();
// Throttling fails here (Inside constructor):
const calendarPeriodSubscription = this.calendarPeriodObservable$.pipe(throttleTime(750)).subscribe(async (calendar: x) => {
// Do http stuff here
}
});
The subject gets called like this:
this.calendarPeriodSubject.next(x);
I also tried with:
this.calendarPeriodSubject.pipe(throttleTime(1000)).subscribe({next: (x) => x});
I would like to process the FIRST time, and the following clicks should not have any effect before after ieg 750ms - To prevent the server from getting spammed basically.
Anyone has any idea?
Thanks!
The problem is that you are using the wrong operator for your use case. The way I understand your explanation you want to send through your first call and stop any further calls to your Server for some amount of ms. But what throttleTime(sec) does is simply put a timer on the action and execute it sec ms later. So you server will still be spammed, just a few ms later.
Your case screams debounceTime() for me. debounceTime docu
This disables any further data to be passed though the Observable for the specified time after a value has been emitted.
Therefore your code should be fine if you use something like:
const calendarPeriodSubscription =
this.calendarPeriodObservable$.pipe(debounceTime(750)).subscribe((calendar: x) => {
// Stuff with returned data
});
LAST EDIT: Try Tracker.afterFlush in the subscription-ready callback.
EDIT: The sorting was not the problem, it was the new subscription to the same collection with new session variable. Problem occurred because of Meteor not kicking old documents before triggering the subscribe-onReady callback...
I have a Meteor helper that returns a sorted collection (mapped documents).
It looks like this:
"currentNames": function () {
if (Session.get("sortBy") === "rating") {
return MyCollection.find({'name': {$exists: true}}, {sort: {rating: -1}}).map(function (document, index) {
document.index = index;
return document;
});
}
else if (Session.get("sortBy") === "alphabet") {
return MyCollection.find({'name': {$exists: true}}, {sort: {name: 1}}).map(function (document, index) {
document.index = index;
return document;
});
}
}
The sort works beautiful. I have a Template using this helper in a {{#each currentNames}}-loop which also works. But when I change the type of sort by changing the Session field sortBy my shown results (the html-dom-elems) are totally whirling around (changing their positions) until they found their final sort. I'm talking about 100 documents in the collection I'm sorting.
Because I don't want my users to see this sorting process live, I want to wait until the sort is finished. But I can not figure out a way to wait until the sort finished. I know when to hide the results (this is when the session variable sortBy is changed), but I dont have a callback or something when the sort is finished. But I need this.
Thank you for your time! Hope you can help me.
From meteor guide:
It’s also worth knowing a little about what happens on the server when the new subscription is started and the old one is stopped.
The server explicitly waits until all the data is sent down (the new subscription is ready) for the new subscription before removing the data from the old subscription. The idea here is to avoid flicker—you can, if desired, continue to show the old subscription’s data until the new data is ready, then instantly switch over to the new subscription’s complete data set.
What this means is in general, when changing subscriptions, there’ll be a period where you are over-subscribed and there is more data on the client than you strictly asked for. This is one very important reason why you should always fetch the same data that you have subscribed to (don’t “over-fetch”).
So in your case, you can hide your view (or show loading text etc.), until your new subscription is ready. You can check it with subscription handlers ready() function (which is reactive).
My nightwatch/selenium test code looks for elements in the page that may not exist using code such as
browser.elementIdElement(ELEMENT,'class name', 'myclass', function(r)
{ if (r.status == 0) console.log('found match')
else console.log('did not find match')
})
If the element is found, the callback is invoked quickly (< 50ms), but if no element matches, the callback takes much longer (>1000ms). I have to do this hundreds of times and there are only a few elements that match the search criteria, so it adds a significant amount of time to a test run.
I would like to limit the time selenium spends searching for elements. I tried using the selenium timeoutsImplicitWait() function, e.g.,
browser.timeoutsImplicitWait(250)
.elementIdElement(ELEMENT,'class name', 'myclass', function(r)
{...})
but it doesn't affect performance. What is the correct method for limiting element search time?
Perhaps I am misunderstanding your problem; both of these patterns works well for me:
client
.useXpath().waitForElementPresent(selector, this.timeout)
.useCss().waitForElementPresent(selector, this.timeout)
this.timeout is set in the prototype of the base test case.
util.inherits(MyExampleBaseClass, Base);
MyExampleBaseClass.prototype = {
before: function (client) {
// call super-before
Base.prototype.before.call(this, client);
this.timeout = 250;
},
after: function (client, callback) {
// call super-after
Base.prototype.after.call(this, client, callback);
},
// Note: This method will not be mistaken by nightwatch for a step because
// it is not enumerable (since it's on the prototype)
getSiteURL: function () {
return "http://www.urlundertest.com/";
}
};
The following code for checking the visibility and continue even if there is no match
browser.waitForElementVisible('selector',timeout,false);
or this for the existence :
browser.waitForElementPresent('selector',timeout,false);
According to nightwatch api,
By the default if the element is not found the test will fail. Set this to false if you wish for the test to continue even if the assertion fails.To set this globally you can define a property abortOnAssertionFailure in your globals.
For more detailed explanation, check here:
http://nightwatchjs.org/api/#waitForElementVisible
I am using the pub / sub jQuery plugin by Peter Higgins. I have run into a problem with JavaScript validation.
This is the crux of the problem...
$.subscribe('/make', function(form_id, fields, path, type) {
for (var i=0; i < fields.length; i++) {
$.publish('/validation/field', [ path+'check_field', $('*[name="'+fields[i]+'"]'), fields ]);
}
if ($('#'+form_id+' .error').length > 0) {
alert('There are errors, please fix the errors before continuing.');
return;
}
The /validation/field will append errors to form fields. When you run this the first time the errors appear but everything is running so quickly an ajax request is sent to save the form. When the form is run the second time the function is stopped correctly as the error classes have been counted.
Is there a way around this?
If the validation is asynchronous
...the usual way you deal with this is to use a callback. In this case, you'd be looking for a callback defined by the validation that tells you when the validation has finished, at which point you could use your code for counting the resulting errors.
If the validation is synchronous
The above assumes that the validation involves an asynchronous activity of some kind. It doesn't look like that pub/sub plugin provides any asynchronicity, so this would be down to what your subscriber for /validation/field does. If it does an ajax call or a setTimeout or similar, then you'll need a callback.
If the /validation/field subscriber does the validation synchronously, then I'm surprised you're having a problem with the fields not being counted correctly afterward. But if you are, you can probably solve it by giving the browser just a moment to breathe:
$.subscribe('/make', function(form_id, fields, path, type) {
for (var i=0; i < fields.length; i++) {
$.publish('/validation/field', [ path+'check_field', $('*[name="'+fields[i]+'"]'), fields ]);
}
// Check results *after* giving the browser a moment to breathe:
setTimeout(function() {
if ($('#'+form_id+' .error').length > 0) {
alert('There are errors, please fix the errors before continuing.');
return;
}
// (...your code left off here, but I'm guessing the rest of the
// function would also need to be within this new anonymous function...)
}, 0);
}
The 0 parameter to setTimeout means "call me back in zero milliseconds", but no browser will actually do that — it'll typically be 4-10 milliseconds later. The point is that it will be asynchronous, after the browser has had a chance to catch up and re-invoke the JavaScript layer.
Be careful though, make sure that the thing doing the validating is doing it synchronously. If it isn't, if it's doing anything async, then the above introduces a race condition into your code where sometimes it will seem to work, other times it won't work. Race conditions will bite you, so double-check. :-)
Dows the subscribe use ajax to call the server?
If wo then thats is your problem as ajax is asyncornious.
The subscribe method then exits immediatly after sending the call, and the function is called on ajax response.
This means that any code after the subscribe is called probably before the ajax request finishes and there will not be any errors yet.
You need then to move aany code folowing the subscribe call into the callback methos instead to be sure it is called after the ajax call.
To prevent any other action you could set a globalvariable, ex. validating = true, and have any other code check that.
I want to run some code on all my treeView nodes depending on a value returned from the database and repeat this until a certain value is returned.
I was thinking that:
Give all my tree nodes the same css class so I can access them from JQuery
have a timer in my JQuery function that used ajax to go to the database, when a certain value is returned then stop the timer
Two questions here. How can I make my function run for each of the nodes and how do I do a timer in JavaScript, so:
$(function(){
$('cssClassOfAllMyNodes').WhatFunctionToCallHere?((){
//How do I do Timer functionality in JavaScript?
ForEachTimeInterval
{
//use Ajax to go to database and retrieve a value
AjaxCallBackFunction(result)
{
if (result = 1)
//How to stop the timer here?
}
}
});
});
Hope i'm clear. Thanks a lot
thanks a lot for the answer. And i would like you to comment on the design.
Bascially what i'm trying to acheive is a Windows Wokflow type functionality where each node in my tree updates its image depending on its status, where its status is got from querying the database with a key unique to the tree node. I'm open to ideas on other ways to implement this if you have any. thanks again
Without commenting on your design you can refer to these
$.each()
setTimeout() or setInterval()
You can do:
$(function(){
$('cssClassOfAllMyNodes').each(function (){
// Do something with "this" - "this" refers to current node.
});
});
Te proper way to handle timers in JS is to have a reference to each timeout or interval and then clearing them out.
The difference between them is:
The timeout will only run once, unless stopped before;
The interval will run indefinitely, until stopped.
So you can do something like:
var delay = 2000; // miliseconds
var timer = setTimeout("functionToBeCalled", delay);
clearTimeout(timer); // whenever you need.
Please note you can pass a string to setTimeout (same with setInterval) with the name of the function to be called. Or you could pass a reference to the function itself:
var callback = function () { alert(1); };
var timer = setTimeout(callback, delay);
Be sure not to set an Interval for AJAX requests, because you response might be delayed and successive calls to the server could eventually overlap.
Instead, you should call setTimeout and when the answer arrives then call setTimeout again.