Javascript data not loading at first time - javascript

I have the following code, it have one problem, on first load it wont display anything, but when I press next button on my carousel, everything will work perfectly, so the problem resides somewhere on the first call, as the other calls are exactly the same but theese are working :S
I wont put where the display code, as it is working because it's only jquery adding data to divs and stuff, but as I said, on first time, data is empty.
var dificildecision = function() {
}
dificildecision.prototype = {
is_animating : false,
base_url : window.base_url,
current_decision : null,
decisiones_seen : 0,
historial_decisiones : {
"decisiones" : []
},
is_previous : false,
previous_id : 1,
next_decision : function(replace) {
if (this.is_animating != true) {
this.is_animating = true;
if (this.is_previous) {
decision = this.get_decision(this.previous_id);
} else {
if (this.get_current_decision() === false)
decision_id = 1;
else
decision_id = this.current_decision.id;
this.get_new_decision(decision_id);
decision = this.get_current_decision();
$('#decision-carousel').html("This is: " + decision.key);
this.is_animating = false;
this.is_previous = false;
}
} else {
// console.log("Slow down");
}
},
get_new_decision : function(decision_id) {
if (typeof (decision_id) === "undefined" || decision_id === null) {
decision_id = 1;
}
$.getJSON('http://echo.jsontest.com/key/value', this.set_current_decision);
},
get_current_decision : function() {
return (this.current_decision) ? this.current_decision : false;
},
set_current_decision : function(decision) {
// THIS DOESN'T WORK
this.current_decision = decision;
// THIS WORK SECOND+ TIME EXECUTED
//dificildecision.prototype.current_decision = decision;
}
};
var dificil = new dificildecision();
dificil.next_decision(true);
$('#testlink').on('click', function(){
dificil.next_decision(true);
});
With this code nothing is displayed on console, but if I change
set_current_decision : function(decision) {
this.current_decision = decision;
}
to
set_current_decision : function(decision) {
dificildecision.prototype.current_decision = decision;
}
It outputs the object only when the carousel function is handled, but not at page load...
I've also tried to change
get_new_decision : function(decision_id) {
if (typeof (decision_id) === "undefined" || decision_id === null) {
decision_id = 1;
}
$.getJSON('/~robhunter/dificildecision/web/app_dev.php/new/'
+ decision_id, this.set_current_decision);
},
to
get_new_decision : function(decision_id) {
if (typeof (decision_id) === "undefined" || decision_id === null) {
decision_id = 1;
}
$.getJSON('/~robhunter/dificildecision/web/app_dev.php/new/'
+ decision_id, dificildecision.prototype.set_current_decision);
},
But exactly as original code, nothing is displayed ever :S
You can try it out here http://jsfiddle.net/TUX5a/

Try:
$(document).ready(function() {
// window.dificildecision = new dificildecision();
var dificildecision = new dificildecision();
}
And use this inside your dificildecision.prototype.next_decision
Explanation:
When you declare your function using this line: function dificildecision() in global scope, there will be a new property named dificildecision assigned to your window object.
When you call window.dificildecision = new dificildecision();, this property (a reference to a function) is replaced with an instance
=> this would cause unpredictable behavior in the application and should be avoided.
Update after the OP created a fiddle:
I have checked your fiddle, you have problem with asynchronous nature of ajax. When you call decision = this.get_new_decision();, you fire an ajax request to server to get the decision. And the next line you call decision = this.get_current_decision();, the decision is not set yet ( the callback set_current_decision is not run yet).
There are 2 solutions to this problem:
Use synchronous ajax by using $.ajax function with async: false. However, this solution is not recommended because it will block the browser and degrade user experience.
Use callback or promise API (recommended). Below is a demo how to do this:
DEMO
Return a promise from getJSON
get_new_decision : function(decision_id) {
if (typeof (decision_id) === "undefined" || decision_id === null) {
decision_id = 1;
}
return $.getJSON('http://echo.jsontest.com/key/value', this.set_current_decision);
}
And return it again inside next_decision:
next_decision : function(replace) {
if (this.is_animating != true) {
this.is_animating = true;
if (this.is_previous) {
decision = this.get_decision(this.previous_id);
} else {
if (this.get_current_decision() === false)
decision_id = 1;
else
decision_id = this.current_decision.id;
decision = this.get_new_decision(decision_id);
this.is_animating = false;
this.is_previous = false;
}
} else {
// console.log("Slow down");
}
return decision;//this could be a promise or a value.
},
Use $.when to execute a callback when data is ready, if the parameter is not a promise, the callback will be called immediately (considered it as a resolved promise):
$.when(dificil.next_decision(true)).then(function(decision){
$('#decision-carousel').html("This is: " + decision.key);
});
This code is just a demo of how to use promise API, you may need to restructure your code to make it fit into this programming model.

Actually I've found that I needed to change get_new_decision method to use $.ajax instead of $.getJSON and set async: false to store variable this way
get_new_decision : function(decision_id) {
if (typeof (decision_id) === "undefined" || decision_id === null) {
decision_id = 1;
}
$.ajax({
async : false,
type : 'GET',
url : '/~robhunter/dificildecision/web/app_dev.php/new/'
+ decision_id,
dataType : 'json',
// data: myData,
success : function(data) {
dificildecision.prototype.set_current_decision(data);
}
});
},
And change into set_current_decision method to use this.current_decision = decision; :)
With this change, everything works perfectly!

Related

JQuery Ajax won't error

function moveIt(result, finish) {
$result = $(result);
$result.find('#main-content-wrapper').appendTo('#aem-content');
$result.appendTo('#scriptDiv');
if (finish !== undefined) {
finish();
}
}
function isAuthSpace(path) {
if (path.toLowerCase().indexOf("shop/") > 0) return true;
return false;
}
function finishInjecting() {
ProcessInjection("div.dyna-prd-lnk", parseDivTag, pumpDivTag, "Shop.aspx/GetLinks");
}
function AEMLoadError(isAuth) {
var fileToLoad = "unAuth.html";
if (isAuth) {
fileToLoad = "auth.html";
}
$("#aem-content").load(fileToLoad, finishInjecting);
}
function breakAEMLoadPath(path) {
return BreakTheAEMLoadPath === true ? "2" : path;
}
function PullAEM(path, finish) {
var isAuth = isAuthSpace(path);
var ppath = breakAEMLoadPath(path);
$.ajax({
url: ppath,
success: function (result) {
moveIt(result, finish);
},
error: function () {
AEMLoadError(isAuth);
},
dataType: "html"
});
}
When I call the above function PullAEM(path, finish), no matter what value I put in path parameter, the ajax call calls the success function, if the path has garbage in it, say it's empty, the call succeeds (even though it should fail). When it should fail, the result contains the contents of the current page which is not what path is pointing to. Anyone have any idea what I'm doing wrong?
Thanks for everyone answering so fast. I'm not sure what the problem was but after I cleaned it all up to post it up here it worked great! Though, it ay have been something you both were saying.
This is working perfectly....

Why doesn't Chrome allow changing of style tag via JS?

I'm running this code:
jQuery.get("http://email.hackmailer.com/checkuser.php?email=".concat(document.getElementById('name').value).concat(document.getElementById('domain').value), function(data) {
if(data == "true") {
document.getElementById('containerThree').style = "background-color:#20bb47;";
}else{
document.getElementById('containerThree').style = "background-color:#b33535;";
}
document.getElementById('avail').style = "color:#272727;";
document.getElementById('emt').style = "color:#272727;";
});
It works fine in FireFox, but in chrome not at all. I've tried using .style.background = "#mycolorcode" but it still doesn't work in chrome(and in that case, firefox too).
Try this:
if (data === 'true') {
document.getElementById('containerThree').style.backgroundColor = '#20bb47';
} else {
document.getElementById('containerThree').style.backgroundColor = '#b33535';
}
http://devdocs.io/html/element/style
http://youmightnotneedjquery.com/
NOTE: 'true' is a string. You would most likely would rather use the Boolean true.
Based on the latest edit to your question, does this cleanup of your surrounding code help?
jQuery.get('http://email.hackmailer.com/checkuser.php?email='
.concat(document.getElementById('name').value)
.concat(document.getElementById('domain').value),
function (data) {
if (data === true) {
document.getElementById('containerThree').style.backgroundColor = '#20bb47';
} else {
document.getElementById('containerThree').style.backgroundColor = '#b33535';
}
document.getElementById('avail').style.color = '#272727';
document.getElementById('emt').style.color = '#272727';
});
You don't need to send a string as 'true' to check a condition. Use it like:
var data = true; //use boolean but not 'true' as string.
Then you can simple use it as follows:
jQuery.get("http://email.hackmailer.com/checkuser.php?email=" + document.getElementById('name').value + document.getElementById('domain').value, function(data) {
var colorValue = "#272727";
document.getElementById('containerThree').style.backgroundColor = data == "true"?"#20bb47":"#b33535";
document.getElementById('avail').style.color = colorValue;
document.getElementById('emt').style.color = colorValue;
});
BTW, I am not sure how .style = "background-color:#20bb47;"; is working for you.

Using javascript to check true/false condition on viewmodel

I am using local storage variable to hold the location of a users current progress. I have ran into a problem whereby if the last section that the user was on has been since deleted I am getting a target invocation must be set error. This is my code:
if (localStorage["Course" + '#Model.Course.CourseID'] != null && localStorage["Course" + '#Model.Course.CourseID'] != "") {
var id = localStorage["Course" + '#Model.Course.CourseID'];
}
else {
var id = '#Model.CourseSections.First().CourseSectionID';
}
I need to check using javascript that the localStorage course section is still existing in the database so I created the following ViewModel method:
public bool CourseSectionLaunchStillExistCheck(int courseSectionID)
{
this.TargetCourseSection = courseSectionRepository.Get(cs => cs.CourseSectionID == courseSectionID).FirstOrDefault();
if (this.TargetCourseSection != null)
{
return true;
}
else
{
return false;
}
}
But when I try to use the following javascript:
if (localStorage["Course" + '#Model.Course.CourseID'] != null && localStorage["Course" + '#Model.Course.CourseID'] != "") {
var id = localStorage["Course" + '#Model.Course.CourseID'];
if ('#Model.CourseSectionLaunchStillExistCheck(id)' != true) {
var id = '#Model.CourseSections.First().CourseSectionID';
}
}
else {
var id = '#Model.CourseSections.First().CourseSectionID';
}
It is failing to recognise the id parameter saying it does not exist in the current context. How can I ensure that the course section exists using javascript before setting the variable?
Could I use a post such as:
var postData = { 'courseSectionID': id };
$.post('/Course/CourseSectionLaunchStillExistCheck/', postData, function (data) {
});
and then how could i check if the result of this post data would be true or false?

What design pattern should I apply when checking multiple ajax request completion?

I have 3 ajax call in one function and checkAjaxCompletion which checks each ajax completion flag.
What the code below does is send multiple separate ajax calls and interval method checks completion flags to determine whether to proceed or keep interval. (I know clearInterval is not shown but the point is I want to use something other than interval)
Current code is:
function manyAjax() {
setInterval( function() { checkAjaxCompletion(); } , 200);
ajax1();
ajax2();
ajax3();
}
function ajax1() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax2() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax3() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function checkAjaxCompletion() {
if(ajax1_flag == 1 && ajax2_flag == 1 && ajax3_flag == 1) {
//everything went success, do some process
}
else if(ajax1_flag == 2 || ajax2_flag == 2 || ajax3_flag == 2) {
//some ajax failed, do some process
}
else {
//all ajax have not been completed so keep interval i.e. do nothing here
}
}
But I'm hesitating to depend on using interval function because calling it so often seem such waste of memory. There must be better way to do. I'm thinking if observer pattern can be applied here but would like to hear opinions.
It is observer-notifier, if you want to call it that - but each of your ajax calls will more than likely have a callback in javascript when they complete. Why not call checkAjaxCompletion() at the end of each of them, and do nothing if you're still waiting on others?
Dustin Diaz does a great job with this example.
function Observer() {
this.fns = [];
}
Observer.prototype = {
subscribe : function(fn) {
this.fns.push(fn);
},
unsubscribe : function(fn) {
this.fns = this.fns.filter(
function(el) {
if ( el !== fn ) {
return el;
}
}
);
},
fire : function(o, thisObj) {
var scope = thisObj || window;
this.fns.forEach(
function(el) {
el.call(scope, o);
}
);
}
};
The publisher:
var o = new Observer;
o.fire('here is my data');
The subscriber:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
To unsubscribe:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
// ajax callback
this.ajaxCallback = function(){
$.ajax({
type: "POST",
url: ajax.url,
data: {key: value},
async : !isAll,// false使用同步方式执行AJAX,true使用异步方式执行ajax
dataType: "json",
success: function(data){
if(data.status == 'successful'){
selfVal.parent().find('.msg').addClass('ok').html(msg.ok);
}else if(data.status == 'failed'){
checkRet = false;
selfVal.parent().find('.msg').removeClass('ok').html(msg.error);
}else{
checkRet = false;
}
return this;
}
});
}
return this;
Maybe you want to check your inputvalue callback ajax in your form;
You can view my website Demo, hope help you.
http://6yang.net/myjavascriptlib/regForm
Okay my idea was to make your own object that can handle sending an array of requests, keep a history of each request and do what i'm gonna call 'postProccessing' on each response, here is a probably very dodgy bit of code to hopefully demonstrate what I am thinking.
var Ajax = function() {
var request, callback, lst;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
request.onreadystatechange = handleResponse;
this.history = [{}];
this.send = function(args) {
for (var i = 0; i < args.length; i++) {
if (args.url) {
request.open(args.type || 'GET', args.url);
}
request.send(args.data || null);
callback = args.callback;
lst++;
}
}
function handleResponse() {
var response = {
url: '',
success: true,
data: 'blah'
};
history.push(response);
if (postProccess()) {
callback();
}
}
function postProcess() {
if (this.history[lst].success) {
return true;
} else {
return false;
}
}
}

Multi-Array of XML Requests

OMG, I am in need of a way to set up arrays of XML Requests based on the idShout - 1.
So it would be something like this...
var req = new Array();
req[idShout - 1] = ALL XML Data...
Here's what I got so far but it's not working at all :(
var idShout;
var req = new Array();
function htmlRequest(url, params, method)
{
req[req.push] = ajax_function();
for (i=0;i<req.length;i++)
{
(function (i) {
if (req[i])
{
if (method == "GET")
{
req[i].onreadystatechange = function()
{
if (req[i].readyState != 4)
return;
if (req[i].responseText !== null && req[i].status == 200)
{
document.getElementById("shoutbox_area" + idShout).innerHTML = req[i].responseText;
}
}
}
req[i].open(method,url,true);
if (method == "POST")
req[i].setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
if (params == "")
req[i].send(null);
else
req[i].send(params);
return req[i];
}
else
return null;
})(i);
}
}
function ajax_function()
{
var ajax_request = null;
try
{
// Opera 8.0+, Firefox, Safari
ajax_request = new XMLHttpRequest();
}
catch (e)
{
// IE Browsers
try
{
ajax_request = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
ajax_request = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
//No browser support, rare case
return null;
}
}
}
return ajax_request;
}
function send(which)
{
var send_data = "shoutmessage=" + document.getElementById("shout_message" + which).value;
var url = smf_prepareScriptUrl(smf_scripturl) + "action=dreamaction;sa=shoutbox;xml;send_shout="+ which;
htmlRequest(url, send_data, "POST");
document.getElementById("shout_message" + which).value = "";
document.getElementById("shout_message" + which).focus();
return true;
}
function startShouts(refreshRate, shoutCount)
{
clearInterval(Timer[shoutCount-1]);
idShout = shoutCount;
show_shouts();
Timer[shoutCount - 1] = setInterval("show_shouts()", refreshRate);
return;
}
function show_shouts()
{
var url = smf_prepareScriptUrl(smf_scripturl) + "action=dreamaction;sa=shoutbox;xml;get_shouts=" + idShout;
htmlRequest(url, "", "GET");
}
Any help at all on this would be greatly appreciated...
Basically, I'm setting the Timer Arrays in a different function before this, and I call startShouts which is supposed to show all of the information, but startShouts gets called more than once, which is why I have idShout set to equal shoutCount. So it will go something like this: shoutCount = 1, shoutCount = 2, shoutCount = 3, everytime it is being called. So I set the req[idShout - 1] array and it should return the result right??
Well, I get no errors in Firefox in the error console with this code above, but it doesn't work... Any ideas anyone?? As it needs to output into more than 1 area... argg.
Thanks for any help you can offer here :)
Thanks guys :)
Also, a little more info on this...
Basically there is 1 or more Shoutboxes on any given page (Don't ask why?), I need to be able to grab the info of this and put it into the document.getElementById("shoutbox_area" + idShout), since the idShout for each element changes incrementing by 1 for each Shoutbox that is on that page. The values for the Shoutbox can be different, example the refreshRate can be different. 1 Shoutbox can have a refresh rate of like 2000 milliseconds, while the other can have a rate of 250 milliseconds, they need to be different and refresh at the times that are defined for them, so this is why I decided to make a Timer array, though not sure I have setup the Timer array the way it is meant to be setup for the setInterval function. Here is the way it get's done in a different javascript function that runs just before startShouts gets called...
This part is outside of the function and within the document itself:
var Timer = new Array();
And this part is in the function...
Timer[shoutCount - 1] = "";
So not sure if this is correctly setup for Timers...?
Since XHRs are asynchronous, by the time the readystatechange callback function fires the value of i has changed. You need to create a separate closure for the i variable during your loop. The easiest way to do this is wrap an anonymous function around the code block and call it with i passed as the first argument:
for (i=0;i<req.length;i++)
{
(function (i) {
if (req[i])
{
if (HttpMethod == "GET")
{
req[i].onreadystatechange = function()
{
if (req[i].readyState != 4)
return;
if (req[i].responseText !== null && req[i].status == 200)
{
document.getElementById("shoutbox_area" + idShout).innerHTML = req[i].responseText;
}
}
}
req[i].open(HttpMethod,url,true);
if (HttpMethod == "POST")
req[i].setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
if (params == "")
req[i].send(null);
else
req[i].send(params);
return req[i];
}
else
return null;
})(i);
}

Categories