I want to asynchronously load content into my page when I click on the links on my navigation bar. While, using the .load() method works I am having difficulty figuring out how to make the promise object work the same way. I am also confused as why my form is visible when i click 'home' even though i set it to be hidden.
http://jsfiddle.net/Piq9117/Lzw514md/
// Navigation
var navigation = (function () {
var $nav = $('#navigation a');
var $page = $('#page');
var $container = $('#container');
$nav.on('click', function (e) {
e.preventDefault();
$page.remove();
dataservice.getPage()
.done(function (data) {
$container.html($(data).find('#page'));
})
.fail(function (jqXHR, statusText, err) {
alert(err);
})
})
// the .load works fine..
// $nav.on('click', function(e) {
// e.preventDefault();
// var url = $(this).attr('href');
// $page.remove();
// $container.load(url + ' #page');
// })
})();
// Promise object, passed to navigation
var dataservice = (function () {
var getPage = function () {
var url = $(this).attr('href'); // this returns undefined
return $.ajax({
type: 'GET',
url: url,
})
}
return {
getPage: getPage
}
})();
// chache/hide/show form
(function () {
var form = {
init: function () {
this.cacheDom();
this.events();
},
cacheDom: function () {
this.$container = $('.container');
this.$page = this.$container.find('#page');
this.$showbtn = this.$container.find('#showbtn');
this.$form = this.$page.find('#form');
this.$form.hide();
this.$submitbtn = this.$page.find('#submitbtn');
},
events: function () {
this.$showbtn.on('click', this.showForm.bind(this));
this.$submitbtn.on('click', this.hideForm.bind(this));
},
showForm: function () {
this.$form.fadeIn(300);
this.$showbtn.hide(300);
},
hideForm: function (e) {
e.preventDefault(300);
this.$form.hide(300);
this.$showbtn.show(300);
}
}
form.init();
})();
this within your dataservice.getPage() function is not the dom element that you want it to be. You would need to pass that element in as an argument and since all you really need is the href maybe it would look better just passing in the url
var getPage = function (url) {
return $.ajax({
type: 'GET',
url: url,
})
}
Then in even handler pass in the href:
$nav.on('click', function (e) {
e.preventDefault();
$page.remove();
dataservice.getPage(this.href) // pass in `href`
.done(function (data) {
$container.html($(data).find('#page'));
}).fail(function (jqXHR, statusText, err) {
alert(err);
});
})
The problem is that you have a reference to $(this) in your getPage method. $(this) doesn't exist in this context, you have to pass it through all your methods.
// Navigation
var navigation = (function () {
var $nav = $('#navigation a');
var $page = $('#page');
var $container = $('#container')
$nav.on('click', function (e) {
e.preventDefault();
$page.remove();
dataservice.getPage($(this))
.done(function (data) {
$container.html($(data).find('#page'));
})
.fail(function (jqXHR, statusText, err) {
alert(err);
})
})
// the .load works fine..
// $nav.on('click', function(e) {
// e.preventDefault();
// var url = $(this).attr('href');
// $page.remove();
// $container.load(url + ' #page');
// })
})();
// Promise object, passed to navigation
var dataservice = (function () {
var getPage = function ($this) {
var url = $this.attr('href'); // this returns undefined
return $.ajax({
type: 'GET',
url: url,
})
}
return {
getPage: function($this) {
getPage($this);
}
}
})();
// chache/hide/show form
(function () {
var form = {
init: function () {
this.cacheDom();
this.events();
},
cacheDom: function () {
this.$container = $('.container');
this.$page = this.$container.find('#page');
this.$showbtn = this.$container.find('#showbtn');
this.$form = this.$page.find('#form');
this.$form.hide();
this.$submitbtn = this.$page.find('#submitbtn');
},
events: function () {
this.$showbtn.on('click', this.showForm.bind(this));
this.$submitbtn.on('click', this.hideForm.bind(this));
},
showForm: function () {
this.$form.fadeIn(300);
this.$showbtn.hide(300);
},
hideForm: function (e) {
e.preventDefault(300);
this.$form.hide(300);
this.$showbtn.show(300);
}
}
form.init();
})();
here is the fiddle (check your javascript console to see the ajax requests)
Related
In my application, I'm trying to use sendBeacon to send data to my remote server. One of the data that I need is how many clicks its been on the page and I'm doing it as follows:
var clickNumber = 0;
document.addEventListener("mouseup", function () {clickNumber++;});
var SendToRemote = window.SendToRemote || [];
SendToRemote.init({
clicks: clickNumber
});
My sendBeacon
navigator.sendBeacon = (url, data) =>
window.fetch(url, { method: 'POST', body: {data: data}, credentials: 'include' });
My only issue now is that the clickNumber is always 0 (which is the default value) and even that mouseup does increment clickNumber, but when sending it sends 0.
How am I able to update the clickNumber so when sendBeacon is triggered, it gets the incremented/updated clickNumber instead of 0.
This is my SendToRemote.init which works fine: (PS: I have removed parts of the codes as it would be over 1000 lines, but kept whats needed):
if (!SendToRemote) {
var SendToRemote = (function(){
var defaults = {
endpoints: {
unload: "https://remote.com"
},
processData: function(results){},
},
results = {
click: 0,
// more stuff here
},
support = !!document.querySelector && !!document.addEventListener,
settings;
var actions = {
sendData: function () {
results.hmn = parseInt(actions.hmnDetection(
results.times.tt, results.times.tp, results.click, results.mouse, results.touch, results.scroll, results.tab
));
let url = settings.endpoints.unload,
data = JSON.stringify(results);
navigator.sendBeacon(url, data);
},
// more functions here
}
function init(options) {
document.addEventListener('DOMContentLoaded', (event) => {
// More stuff here
// Event Listener to porcess
if(modifiable.processOnAction){
let node = document.querySelector(modifiable.selector);
if(!!!node) throw new Error('Selector was not found.');
actions._e(node, modifiable.event, `init-${modifiable.selector}-processOnAction`, function() {
let nodeInput = document.getElementsByName(modifiable.element)[0];
if(!!!nodeInput) throw new Error('nodeInput was not found.');
nodeInput.value = JSON.stringify(results);
hasProcessed = true;
})
}
addEventListener('unload', (event) => {
if (!navigator.sendBeacon) {
navigator.sendBeacon = (url, data) =>
window.fetch(url, { method: 'POST', body: {data: data}, credentials: 'include' });
}
if (!hasProcessed) {
actions.sendData();
hasProcessed = true;
}
return;
});
});
}
function processResults(){
if(settings.hasOwnProperty('processData')){
if (!modifiable.processOnAction){
return settings.processData.call(undefined, results);
}
return results;
}
return false;
}
// Module pattern, only expose necessary methods
return {
init: init,
processResults: processResults,
};
})();
}
Thanks in advance!
During loading of the partial Html with controller, my function named $scope.actionViewVisitors() is recognized and runs without errors. But whenever I use it inside another function on the same controller, it gives me an error:
TypeError: $scope.actionViewVisitors is not a function. Please see my code below:
angular.module("Visitor.controller", [])
// ============== Controllers
.controller("viewVisitorController", function ($scope, $rootScope, $http, viewVisitorService, viewAccountService, DTOptionsBuilder) {
$scope.visitorList = null;
$scope.viewAccountDetail = null;
$scope.avatar = null;
$scope.visitorDetail = null;
$scope.visitorBtn = "Create";
$scope.actionViewAccount = function () {
$scope.actionViewAccount = viewAccountService.serviceViewAccount()
.then(function (response) {
$scope.viewAccountDetail = response.data.account;
$scope.avatar = "../../avatars/" + response.data.account.AccountId + ".jpg";
})
}
$scope.dtOptions = DTOptionsBuilder.newOptions()
.withDisplayLength(10)
.withOption('bLengthChange', false);
// THIS ONE IS NOT RECOGNIZED
$scope.actionViewVisitors = function () {
$scope.actionViewVisitors = viewVisitorService.serviceViewVisitors()
.then(function (response) {
debugger;
$scope.visitorList = response.data.visitorList;
});
}
// I DON'T GET ANY ERROR HERE
$scope.actionViewVisitors();
$scope.actionViewAccount();
$scope.createVisitor = function () {
$scope.statusMessage = null;
if ($scope.visitorBtn == "Create") {
$scope.createVisitor = viewVisitorService.serviceCreateVisitor($scope.visitorDetail)
.then(function (response) {
if (response.data.response == '1') {
bootbox.alert({
message: "Successfully created a new visitor.",
size: 'small',
classname: 'bb-alternate-modal'
});
} else if (response.data.response == '0') {
bootbox.alert({
message: "Failed in creting visitor.",
size: 'small',
classname: 'bb-alternate-modal'
});
}
});
debugger;
$scope.visitorDetail = undefined;
// I GET THE ERROR WHEN I CALL THIS METHOD
$scope.actionViewVisitors();
}
}
})
// ============== Factories
.factory("viewVisitorService", ["$http", function ($http) {
var fac = {};
fac.serviceViewVisitors = function () {
return $http({
url: '/Visitor/ViewVisitors',
method: 'get'
});
}
fac.serviceCreateVisitor = function(visitor) {
return $http({
url: '/Visitor/CreateVisitor',
data: { visitor: visitor },
method: 'post'
});
}
return fac;
}])
You are overwriting the function with Promise in the following line, thus the error is correct
$scope.actionViewVisitors = function () {
$scope.actionViewVisitors = viewVisitorService.serviceViewVisitors()
.then(function (response) {
$scope.visitorList = response.data.visitorList;
});
}
Remove $scope.actionViewVisitors =
$scope.actionViewVisitors = function () {
viewVisitorService.serviceViewVisitors()
.then(function (response) {
$scope.visitorList = response.data.visitorList;
});
}
On the first call to the function you are changing it from a function to a Promise. Maybe you want to be returning the result instead?
$scope.actionViewVisitors = function () {
return viewVisitorService.serviceViewVisitors()
.then(function (response) {
debugger;
$scope.visitorList = response.data.visitorList;
});
}
I get desired output from below code. These are two JavaScript function expressions for printing data
(function(){
var getData=function()
{
console.log("getdata");
},
setData=function()
{
getData();
console.log("setData");
};
setData();
})();
But when I try something like this in another page.I didn't get desired output.
This is my code.
var employeesList = {
getemployees: function () {
var data= getData("Employees/GetEmployees");
},
init: function () {
this.getemployees();
}
}.init();
var getData = function (url) {
var error = false;
$.ajax({
type: 'GET',
url: url,
dataType: 'json',
success: function (data) {
return data;
},
error: function () {
return error = true;
}
});
};
I got an error like this.
getData is not a function
please help.
You can't use a variable before have defined it, so you have to declare getData before employeesList
The variable data in getemployees couldn't be accessible, I added a return there, so you can use its value in init
var getData = function (url) {
var error = false;
/*$.ajax({
type: 'GET',
url: url,
dataType: 'json',
success: function (data) {
return data;
},
error: function () {
return error = true;
}
});*/
return 'test_result';
};
var employeesList = {
getemployees: function () {
//Here you should return the result
return getData("Employees/GetEmployees");
},
init: function () {
var res = this.getemployees();
console.log(res);
}
}.init();
I hope it was clear, bye.
There are two methods to define "function":
var func_name = function(){...}
function func_name() {...}
The difference is that when you use the second one, it can be called before being declared.
var employeesList = {
getemployees: function () {
var data= getData("Employees/GetEmployees");
},
init: function () {
this.getemployees();
}
}.init();
//var getData = function (url) {
function getData (url) { // <====== change to this
var error = false;
$.ajax({
type: 'GET',
url: url,
dataType: 'json',
success: function (data) {
return data;
},
error: function () {
return error = true;
}
});
};
I'm checking the server if a job is done. I don't want to spam the server so that's why I will use setInterval.
I call the trigger function, and when the job is done on the server (perhaps 2-3 calls before it's done), the function is done.
I know that I could call my finishFunction in the interval and kind of solve it. But I would like to return it because I call the trigger function from another js file. And if it's possible, I would like to handle it there.
function trigger() {
var response = startInterval();
response.then(function() {
//done finishFunction()
});
}
function checkServer() {
var obj = { test: true }
var respons = $.ajax({
url: "MyUrl",
data: JSON.stringify({ obj: obj }),
type: "POST",
contentType: "application/json",
dataType: "JSON",
cache: false
});
return respons;
}
function startInterval() {
var inProgress = false;
var interval = setInterval(function () {
if (!inProgress) {
inProgress = true;
var response = checkServer().then(function (data) {
var isDoneInQueue = JSON.parse(data.d);
if (isDoneInQueue) {
//finishFunction()???
clearInterval(interval);
return response;
};
inProgress = false;
});
}
}, 1000);
}
Return a Deferred object from the function, and resolve it when the server job is done:
function startInterval() {
var result = $.Deferred();
var inProgress = false;
var interval = setInterval(function () {
if (!inProgress) {
inProgress = true;
checkServer().then(function (data) {
var isDoneInQueue = JSON.parse(data.d);
if (isDoneInQueue) {
clearInterval(interval);
result.resolve(data);
};
inProgress = false;
});
}
}, 1000);
return result;
}
Whatever you call the resolve method with, is sent to the function that you use with the then method:
function trigger() {
startInterval().then(function(data) {
//done finishFunction()
});
}
I am trying to stub several ajax calls, but I want to have both beforeSend and success executed, is this possible?
I want something like this:
var stub = sinon.stub(jQuery, "ajax");
stub.onCall(0).yieldsTo("beforeSend").yieldsTo("success", {some: 'data'});
stub.onCall(1).yieldsTo("beforeSend").yieldsTo("success", {other: 'stuff'});
But this skips the 'beforeSend' method.
I know it would be easier to allow ajax to do it's stuff and use sinon's fakeServer, but I can't as I'm testing in Node with a fake browser and it just doesn't work
You could use yieldTo after the call:
var stub = sinon.stub();
stub({
foo: function() {
console.log('foo');
},
bar: function() {
console.log('bar');
}
});
stub.yieldTo('foo');
stub.yieldTo('bar');
I was able to work around this by adding some additional code:
var responses = {};
var executionComplete;
beforeEach(function () {
executionComplete = $.Deferred();
sinon.stub($, "ajax", function (options) {
if (options.beforeSend) {
options.beforeSend();
}
completeAjaxCall(options);
});
});
afterEach(function () {
$.ajax.restore();
});
var completeAjaxCall = function (options) {
var response = findResponse(options.url, options.type);
setTimeout(function () {
if (response.code < 400) {
if (options.dataFilter && response.data) {
response.data = options.dataFilter(JSON.stringify(response.data));
}
if (options.success) {
options.success(response.data);
}
} else {
if (options.error) {
options.error(response.data);
}
}
if (options.complete) {
options.complete();
}
if (response.completeExecution) {
executionComplete.resolve();
}
}, response.serverResponseTime);
};
var findResponse = function (url, type) {
var response = responses[url];
expect(response, url + ' should have a response').to.exist;
expect(response.type).to.equal(type);
delete responses[url];
if (Object.keys(responses).length === 0) {
response.completeExecution = true;
}
return response;
};
var givenResponse = function (response) {
responses[response.url] = response;
};
Then in my test I can use it like this:
it('should do some stuff', function (done) {
//given
givenResponse({serverResponseTime: 4, code: 200, url: '/saveStuff', type: 'POST'});
givenResponse({serverResponseTime: 1, code: 200, url: '/getStuff', type: 'GET'});
//when
$('button').click();
//then
executionComplete.then(function () {
expect(something).to.be.true;
done();
});
});