Reputation: 1154
In a Meteor app, one function that runs on a click takes a while to run on some slower devices. As a result, on these slow devices, the app doesn't seem to do anything until after the function has completed.
The function in question loops through a largish array. It does not do any external stuff, or method calls.
To visually clue in the user, I want to show a spinner to the user (on slow devices). Ideally, I would show the spinner at the start of the event, and then remove the spinner at the end of the event. However, if my understanding of Meteor is correct (and based on what seems to be happening when I try it out), all template updates specified during the event are only propagated at the end of the event. So, as a result, the spinner never shows.
How can I make this work as intended?
Current setup (edit with actual code):
In categories.html:
{{#if hasSubCategories}}
<a href='#_' id='categorySelect-{{id}}' class='btn categorySelect pull-right
{{#if allSubsSelected}}
btn-danger
{{else}}
btn-success
{{/if}}
'>{{#if isFlipping}}<span id='spinner-{{id}}'>flip</span>{{/if}}<span class="glyphicon
{{#if allSubsSelected}}
glyphicon-remove
{{else}}
glyphicon-ok
{{/if}}
" aria-hidden="true"></span></a>
{{/if}}
In categories.js:
Template.categories.events({
"click .categorySelect": function (event) {
Session.set('categorySpinner', this.id);
categoryFlipper(this.id, function() {
Session.set('categorySpinner', "");
});
return false;
},
});
Template.categories.helpers({
allSubsSelected: function() {
var finder = Categories.find({parentId: this.id});
var allSelected = true;
finder.forEach(function(item) {
if (!($.inArray(item.id, Session.get("categoriesSelected")) !== -1)) {
allSelected = false;
}
});
return allSelected;
},
isFlipping: function() {
if (Session.get("categorySpinner") == this.id)
return true;
else
return false;
}
});
In main.js:
categoryFlipper = function (id, callback) {
var finder = Categories.find({parentId: id});
var allSelected = true;
finder.forEach(function(item) {
if (!($.inArray(item.id, Session.get("categoriesSelected")) !== -1)) {
allSelected = false;
}
});
var t = Session.get("categoriesSelected");
if (allSelected) {
finder.forEach(function(item) {
t.splice($.inArray(item.id, t), 1);
});
}
else {
finder.forEach(function(item) {
if (!($.inArray(item.id, t) !== -1)) {
t.push(item.id);
}
});
}
Session.set("categoriesSelected", t);
callback();
}
Upvotes: 0
Views: 147
Reputation: 27713
Looking at your sample code (though I still don't have a complete picture since I don't see the helper definitions for allSubsSelected
and isFlipping
), I'm pretty sure that your categoryFlipper
function executes so quickly that you never really see the spinner. There's nothing in that code that would really take any significant amount of time. You have a find()
call, but that's not what really takes the most amount of time. It's your subscribe()
call that you usually need to figure in some delay for as the data is pulled from the database to the mini-mongo client in the browser.
Something like this is fairly common:
{{#unless Template.subscriptionsReady}}
spinner here...
{{else}}
Content here.
{{/unless}}
That way, while your subscription is triggering the publication and pulling data down, Template.subscriptionsReady
returns false, and the spinner is shown. Try that approach instead.
Upvotes: 1