I have a durandal/requirejs single page application. When a user sits idle, I need to display a warning to the user indicating that the session is about to time out. I have looked at several examples on the internet for asp.net apps, but can't find any examples for a single page application.
My application is similar to John Papa's code camper (MVC application).
How can I get a session timeout warning to the user if their session is 2 minutes away from timing out?
--EDIT
In my main.js file I have-
app.setRoot('viewmodels/shell', 'entrance');
router.guardRoute = function (instance, instruction) {
var sess_pollInterval = 60000;
//How many minutes the session is valid for
var sess_expirationMinutes = 2;
//How many minutes before the warning prompt
var sess_warningMinutes = 1;
var sess_intervalID;
var sess_lastActivity;
initSessionMonitor();
function initSessionMonitor() {
sess_lastActivity = new Date();
sessSetInterval();
$(document).bind('keypress.session', function (ed, e) { sessKeyPressed(ed, e); });
}
function sessSetInterval() {
sess_intervalID = setInterval('sessInterval()', sess_pollInterval);
}
function sessClearInterval() {
clearInterval(sess_intervalID);
}
function sessKeyPressed(ed, e) {
sess_lastActivity = new Date();
}
function sessPingServer() {
//Call an AJAX function to keep-alive your session.
alert('someAJAXFunction();');
}
function sessLogOut() {
alert('here');
//window.location.href = '/Account/LogOff';
}
function sessInterval() {
var now = new Date();
var diff = now - sess_lastActivity;
var diffMins = (diff / 1000 / 60);
if (diffMins >= sess_warningMinutes) {
//wran before expiring
//stop the timer
sessClearInterval();
//promt for attention
if (confirm('Your session will expire in ' + (sess_expirationMinutes - sess_warningMinutes) +
' minutes (as of ' + now.toTimeString() + '), press OK to remain logged in ' +
'or press Cancel to log off. \nIf you are logged off any changes will be lost.')) {
now = new Date();
diff = now - sess_lastActivity;
diffMins = (diff / 1000 / 60);
if (diffMins > sess_expirationMinutes) {
//timed out
sessLogOut();
}
else {
//reset inactivity timer
sessPingServer();
sessSetInterval();
sess_lastActivity = new Date();
}
} else {
sessLogOut();
}
} else {
sessPingServer();
}
}
return true;
};
}
now getting "Uncaught ReferenceError: sessInterval is not defined." Ideas?
Here's how I do it in my idle service. It uses some other services, but you should get the idea. Basically, I start tracking user activity in observable when he sings in and reset the timeout for idle handler everytime observable changes.
//idle.js
define(function (require) {
var ko = require('knockout'),
$ = require('jquery'),
router = require('lib/router'),
config = require('lib/config'),
dialog = require('lib/dialog'),
auth = require('auth/auth'),
lastActionDate = ko.observable(),
signoutHandle = null,
onIdle = function () {
console.log('user has been idle, signing out');
return auth.signOut()
.then(function () {
router.navigate('');
dialog.show('auth/idle');
});
},
init = function () {
var userActionHandler = function () {
lastActionDate(new Date());
};
auth.on('signin:success').then(function (user) {
$(document).on('click keydown scroll', userActionHandler);
userActionHandler();
});
auth.on('signout:success').then(function (using) {
$(document).off('click keydown scroll', userActionHandler);
});
lastActionDate.subscribe(function () {
if (signoutHandle) {
clearTimeout(signoutHandle);
}
signoutHandle = setTimeout(onIdle, config.get('idleTimeout') * 1000);
});
};
return {
init: init
};
});
Then I just call idle.init() my main.js file before app.start()
The approach I used was different than my post above. I used timeout-dialog.js and altered that script to use with durandal's router and any other service I needed within my application. I also used idle js. Here is the code-
main.js in app.start()-
var timeout = 100;
$(document).bind("idle.idleTimer", function () {
controls.timeoutDialog.setupDialogTimer();
});
$(document).bind("active.idleTimer", function () {
var sess = Security.GetKeepSessionAlive();
});
$.idleTimer(timeout);
timeout-dialog.js code-
String.prototype.format = function () {
var s = this,
i = arguments.length;
while (i--) {
s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
}
return s;
};
define(['durandal/system', 'plugins/router', 'services/logger', 'services/SecurityDataService'],
function (system, router, logger, Security){
timeoutDialog = {
settings: {
timeout: 50,
countdown: 15,
title: 'Your session is about to expire!',
message: 'You will be logged out in {0} seconds.',
question: 'Do you want to stay signed in?',
keep_alive_button_text: 'Yes, Keep me signed in',
sign_out_button_text: 'No, Sign me out',
keep_alive_url: '',
keep_alive_function: function () {
},
logout_url: function () {
router.map([
{ route: 'ErrorPage', moduleId: 'ErrorPage', title: 'ErrorPage', title: 'ErrorPage', nav: false }
]).activate
router.navigate('ErrorPage');
},
logout_redirect_url: function () {
router.map([
{ route: 'ErrorPage', moduleId: 'ErrorPage', title: 'ErrorPage', title: 'ErrorPage', nav: false }
]).activate
router.navigate('ErrorPage');
},
logout_function: function () {
amplify.store("ErrorDetails", "Session Timed Out!");
router.map([
{ route: 'ErrorPage', moduleId: 'ErrorPage', title: 'ErrorPage', title: 'ErrorPage', nav: false }
]).activate
router.navigate('ErrorPage');
},
restart_on_yes: true,
dialog_width: 350
},
alertSetTimeoutHandle: 0,
setupDialogTimer: function (options) {
if (options !== undefined) {
$.extend(this.settings, options);
}
var self = this;
if (self.alertSetTimeoutHandle !== 0) {
clearTimeout(self.alertSetTimeoutHandle);
}
self.alertSetTimeoutHandle = window.setTimeout(function () {
self.setupDialog();
}, (this.settings.timeout - this.settings.countdown) * 1000);
},
setupDialog: function () {
//check for other modal forms on view
//$.element.modal('hide');
$('.modal').modal('hide');
var self = this;
self.destroyDialog();
$('<div id="timeout-dialog">' +
'<p id="timeout-message">' + this.settings.message.format('<span id="timeout-countdown">' + this.settings.countdown + '</span>') + '</p>' +
'<p id="timeout-question">' + this.settings.question + '</p>' +
'</div>')
.appendTo('body')
.dialog({
modal: true,
width: this.settings.dialog_width,
minHeight: 'auto',
zIndex: 10000,
closeOnEscape: false,
draggable: false,
resizable: false,
dialogClass: 'timeout-dialog',
title: this.settings.title,
buttons: {
'keep-alive-button': {
text: this.settings.keep_alive_button_text,
id: "timeout-keep-signin-btn",
click: function () {
self.keepAlive();
}
},
'sign-out-button': {
text: this.settings.sign_out_button_text,
id: "timeout-sign-out-button",
click: function () {
self.signOut(true);
}
}
}
});
self.startCountdown();
},
destroyDialog: function () {
if ($("#timeout-dialog").length) {
$("#timeout-dialog").dialog("close");
$('#timeout-dialog').remove();
}
},
startCountdown: function () {
var self = this,
counter = this.settings.countdown;
this.countdown = window.setInterval(function () {
counter -= 1;
$("#timeout-countdown").html(counter);
if (counter <= 0) {
window.clearInterval(self.countdown);
self.signOut(false);
}
}, 1000);
},
keepAlive: function () {
var self = this;
this.destroyDialog();
window.clearInterval(this.countdown);
this.settings.keep_alive_function();
if (this.settings.keep_alive_url !== '') {
$.get(this.settings.keep_alive_url, function (data) {
if (data === "OK") {
if (this.settings.restart_on_yes) {
self.setupDialogTimer();
}
}
else {
self.signOut(false);
}
});
}
},
signOut: function (is_forced) {
var self = this;
this.destroyDialog();
this.settings.logout_function(is_forced);
if (this.settings.logout_url !== null) {
$.post(this.settings.logout_url, function (data) {
self.redirectLogout(is_forced);
});
}
else {
self.redirectLogout(is_forced);
}
},
redirectLogout: function (is_forced) {
var target = this.settings.logout_redirect_url + '?next=' + encodeURIComponent(window.location.pathname + window.location.search);
if (!is_forced)
target += '&timeout=t';
window.location = target;
},
};
var dataservice = {
timeoutDialog: timeoutDialog
};
return dataservice;
});
I put the timeout-dialog.js in my own folder under the apps folder to bring in durandal and other services i needed. The idle-timer.js was left in the scripts folder and registered via bundle.config.
Related
I have declared a function sessionTimeoutTwo between script tags.
<script language="javascript">
var $jq = jQuery.noConflict();
$jq(document).ready(function() {
alert('called');
$jq.sessionTimeoutTwo({
title: 'Session Timeout Warning',
message: 'Your session is about to expire in exactly:',
warnAfter: 3000,
redirAfter: 8000,
keepAliveUrl: 'http://www.google.com',
redirUrl: 'http://www.google.com',
logoutUrl: 'http://www.google.com'
});
}
//this is the function definition
(function ($) {
jQuery.sessionTimeoutTwo = function (options) {
var defaults = {
title: 'Session Timeout',
message: 'Your session is about to expire in: ',
keepAliveUrl: '/keep-alive',
redirUrl: '/timed-out',
logoutUrl: '/log-out',
warnAfter: 900000, // 15 minutes
redirAfter: 1200000 // 20 minutes
};
// Extend user-set options over defaults
var o = defaults;
if (options) {
o = $.extend(defaults, options);
}
var latestActivity = new Date();
var count=o.redirAfter/1000;
var counter=setInterval(timer, 1000)
resetOnUser();
checkActivity();
// Create timeout warning dialog
$('body').append('<div title="'
+ o.title
+ '" id="sessionTimeout-dialog"><p>'
+ o.message
+ '</p><span id="sessionTimeout-timer"></span> seconds.</div>');
$('#sessionTimeout-dialog').dialog({
autoOpen: false,
width: 400,
modal: true,
closeOnEscape: false,
open: function () {
$(".ui-dialog-titlebar-close").hide();
},
buttons: {
// Button one - takes user to logout URL
"Log Out Now": function () {
window.location = o.logoutUrl;
},
// Button two - closes dialog and makes call to keep-alive URL
"Stay Connected": function () {
latestActivity = new Date();
$(this).dialog('close');
$.ajax({
type: 'POST',
url: o.keepAliveUrl
});
}
}
});
function resetOnUser() {
$(this).mousemove(function (e) {
latestActivity = new Date();
});
$(this).keypress(function (e) {
latestActivity = new Date();
});
}
function elapsed() {
return (new Date() - latestActivity);
}
function checkActivity() {
var check = setInterval(
function () {
if (elapsed() > o.warnAfter) {
$('#sessionTimeout-dialog').dialog('open');
}
if (elapsed() > o.redirAfter) {
window.location = o.redirUrl;
}
}, 3000);
}
function timer() {
count=count-1;
if (count <= 0)
{
clearInterval(counter);
return;
}
$("#sessionTimeout-timer").html(count);
}
};
})(jQuery);
</script>
It is displaying the alert.
After that at the function call I'm getting the below error.
Uncaught TypeError: $jq.sessionTimeoutTwo is not a function.
I added jQuery.noConflict(); also.
But still getting the error.
Could you help me on this.
Thanks.
Place your code in which you have defined function sessionTimeoutTwo() at the top and then you can make successful call to it later.
var $jq = jQuery.noConflict();
//this is the function definition
(function ($) {
jQuery.sessionTimeoutTwo = function (options) {
console.log('Entering sessionTimeoutTwo function');
var defaults = {
title: 'Session Timeout',
message: 'Your session is about to expire in: ',
keepAliveUrl: '/keep-alive',
redirUrl: '/timed-out',
logoutUrl: '/log-out',
warnAfter: 900000, // 15 minutes
redirAfter: 1200000 // 20 minutes
};
// Extend user-set options over defaults
var o = defaults;
if (options) {
o = $.extend(defaults, options);
}
var latestActivity = new Date();
var count=o.redirAfter/1000;
var counter=setInterval(timer, 1000)
resetOnUser();
checkActivity();
// Create timeout warning dialog
$('body').append('<div title="'
+ o.title
+ '" id="sessionTimeout-dialog"><p>'
+ o.message
+ '</p><span id="sessionTimeout-timer"></span> seconds.</div>');
$('#sessionTimeout-dialog').dialog({
autoOpen: false,
width: 400,
modal: true,
closeOnEscape: false,
open: function () {
$(".ui-dialog-titlebar-close").hide();
},
buttons: {
// Button one - takes user to logout URL
"Log Out Now": function () {
window.location = o.logoutUrl;
},
// Button two - closes dialog and makes call to keep-alive URL
"Stay Connected": function () {
latestActivity = new Date();
$(this).dialog('close');
$.ajax({
type: 'POST',
url: o.keepAliveUrl
});
}
}
});
function resetOnUser() {
$(this).mousemove(function (e) {
latestActivity = new Date();
});
$(this).keypress(function (e) {
latestActivity = new Date();
});
}
function elapsed() {
return (new Date() - latestActivity);
}
function checkActivity() {
var check = setInterval(
function () {
if (elapsed() > o.warnAfter) {
$('#sessionTimeout-dialog').dialog('open');
}
if (elapsed() > o.redirAfter) {
window.location = o.redirUrl;
}
}, 3000);
}
function timer() {
count=count-1;
if (count <= 0)
{
clearInterval(counter);
return;
}
$("#sessionTimeout-timer").html(count);
}
};
})(jQuery);
$jq(document).ready(function() {
alert('called');
$jq.sessionTimeoutTwo({
title: 'Session Timeout Warning',
message: 'Your session is about to expire in exactly:',
warnAfter: 3000,
redirAfter: 8000,
keepAliveUrl: 'http://www.google.com',
redirUrl: 'http://www.google.com',
logoutUrl: 'http://www.google.com'
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
You are calling function which has not been loaded to DOM yet, that is the reason you need to put your function definition before document ready.
<script language="javascript">
var $jq = jQuery.noConflict();
// var sessionTimeoutTwo;
(function ($) {
jQuery.sessionTimeoutTwo = function (options) {
var defaults = {
title: 'Session Timeout',
message: 'Your session is about to expire in: ',
keepAliveUrl: '/keep-alive',
redirUrl: '/timed-out',
logoutUrl: '/log-out',
warnAfter: 900000, // 15 minutes
redirAfter: 1200000 // 20 minutes
};
// Extend user-set options over defaults
var o = defaults;
if (options) {
o = $.extend(defaults, options);
}
var latestActivity = new Date();
var count=o.redirAfter/1000;
var counter=setInterval(timer, 1000)
resetOnUser();
checkActivity();
// Create timeout warning dialog
$('body').append('<div title="'
+ o.title
+ '" id="sessionTimeout-dialog"><p>'
+ o.message
+ '</p><span id="sessionTimeout-timer"></span> seconds.</div>');
function resetOnUser() {
$(this).mousemove(function (e) {
latestActivity = new Date();
});
$(this).keypress(function (e) {
latestActivity = new Date();
});
}
function elapsed() {
return (new Date() - latestActivity);
}
function checkActivity() {
var check = setInterval(
function () {
if (elapsed() > o.warnAfter) {
$('#sessionTimeout-dialog').dialog('open');
}
if (elapsed() > o.redirAfter) {
window.location = o.redirUrl;
}
}, 3000);
}
function timer() {
count=count-1;
if (count <= 0)
{
clearInterval(counter);
return;
}
$("#sessionTimeout-timer").html(count);
}
};
})(jQuery);
$jq(document).ready(function() {
alert('called');
$jq.sessionTimeoutTwo({
title: 'Session Timeout Warning',
message: 'Your session is about to expire in exactly:',
warnAfter: 3000,
redirAfter: 8000,
keepAliveUrl: 'http://www.google.com',
redirUrl: 'http://www.google.com',
logoutUrl: 'http://www.google.com'
});
$jq('#sessionTimeout-dialog').dialog({
autoOpen: false,
width: 400,
modal: true,
closeOnEscape: false,
open: function () {
$jq(".ui-dialog-titlebar-close").hide();
},
buttons: {
// Button one - takes user to logout URL
"Log Out Now": function () {
window.location = '/log-out';
},
// Button two - closes dialog and makes call to keep-alive URL
"Stay Connected": function () {
latestActivity = new Date();
$jq(this).dialog('close');
$jq.ajax({
type: 'POST',
url: '/keep-alive'
});
}
}
});
}
);
</script>
Here is the working fiddle .
I don't know if it is possible to call a typescript inside a jquery function. if it is possible, what is the right method to do it?
this my component.ts
getCalendar(){
calendarOptions:Object = {
height: 'parent',
fixedWeekCount : false,
defaultDate: '2017-03-01',
editable: true,
eventLimit: true, // allow "more" link when too many
dayclick function
dayClick: function(date, jsEvent, view) {
this.addModal(); **this function is not working**
//console.log(jsEvent);
// alert('Clicked on: ' + date.format());
// alert('Coordinates: ' + jsEvent.pageX + ',' + jsEvent.pageY);
// alert('Current view: ' + view.name);
},
success: function(doc) {
var events = [];
$(doc).find('event').each(function() {
events.push({
title: $(this).attr('title'),
start: $(this).attr('start') // will be parsed
});
});
},
eventAllow: function(dropLocation, draggedEvent) {
if (draggedEvent.id === '999') {
return dropLocation.isAfter('2017-03-22'); // a boolean
}
else {
return true;
}
}
};
ngOnInit() {
this.getTotalEmployee();
this.getComputeAbsent();
this.getTotalAttendance();
// this.showEvent();
this.calendarOptions['events'] = this.events;
}
public catchError(error: any) {
let response_body = error._body;
let response_status = error.status;
if( response_status == 500 ){
this.error_title = 'Error 500';
this.error_message = 'The given data failed to pass validation.';
} else if( response_status == 200 ) {
this.error_title = '';
this.error_message = '';
}
}
showEvent(){
this._event_service.getEventList()
.subscribe(
data => {
this.events = Array.from(data);
this.calendarOptions['events'] = this.events;
console.log(this.calendarOptions['events']);
},
err => this.catchError(err)
);
}
getEvents() {
this._event_service.getEvents().subscribe(
data => {
this.eventsList = Array.from(data);
this.calendarOptions['events'] = this.eventsList;
},
err =>{}
);
}
this is my modal function that im trying to call in jquery function above
addModal() {
let disposable = this.modalService.addDialog(EventComponent, {
title:'Add Event'
}).subscribe((isConfirmed)=>{
});
}
getTotalAttendance() {
let pre;
this._attend_service.getTotalPresent().subscribe(
data => {
pre = Array.from(data);
this.present = pre[0].total_present;
},
err =>{}
);
}
getTotalEmployee() {
let totalEmp;
let filter = "Active";
this._attend_service.getTotalEmp(filter).subscribe(
data => {
totalEmp = data; // fetced record
this.total_emp = totalEmp[0].total_employee;
},
err =>{}
);
}
getComputeAbsent(){
let employee = parseInt(this.employee);
let attendance = parseInt(this.attendance);
this.totalAbsent = employee - attendance;
}
If you don't need the enclosed this
You can use the arrow function:
dayClick: (date, jsEvent, view)=> {
this.addModal();
}
Or you can store the outer this in a variable and use it later
var self = this; // store here
dayClick: function(date, jsEvent, view) {
self.addModal(); // use here
}
Edit:
getCalendar(){
var self = this; // ******
calendarOptions:Object = {
height: 'parent',
fixedWeekCount : false,
defaultDate: '2017-03-01',
editable: true,
eventLimit: true, // allow "more" link when too many
dayClick: function(date, jsEvent, view) {
self.addModal(); // *********
},
success: function(doc) {
var events = [];
$(doc).find('event').each(function() {
events.push({
title: $(this).attr('title'),
start: $(this).attr('start') // will be parsed
});
});
},
eventAllow: function(dropLocation, draggedEvent) {
if (draggedEvent.id === '999') {
return dropLocation.isAfter('2017-03-22'); // a boolean
}
else {
return true;
}
}
};
I have this code, I want to go thru all the links available at the bottom of the page. After clicking them I want to make sure the URL opened is the correct one.
I think the the recursive calls are done too early. Another issue is how can I do to tell that link belongs to certain URL.
function links(browser, total_links) {
if (total_links <= 0) {
browser.end();
return;
}
console.log("Number of links: " + total_links);
console.log('Flag1');
browser
.waitForElementVisible('.bottom .socal>span:nth-child(' + total_links + ')', 1000, function () {
console.log('Flag2');
browser.execute('scrollIntoView(alignToBottom)')
.moveToElement('.bottom .socal>span:nth-child(' + total_links + ')', 3, 3)
.pause(3000)
.click('.bottom .socal>span:nth-child(' + total_links + ') a', function () {
console.log('Flag3');
browser.keys(['\uE006'])
// .assert.urlContains('facebook')
//.assert.urlEquals('https://www.facebook.com/unitel.ao/?fref=ts')
.window_handles(function (result) {
console.log('Flag4');
browser.assert.equal(result.value.length, 2, 'There should be two windows open.');
var handle_1 = result.value[0];
var handle_2 = result.value[1];
browser.switchWindow(handle_2, function () {
browser.closeWindow()
.switchWindow(handle_1, function () {
total_links = total_links - 1;
links(browser, total_links);
});
});
});
console.log('Flag5');
});
console.log('Flag6');
});
}
module.exports = {
'Social links': function (browser) {
var total_links;
browser
.url('http://m.unitel.ao/fit/')
.execute(function () {
return document.querySelectorAll("ul.navbar-nav>li").length;
},
function (tags) {
total_links = tags.value;
links(browser, total_links);
});
// .end();
}
};
Humh, it seems like you were stuck with this days ago.I recommend page-object,it will help you stay away hardcode and easier to change css in the future.
A home page object(home.js) may be like this :
module.exports = {
url: function() {
return 'http://m.unitel.ao/fit/';
},
commands: [{
getUrl: function(n) {
if (n === 3) {
return 'youtube.com/user/tvUNITEL';
}
if (n === 1) {
return 'facebook.com/unitel.ao/?fref=ts';
}
if (n === 2) {
return 'instagram.com/unitelangola/';
}
if (n === 4) {
return 'plus.google.com/110849312028181626033/posts';
}
}
}],
elements: {
facebook: {
selector: '.bottom .socal>span:nth-child(1)',
},
instagram: {
selector: '.bottom .socal>span:nth-child(2)'
},
youtube: {
selector: '.bottom .socal>span:nth-child(3)'
},
googleplus: {
selector: '.bottom .socal>span:nth-child(4)'
}
}
};
And in your test should be like :
module.exports = {
'Social links': function(browser) {
const homePage = browser.page.home();
var j = 0;
for (var i in homePage.elements) {
homePage
.navigate()
.waitForElementVisible(homePage.elements[i].selector, 5000, false,
function() {
browser.pause(3000);
})
.click(homePage.elements[i].selector, function() {
browser
.pause(2000)
.window_handles(function(result) {
url = homePage.getUrl(j + 1);
var home = result.value[0];
var handle = result.value[1];
browser
.switchWindow(handle)
.verify.urlContains(url)
.closeWindow()
.switchWindow(home);
j += 1;
});
})
}
}
};
PS:In case you dont know how to create a page-object, here is the doc http://nightwatchjs.org/guide#using-page-objects.
In config file
Nightwatch.js:
"src_folders" : ["tests"],
"output_folder" : "reports",
"custom_commands_path" : "",
"custom_assertions_path" : "",
"page_objects_path" : "./lib/pages", /* you need to add the path,e.g: './lib/pages', */
"globals_path" : "",
I have used Durandal.js for my SPA. I need to have slideshow of Images as background in certain pages, for which I am using jquery-backstretch. I am fetching images from my web back-end. Everything works fine while navigating between pages in normal speed. But, when I navigate from one of the pages which has backstretch to another one with backstretch very rapidly, Images from backstretch in first page also creeps in second page. When I debugged, only the correct Images were being passed to second page. And also the slideshow is not running in a proper interval. So it must be both the backstretches being invoked.
Please tell me how I can stop the previous backstretch from appearing again. Here are the relevant code snippets.
This is my first page's(with backstretch) viewmodel code.
var id = 0;
var backstetcharray;
function loadbackstretchb() {
backstetcharray = new Array();
$.each(that.products, function (i, item)
{
if(item.ProductBackImage != "")
{
backstetcharray.push("xxxxxxxxxx" + item.ProductBackImage);
}
}
);
$.backstretch(backstetcharray, { duration: 5000, fade: 1500 });
}
var that;
define(['plugins/http', 'durandal/app', 'knockout'], function (http, app, ko) {
var location;
function callback() {
window.location.href = "#individual/"+id;
// this.deactivate();
};
return {
products: ko.observableArray([]),
activate: function () {
currentpage = "products";
that = this;
return http.get('yyyyyyyyyyyyyyy').then(function (response) {
that.products = response;
loadbackstretchb();
});
},
attached: function () {
$(document).ready(function () {
$('.contacticon').on({
'mouseenter': function () {
$(this).animate({ right: 0 }, { queue: false, duration: 400 });
},
'mouseleave': function () {
$(this).animate({ right: -156 }, { queue: false, duration: 400 });
}
});
});
$(document).ready(function () {
$(".mainmenucont").effect("slide", null, 1000);
});
//setTimeout($(".mainmenucont").effect("slide", null, 1000), 1000);
$(document).on("click", ".ind1", function (e) {
// alert("ind1");
id = e.target.id;
// $(".mainmenucont").effect("drop", null, 2000, callback(e.target.id));
$('.mainmenucont').hide('slide', { direction: 'left' }, 1000, callback);
});
}
}
});
This is my second page's(with backstretch) viewmodel code.(To where I am navigating)
var recs;
var open;
var i, count;
var backstetcharray;
function loadbackstretchc() {
backstetcharray = new Array();
$.each(recs, function (i, item) {
if (item.BackgroundImage != "") {
backstetcharray.push("xxxxxxxxxx" + item.BackgroundImage);
}
}
);
$.backstretch(backstetcharray, { duration: 5000, fade: 1500 });
}
var that;
define(['plugins/http', 'durandal/app', 'knockout'], function (http, app, ko) {
var system = require('durandal/system');
var location;
function menucallback() {
window.location.href = location;
// this.deactivate();
};
return {
activate: function (val) {
currentpage = "recipes";
open = val;
that = this;
var pdts;
recs;
var recipeJson = [];
http.get('yyyyyyyyyyyyyy').then(function (response) {
pdts = response;
http.get('yyyyyyyyyyyy').then(function (response1) {
recs = response1;
loadbackstretchc();
$.each(pdts, function (i, item) {
var json = [];
$.each(recs, function (j, jtem) {
if (item.DocumentTypeId == jtem.BelongstoProduct) {
json.push(jtem);
}
});
jsonitem = {}
jsonitem["product"] = item.ProductName;
jsonitem["link"] = "#" + item.UmbracoUrl;
jsonitem["target"] = item.UmbracoUrl;
jsonitem["recipes"] = json;
recipeJson.push(jsonitem);
});
// that.products = recipeJson;
count = recipeJson.length;
i = 0;
return that.products(recipeJson);
});
});
},
attached: function(view) {
$(document).ready(function () {
$('.contacticon').on({
'mouseenter': function () {
$(this).animate({ right: 0 }, { queue: false, duration: 400 });
},
'mouseleave': function () {
$(this).animate({ right: -156 }, { queue: false, duration: 400 });
}
});
});
$(document).ready(function () {
$(".mainmenucont").effect("slide", null, 1000);
});
$(document).on("click", ".recipeclick", function (e) {
console.log(e);
location = "#recipe/" + e.target.id;
$('.mainmenucont').hide('slide', { direction: 'left' }, 1000, menucallback);
});
$(document).on("click", ".locclick", function (e) {
if (e.handled != true) {
if (false == $(this).next().is(':visible')) {
$('#accordion ul').slideUp(300);
}
$(this).next().slideToggle(300);
e.handled = true;
}
});
},
products: ko.observableArray([]),
expand: function() {
++i;
if (i == count) {
$("#" + open).addClass("in");
}
}
};
});
I wish to write some unit tests for the custom adapter I have written for Ember-Data and I am running into errors. Here is how I am setting up the store and a test model:
window.App = Ember.Application.create();
App.Store = DS.Store.extend({ adapter: DS.WebSqlStorageAdapter.extend({ logQueries: true }) });
App.createTables = function() {
var db = store.adapter.create().db;
db.transaction(
function(tx) {
tx.executeSql('DROP TABLE IF EXISTS test_models;');
tx.executeSql('CREATE TABLE IF NOT EXISTS test_models (' +
'id INTEGER PRIMARY KEY AUTOINCREMENT,' +
'"string" TEXT,' +
'"number" REAL,' +
'"date" TEXT,' +
'"boolean" INTEGER' +
');');
},
function(err) {
console.error(err);
throw new Exception('Database error!');
},
function() {
App.dbCreated = true;
}
);
}
App.TestModel = DS.Model.extend({
number: DS.attr('number'),
date: DS.attr('date'),
string: DS.attr('string'),
boolean: DS.attr('boolean')
});
App.dbCreated = false;
window.store = App.Store.create();
setTimeout(App.createTables, 500);
Here's my test setup and my first test:
var m;
function waitForDbInit() {
waitsFor(function() { return App.dbCreated; }, 'DB initialization', 4000);
}
function waitsFor(fn, label, time) {
QUnit.stop();
var int2 = setInterval(function() {
throw new Error(label + 'was not completed after ' + time + ' ms.');
}, time);
var int = setInterval(function() {
if (fn()) {
clearInterval(int);
clearInterval(int2);
QUnit.start();
}
}, 50);
}
var inc = 0;
module('CRUD', {
setup: function() {
waitForDbInit();
m = store.createRecord('test_model', {
id: ++inc,
string: 'String!',
number: 1234,
date: new Date(),
boolean: true
});
}
});
asyncTest('creates a record', function() {
m.save().then(function() {
ok(m.get('number') === 12345);
start();
}, function(err) {
console.error(err);
ok(false);
start();
});
});
When I run the tests this is the error I get on every one:
Setup failed on retrieves a record: Cannot call method 'lookupFactory' of undefined
Source:
at DS.Store.Ember.Object.extend.modelFor (http://localhost:4567/lib/ember-data.js:2179:34)
at DS.Store.Ember.Object.extend.createRecord (http://localhost:4567/lib/ember-data.js:1343:17)
at Object.module.setup (http://localhost:4567/tests.js:24:15)
at Object.Test.setup (http://localhost:4567/lib/qunit.js:176:31)
at http://localhost:4567/lib/qunit.js:358:10
at process (http://localhost:4567/lib/qunit.js:1453:24)
at http://localhost:4567/lib/qunit.js:479:5