Set timeout to layoutTemplate meteor / iron - javascript

I've been struggling to set 3 seconds timeout for my loadingTemplate.
Using the code bellow loadingTemplate is rendered but it does redirect to layoutTemplate after passing 3 seconds, as I expect.
Please find bellow my code and comments issues.
I also deployed this version to http://ns1-timeout.meteor.com/
I appreciate any help.
Router.configure({
layoutTemplate: 'applayout',
loadingTemplate: 'loading',
waitOn: function () {
var isTimePassed = false;
var clock = 3;
var timeLeft = function() {
if (clock > 0) {
clock--;
Session.set("time", clock);
console.log(clock);
} else {
console.log("That's All Folks");
//return true
isTimePassed = true;
Meteor.clearInterval(interval);
console.log('is Time passed: '+ isTimePassed);
return isTimePassed; // seems it is being ignored
}
};
var interval = Meteor.setInterval(timeLeft, 1000);
return {
ready: function () {
console.log('return ready: ' + isTimePassed);
return isTimePassed; // keeps the loading page and does not redirect to applayout if changed to false, loadingTemplate is not loaded and
}
}
}
});

Returning from a setInterval won't do anything. You need to use a reactive variable and have ready return the value of that reactive variable:
Router.configure({
layoutTemplate: 'applayout',
loadingTemplate: 'loading',
waitOn: function () {
Session.set('isTimePassed', false);
var isTimePassed = false;
var clock = 3;
var timeLeft = function() {
if (clock > 0) {
clock--;
Session.set("time", clock);
console.log(clock);
} else {
console.log("That's All Folks");
//return true
isTimePassed = true;
Meteor.clearInterval(interval);
console.log('is Time passed: '+ isTimePassed);
Session.set('isTimePassed', true);
}
};
var interval = Meteor.setInterval(timeLeft, 1000);
return {
ready: function () {
return Session.get('isTimePassed');
}
}
}
});
However, it is not exactly clear in your question if this is what you are intending to do.

After a few hours working on this I figured out that the best way to set a custom timeout for a loading template was not using Router.configure. The correct way would be setting a call to onBeforeAction function to my / route. So the code has ended as the following:
Router.configure({
layoutTemplate: 'appLayout',
loadingTemplate: 'loading'
});
Router.onBeforeAction(function(){
if(!Session.get('templateLoaded'))
{
setTimeOut(1000);
this.layout('loading');
this.render('loading');
}
else
{
this.render('home');
this.next();
}
},
{
only: ['home']
});
var setTimeOut = function (timeout) {
var self = this;
self._ready = false
self._dep = new Tracker.Dependency();
Meteor.setTimeout(function () {
self._ready = true;
self._dep.changed();
if(Meteor.isClient){
Session.set('templateLoaded', true); // set session variable to true so applayout Template will be rendered
}
}, timeout);
return function () {
self._dep.depend();
return function () {
return self._ready;
}
}
};

Related

using bootstrap 3.37 header dropdown menu and tranlsating jquery to knockoutJS

I was looking at this article to apply header menu with dropdowns in my mvc5 knockoutjs solution.
https://jdmdigital.co/news/codex/bootstrap-3-secondary-dropdown-menu/
The frontend it looks nice, and it is ok in my solution, however, I cant figure it out how to bind js section to work.
Now when I click on my dropdown parent item, nothing happens, because the js code is not working.
here is my setup of the js (knockoutjs) file.
define(['durandal/system', 'plugins/router', 'durandal/services/logger', 'knockout', 'common', 'plugins/dialog', 'durandal/binder', 'fastclick'],
function (system, router, logger, ko, common, dialog, binder, fs) {
var shell = {
activate: activate,
router: router,
};
// Make Dropdown Submenus possible
$('.dropdown-submenu a.dropdown-submenu-toggle').on("click", function (e) {
$('.dropdown-submenu ul').removeAttr('style');
$(this).next('ul').toggle();
e.stopPropagation();
e.preventDefault();
});
// Clear Submenu Dropdowns on hidden event
$('#bs-navbar-collapse-1').on('hidden.bs.dropdown', function () {
$('.navbar-nav .dropdown-submenu ul.dropdown-menu').removeAttr('style');
});
//...
//...
//OTHER INIT METHODS (not in the scope for this question)
//#region Internal Methods
function activate() {
var result = registerRoutes();
//setRouteGuard();
if (window.cordova) {
window.document.addEventListener("deviceready", function () {
shell.refreshUserData(true);
shell.changeLanguage();
});
} else {
shell.refreshUserData(true);
shell.changeLanguage();
}
shell.isLoading.subscribe(function (newValue) {
//if something gone wrong
if (newValue) {
setTimeout(function () {
//shell.isLoading(false);
}, 10000);
}
});
if (router.activeInstruction().config.moduleId == "viewmodels/parentschedule") {
if (shell.isAnonymousUser() == true) {
shell.isClient(false);
shell.isEmployee(false);
}
else {
shell.isClient(true);
shell.isEmployee(true);
}
//console.log("test");
}
return result;
}
function route(r, moduleId, name, visible, alwaysVisible, role, condition) {
var self = this;
self.route = r;
self.moduleId = moduleId;
self.title = name;
self.visible = visible;
self.nav = true;
self.role = role;
self.condition = condition;
self.mouseover = ko.observable(false);
self.onhover = function () {
self.mouseover(!self.mouseover());
};
self.goToPage = function () {
router.navigate(this.hash);
};
self.alwaysVisible = alwaysVisible;
self.isTouched = ko.observable(false);
self.setTouched = function () {
self.isTouched(true);
return true;
}
self.setUnTouched = function () {
setTimeout(function () {
self.isTouched(false);
}, 200);
return true;
}
self.isActiveMenuItem = ko.computed(function () {
return router.activeInstruction() &&
router.activeInstruction().fragment.indexOf(self.route) > -1
});
return self;
}
//#endregion
});

$scope.$watch only triggered once

I've set the following watcher in my controller:
var embeds = {twitter: false, facebook: false};
$scope.$watch(embeds, function(newVal, oldVal) {
if(embeds.twitter && embeds.facebook) $scope.loading = appLoader.off();
});
This should fire when embeds changes. I have the following functions that check if all my embedded Tweets and Facebook posts have loaded for the page. When all Tweets or Facebook posts are loaded, it updates embeds within a $timeout block in order to trigger a digest cycle.
checkFBInit();
twttr.ready(function(twttr) {
twttr.events.bind('loaded', function(event) {
$timeout(function() {
embeds.twitter = true;
});
});
});
function checkFBInit() {
// Ensure FB.init has been called before attempting to subscribe to event
var fbTrys = 0;
function init() {
fbTrys++;
if (fbTrys >= 60) {
return;
} else if (typeof(FB) !== 'undefined') {
fbTrys = 60;
FB.Event.subscribe('xfbml.render', function() {
$timeout(function() {
embeds.facebook = true;
});
});
return;
} else {
init();
};
};
init();
};
The problem I'm having is that my watcher only fires once when I set it. I've tried binding embeds to $scope and/or watching embeds.twitter and embeds.facebook but the watcher only ever fires once.
Use:
$scope.embeds = {twitter: false, facebook: false};
$scope.$watch('embeds', function(newVal, oldVal) {
if ($scope.embeds.twitter && $scope.embeds.facebook) {
$scope.loading = appLoader.off();
}
}, true);
See https://docs.angularjs.org/api/ng/type/$rootScope.Scope. First argument must be string or function which return the name of param.

clearInterval not working as I expect it too

I made a demo which is here. All you have to do is start typing in the text field, make sure you have the console open. So as you type, you'll instantly see the OMG Saved, and the counter in the console will go nuts.
Now click the button, watching the console you should see something like 11 or some other value, but you'll also see the counter reset and continues going. I do not want this. I want the counter to stop, I have clicked a button and while the page hasn't refreshed, the counter should stop if I understand these docs on setInterval().
the app I am developing which uses code very similar to this, does not refresh as most single page apps don't. So it is imperative that I have control over this setInterval.
So my question is:
How do I reset the counter such that, until I type again in the input box OR if the input box element cannot be found the flash message does not show up, the interval is set back to 0.
update
The following is the JavaScript code, which is run on the link provided above.
var ObjectClass = {
initialize: function() {
$('#flash-message').hide();
},
syncSave: function() {
$('#content').keypress(function(){
SomeOtherClass.autoSave = setInterval( function(){
$('#flash-message').show();
$('#flash-message').delay(1000).fadeOut('slow');
}, 500);
});
},
listenForClick: function() {
$('#click-me').click(function() {
console.log(SomeOtherClass.autoSave);
clearInterval(SomeOtherClass.autoSave);
});
}
};
var SomeOtherClass = {
autoSave: null
};
ObjectClass.initialize();
ObjectClass.syncSave();
ObjectClass.listenForClick();
You have to put this
clearInterval(SomeOtherClass.autoSave);
before this line:
SomeOtherClass.autoSave = setInterval( function(){
So that you kill the previous interval and you ahve ONLY ONE interval at the same time
Your code will be:
var ObjectClass = {
initialize: function () {
$('#flash-message').hide();
},
syncSave: function () {
$('#content').keypress(function () {
clearInterval(SomeOtherClass.autoSave);
SomeOtherClass.autoSave = setInterval(function () {
$('#flash-message').show();
$('#flash-message').delay(1000).fadeOut('slow');
}, 500);
});
},
listenForClick: function () {
$('#click-me').click(function () {
console.log(SomeOtherClass.autoSave);
clearInterval(SomeOtherClass.autoSave);
});
}
};
var SomeOtherClass = {
autoSave: null
};
ObjectClass.initialize();
ObjectClass.syncSave();
ObjectClass.listenForClick();
What you need to do is use a timeout instead of an interval, like this:
var ObjectClass = {
initialize: function() {
$('#flash-message').hide();
},
syncSave: function() {
$('#content').keypress(function(){
SomeOtherClass.autoSave = setTimeout( function(){
$('#flash-message').show();
$('#flash-message').delay(1000).fadeOut('slow');
}, 500);
});
},
listenForClick: function() {
$('#click-me').click(function() {
console.log(SomeOtherClass.autoSave);
if(typeof SomeOtherClass.autoSave === 'number'){
clearTimeout(SomeOtherClass.autoSave);
SomeOtherClass.autoSave = 0;
}
});
}
};
var SomeOtherClass = {
autoSave: 0
};
ObjectClass.initialize();
ObjectClass.syncSave();
ObjectClass.listenForClick();

What does this BlackBerry Web App Javascript code do?

I know my way around several programming languages but am struggling understanding Javascript and how it's used in mobile apps. I'm developing for BlackBerry and a using the BlackBerry 10 jQuery Mobile Theme. I'm looking at the App.js from the samples and am confused as to what the App object is.
App = {};
App.init = function () {
console.log("App Init");
App.utils.metaHack();
$("#activity").live("pageinit", function(){
App.page.activity.init();
});
$("#bb_activity").live("pageinit", function(){
App.page.bb_activity.init();
});
$("#progressPage").live("pageinit", function(){
App.page.progress.init();
});
$("#sliderPage, #sliderPageDark").live("pageinit", function(){
App.page.slider.init();
});
$("#togglePage, #togglePageDark").live("pageinit", function(){
App.page.toggle.init();
});
$("#actionBarSample").live("pageinit", function() {
App.page.actionBarSample.init();
});
$('#applicationMenu').live("pageinit", function() {
App.page.applicationMenu.init();
});
}
App.utils = {
metaHack: function () {
var meta = document.createElement("meta");
meta.setAttribute('name','viewport');
meta.setAttribute('content','initial-scale='+ (1/window.devicePixelRatio) + ',user-scalable=no');
document.getElementsByTagName('head')[0].appendChild(meta);
}
}
App.page = {
activity: {},
bb_activity: {},
progress: {},
slider: {},
toggle: {},
actionBarSample: {},
applicationMenu: {}
}
App.page.activity.init = function() {
$('#show').on('click', function () {
$.mobile.loading('show');
});
$('#text').on('click', function() {
$.mobile.loading('show', {
text: 'Loading',
textVisible: true,
textonly: true,
theme: 'a'
});
});
$('#swatch-a').on('click', function() {
$.mobile.loading( 'show', {
text: 'Loading',
textVisible: true,
theme: 'a'
});
});
$('#swatch-a-notext').on('click', function() {
$.mobile.loading( 'show', {
theme: 'a'
});
});
$('#swatch-c').on('click', function() {
$.mobile.loading( 'show', {
text: 'Loading',
textVisible: true,
theme: 'c'
});
});
$('#swatch-c-notext').on('click', function() {
$.mobile.loading( 'show', {
theme: 'c'
});
});
$('#hide').on('click', function () {
$.mobile.loading('hide');
});
}
App.page.bb_activity.init = function() {
console.log("bb_activity");
$('#throttle').on('change', function () {
console.log("throttle");
var speed = $('#throttle').val();
$('#speedTest').activityindicator('speed', speed+'s');
});
}
App.page.progress.init = function() {
var p = 0;
var error = pause = false;
function watchProgress() {
if( p > 100 || error || pause) {
return;
}
$('#rogress').progressbar("setValue", p);
p+= 4;
setTimeout(watchProgress, 100);
}
$('#start').on('vclick', function () {
error = false;
watchProgress();
});
$('#error').on('vclick', function () {
$('#rogress').progressbar("setError", error = !error);
});
$('#pause').on('vclick', function () {
$('#rogress').progressbar("pause", pause = !pause);
});
$('#reset').on('vclick', function () {
p = 0;
error = pause = false;
$('#rogress').progressbar("setValue", p);
});
}
App.page.slider.init = function() {
$('#slider-disabled').slider('disable');
$('#slider-disabled-highlight').slider('disable');
}
App.page.toggle.init = function() {
console.log("toggle init");
$('#flip-disabled').slider('disable');
}
App.page.actionBarSample.init = function() {
var $tabo = $("#tover"),
overflowState = $tabo.hasClass("noContent");
$("#left").on("panelbeforeopen", function() {
//Save the state of the overflow button
overflowState = $tabo.hasClass("noContent");
$tabo.addClass("noContent");
})
.on("panelbeforeclose", function() {
//Put the overflow button into the correct state
if(!overflowState) {
$tabo.removeClass("noContent");
}
});
//Handle overflow menu clicks
$(".bb10-panel").bind("vclick", function() {
//Close the panel
$(this).panel("close");
});
$("#left li").bind("vclick", function() {
//Clear the active state from any other buttons that may have been set to active
$(this).siblings().removeClass("ui-btn-active");
//Add the active state to the selected button
$(this).addClass("ui-btn-active");
//Clear the contents of the tab overflow button
//Add class to put the tab overflow icon in the correct position
//Clear the active state from all tab buttons in action bar
$('[data-role="tab"], [data-role="tab-overflow"]').removeClass("active");
});
$(".inBar").bind("vclick", function() {
//Set the active state to the tab in the actionbar
$('#' + this.id.slice(0, 2)).addClass("active");
$tabo.addClass("noContent").empty();
overflowState = true;
});
$(".notInBar").bind("vclick", function() {
//Set the active state to the tab overflow button
$tabo.empty()
.addClass("active")
.html('<img src="img/generic_81_81_placeholder.png" alt=""><p>' + $(this).text() + '</p>')
.removeClass("noContent");
overflowState = false;
});
$("[data-role='tab']").bind("vclick", function() {
//Change page on tab click
if($(this).data("href")) {
$.mobile.changePage( $(this).data("href"), { transition: "slideup"} );
}
});
}
App.page.applicationMenu.init = function() {
if(typeof blackberry != 'undefined'){
blackberry.event.addEventListener('swipedown', function(){
$('#top').panel("open");
});
$('#menuBtn').css('display','none');
}
else{
$('#simulInst').css('display','none');
}
}
App.init();
Is App an object specific to Blackberry? I did some dabbling and made a small app but didn't use App or init anything.
App in this example is defined at the top:
App = {};
So it's just a new plain old JavaScript object (dictionary), which they then define functions and data to it e.g. App.utils = ....
You can try it out on a browser, press F12 and then go to the console (ESC) and type e.g. blah = {} and you will see a new object created with the name blah. Everything is an object in JavaScript apparently.
Read more
http://www.w3schools.com/js/js_objects.asp

chrome ext: limiting DOMNodeInserted

I'm developing a chrome plugin that inject a class to every element in the page. But in pages such as facebook or twitter there is content loaded dynamically, so I use this code to check when this conent is loaded:
document.addEventListener('DOMNodeInserted', function() {
console.log('fatto');
}, true);
the problem is that this way, the script is fired every single time a node is inserted. Therefore I'd like to add some kind of limitation. something like: When a node is inserted fire the script and then wait 2 sec.
I'm trying something like this but no success:
var check = 1;
document.addEventListener('DOMNodeInserted', function() {
if(check == 1) {
check = 0;
setInterval( function() {
//do stuff
check = 1;
}, 1000);
console.log('fatto');
}
}, true);
thanks
I've seen this technique referred to as debouncing. Here's an example:
(function() {
var timer;
var doStuff = function() {
timer = null;
alert("Doing stuff");
};
document.addEventListener('DOMNodeInserted', function() {
if (timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(doStuff, 2000);
}, false);
})();
You can generalize this:
function addDebouncedEventListener(obj, eventType, listener, delay) {
var timer;
obj.addEventListener(eventType, function(evt) {
if (timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(function() {
timer = null;
listener.call(obj, evt);
}, delay);
}, false);
}
addDebouncedEventListener(document, 'DOMNodeInserted', function(evt) {
alert(evt.target.nodeName + " inserted");
}, 2000);
I'd say:
var timeout;
document.addEventListener('DOMNodeInserted', function() {
startNewTimeout();
}, true);
function startNewTimeout() {
//only if there is no active timeout already
if(timeout === undefined) {
timeout = setTimeout( function() {
timeout = undefined;
//do stuff
}, 1000);
}
}
​This script won't delay the execution of //do stuff indefinitely. It will make sure that //do stuff is executed max. 1sec after first DOMNodeInserted event.

Categories

Resources