I have a very strange issue that I am running into. I am using jsTree from JQueryUI on one of my sites, and I have different implementations of it used in different .js files. One of them seems to work, which is very confusing as it uses almost identical code (only the variable names are different) to the implementation that is broken. The problem comes from the contextmenu function. The code I am using is as follows:
$(document).ready(function () {
if(typeof dryerList == 'undefined' || dryerList.length == 0) {
var dryerList = [];
$.ajax({
url:'../TrackingApp/getGrainBins.php?t=234.23423452353',
async: false,
success: function(text) {
try {
dryerList = $.parseJSON(text);
} catch (e) {
alert('ERROR: ' + e);
}
if(dryerList.length == 0) {
alert('ERROR: No fleet data received.')
}
}
});
}
$("#dryerListTree").jstree({
plugins : ['json_data', 'ui', 'themes', 'contextmenu'],
contextmenu: {items: customBinMenu},
json_data : { data: binNodes }
});
$('#dryerListTree').bind("dblclick.jstree", function (event) {
var node = $(event.target).closest("li");
var id = node[0].id;
for(i=0; i < dryerList.length; i++) {
if(id == dryerList[i].id) {
centerMap(dryerList[i].y, dryerList[i].x);
break;
}
}
});
});
function customBinMenu(node) {
if ($(node).hasClass("folder")) {
return;
}
var items = {
centerItem: {
label: "Locate",
action: function () {
// Centers map on selected bin
var id = node[0].id;
for(i=0; i < dryerList.length; i++) {
if(id == dryerList[i].id) {
centerMap(dryerList[i].y, dryerList[i].x);
break;
}
}
}
},
dashboardItem: {
label: "Dashboard",
action: function () {
// Opens dryer info window over map
var id = node[0].id;
var dryerIndex = -1;
for(i=0; i < dryerList.length; i++) {
if(id == dryerList[i].id) {
dryerIndex = i;
break;
}
}
}
}
};
return items;
}
The strange bit is, the double-click handler works just fine. When I get to the customBinMenu() function, the dryerList array is there, and dryerList[0] contains 4 of the 5 values that it should- but somehow the 'id' element has been dropped from that object. I have been looking at this for quite some time, and I can't figure out how it can drop a single element from the object without losing any other data, especially when identical code is working for a similar list. Any suggestions?
Ok, I read in your question: 'and dryerList[0] contains 4 of the 5 values that it should- but somehow the 'id' element has been dropped from that object'
So by 'element' and 'value' I assume you mean 'attribute': the node's 'id'-attribute to be precise ??
I see in your code: var id = node[0].id;
That should be: var id = node[0].getAttribute("id");
Good luck!
UPDATE 1:
Ok, if (as per your comment) var id = node[0].id; (getting id from node[0]) is ok, then if(id == dryerList[i].id) looks wrong, since you just (re-)defined id to be the value of node[0]'s id.
Actually I would not use 'id' as a var-name (in this case).
So what if you did: var idc = node[0].getAttribute("id");
and then: if(idc === dryerList[i].getAttribute("id"))
UPDATE 5: You still have some errors by the way:
You forgot a semi-colon to close the alert in:
if(dryerList.length == 0) {
alert('ERROR: No fleet data received.')
}
You should use '===' to compare with '0' on line 2 and 14
naturally in real life you would define function customBinMenu(node) before it was used in your document.ready function.
Fixed by swapping code order.
The same goes for this document.ready function where you used var dryerList before it was defined.
Fixed by: var dryerList = dryerList || []; if(dryerList.length === 0){//ajax & json code}
Could you please confirm if this fiddle, which is now valid javascript, represents your intended baseline-code that still results in your problem of the 'id'-attribute being 'undefined' in dryerList's node-collection (since the code you posted contained some simple errors that are fixed in this jsfiddle, excluding the things mentioned in update 1, since you commented that this is not the problem) ?
May I ask (since you start at document.ready), why do you (still) check if dryerList already exists?
May I ask if you could update that corrected fiddle with some demo-data for us to toy around with?
Related
I have coded a javascript file:
$(function() {
return $(".ajax-form").on("ajax:success", function(e, data, status, xhr) {
var model_name;
model_name = $(this).data('model-name');
console.log('ajax form success');
if (model_name === 'contact') {
return $('#modal-alert-contact').modal('show');
} else {
return $('#modal-alert-demo').modal('show');
}
}).bind("ajax:error", function(e, xhr, status, error) {
var elm, messages, model_name;
model_name = $(this).data('model-name');
console.log('ajax form error');
console.log(model_name);
if (model_name === 'contact') {
if (xhr.responseJSON["email"]) {
elm = $('.alert-contact-fields');
messages = [];
$.each(xhr.responseJSON, function(id, error_messages) {
return messages.push(("<li><strong class='titleize'>" + id + "</strong> - can't be blank</li>").replace(/_/g, " "));
});
elm.find('.messages').html(messages);
return elm.removeClass('hide');
} else {
elm = $('.alert-contact-fields');
return elm.addClass('hide');
}
} else {
if (xhr.responseJSON["company_name"]) {
elm = $('.alert-demo-fields');
messages = [];
$.each(xhr.responseJSON, function(id, error_messages) {
return messages.push(("<li><strong class='titleize'>" + id + "</strong> - can't be blank</li>").replace(/_/g, " "));
});
elm.find('.messages').html(messages);
return elm.removeClass('hide');
} else {
elm = $('.alert-demo-fields');
return elm.addClass('hide');
}
}
});
});
and I found it out messy, and repeating same codes.
What I'm want to do is this part:
messages = [];
$.each(xhr.responseJSON, function(id, error_messages) {
return messages.push(("<li><strong class='titleize'>" + id + "</strong> - can't be blank</li>").replace(/_/g, " "));
});
elm.find('.messages').html(messages);
return elm.removeClass('hide');
I want that part to be a function, and after I do that, I will call that function to use it on my function. Is it possible or there's some technique to improve my coding structure?
Thanks!
I think you want something like this:
$(function() {
var myform = $(".ajax-form");
var makeMessages = function(json) {
return $.map(json, function(error_messages, id) {
return ("<li><strong class='titleize'>" + id + "</strong> - can't be blank</li>").replace(/_/g, " ");
});
};
myform.on('ajax:success', function(e, data, status, xhr) {
var modal_to_show = ($(this).data('model-name') === 'contact') ? '#modal-alert-contact' : '#modal-alet-demo';
return $(modal_to_show).modal('show');
});
myform.on('ajax:error', function(e, xhr, status, error) {
var fields;
if ($(this).data('model-name') === 'contact') {
fields = $('.alert-contact-fields');
if (xhr.responseJSON["email"]) {
return fields.find('messages').html(makeMessages(xhr.responseJSON)).end().removeClass('hide');
}
return fields.addClass('hide');
}
fields = $('.alert-demo-fields');
if (xhr.responseJSON["company_name"]) {
return fields.find('.messages').html(makeMessages(xhr.responseJSON)).end().removeClass('hide');
}
return fields.addClass('hide');
});
});
makeMessages is a function that takes the json object and returns a set of strings; map() is a much better function for that than each(), because it requires no intermediate array to save the values.
The 'success' handler shows the use of the 'ternary operator', also known as a conditional expression. You want to know which modal to show: this is how you pick it, then have one and only one 'show' operation. It's way easier to debug.
For the 'error' handler, each time you set the messages, you just call makeMessages() with your JSON and get back the array of strings you want. Because you had to find the messages field inside the alert-*-fields, I call end() which pops the current jquery context back one search (from the 'find' to the initial $() call) and then call 'show' on it instead.
Since you call 'return' at the end of a chosen successful operation, there is no need at all for 'else' statements. They're noise. Either your code does its thing, or it falls through to the next stage.
You could remove my fields = set operations, since performance-wise each will only be called once, so it's harmless to have that repetition. But this makes explicit which region you're working in.
If you want to get insanely dense about what you're working on, put all the decision-making up top (what to work on, what to show), and make the rest of the code pure machinery, the 'how' part of your code. The 'error' handler becomes this:
myform.on('ajax:error', function(e, xhr, status, error) {
var handler = (($(this).data('model-name') === 'contact') ?
{ 'fieldclass': '.alert-contact-fields', 'objname': 'email' } :
{ 'fieldclass': '.alert-demo-fields', 'objname': 'company_name' });
var fields = $(handler.fieldclass);
if (xhr.responseJSON[handler.objname]) {
return fields.find('.messages').html(makeMessages(xhr.responseJSON)).end().removeClass('hide');
}
return fields.addClass('hide');
});
At which point 'makeMessages()' just becomes a nice, convenient function because it shows (and names! Good names are always important to maintenance) what you're doing with the JSON object.
One (well, two) last alternatives:
myform.on('ajax:error', function(e, xhr, status, error) {
var drawResults = function(fieldclass, objname) {
var fields = $(fieldclass);
if (xhr.responseJSON[objname]) {
return fields.find('messages').html(makeMessages(xhr.responseJSON)).end().removeClass('hide');
}
return fields.addClass('hide');
};
return ($(this).data('model-name') === 'contact' ?
drawResults('.alert-contact-fields', 'email') :
drawResults('.alert-data-fields', 'company_name'));
/* Absolutely minimal alternative, but some people find
* using the apply method obfuscating. */
return drawResults.apply(this, $(this).data('model-name') === 'contact' ?
['.alert-contact-fields', 'email'] :
['.alert-data-fields', 'company_name']);
});
Rather than use fields and decisions up front, this puts all the decision making at the end, and describes what will happen once the decision is made up front. This uses a more familiar syntax of calling a function. It's important to see that drawResults() has access to the xhr object already, so it isn't necessary to pass it in.
One last possible extraction is to turn $(this).data('model-name') === 'contact' into a function, like isDemo(), so that code only happens once and is also well-named.
I have scoured the other question/answer for this and implemented everything and I still cannot access the values of the object. Here's the code I am using:
function apply_voucher(voucher) {
var dates = $.parseJSON($("[name='dates']").val());
var voucher_yes_no = new Array();
var voucher_reduction = new Array();
if(voucher.length > 0)
{
$.each(dates, function(room_id, these_dates) {
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_yes_no.push('yes');
voucher_reduction.push(result.voucher_reduction);
} else {
voucher_yes_no.push('no');
}
}, 'json');
});
// check if there are any yes's in the array
if('yes' in voucher_yes_no) {
console.log("no yes's");
} else {
console.log(voucher_reduction);
console.log(typeof voucher_reduction);
for (var prop in voucher_reduction) {
console.log(prop);
console.log(voucher_reduction[prop]);
if (voucher_reduction.hasOwnProperty(prop)) {
console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
}
}
}
}
}
Apologies for the constant console logging - I'm just trying to track everything to make sure it's all doing what it should. The console output I get from this is below:
...which shows the object containing one value, "1.01" and my console.log of the typeof it to make sure it is actually an object (as I thought I was going mad at one point). After this there is nothing from inside the for-in loop. I have tried jquery's $.each() also to no avail. I can't understand why nothing I'm trying is working!
It does not work because the Ajax call is asynchronous!
You are reading the values BEFORE it is populated!
Move the code in and watch it magically start working since it will run after you actually populate the Array!
function apply_voucher(voucher) {
var room_id = "169";
var dates = $.parseJSON($("[name='dates']").val());
var voucher_reduction = new Array();
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_reduction.push(result.voucher_reduction);
}
console.log(voucher_reduction);
console.log(typeof voucher_reduction);
for (var prop in voucher_reduction) {
console.log(prop);
console.log(voucher_reduction[prop]);
if (voucher_reduction.hasOwnProperty(prop)) {
console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
}
}
}, 'json');
}
From what it looks like, you plan on making that Ajax call in a loop. For this you need to wait for all of the requests to be done. You need to use when() and then(). It is answered in another question: https://stackoverflow.com/a/9865124/14104
Just to say for future viewers that changing the way I did this to use proper deferred objects and promises, which blew my head up for a while, but I got there! Thanks for all the help, particularly #epascarello for pointing me in the right direction :) As soon as I started doing it this way the arrays began behaving like arrays again as well, hooray!
Here's the final code:
function apply_voucher(voucher) {
var booking_id = $("[name='booking_id']").val();
var dates = $.parseJSON($("[name='dates']").val());
if(voucher.length > 0) {
var data = []; // the ids coming back from serviceA
var deferredA = blah(data, voucher, dates); // has to add the ids to data
deferredA.done(function() { // if blah successful...
var voucher_yes_no = data[0];
var voucher_reduction = data[1];
if(voucher_yes_no.indexOf("yes") !== -1)
{
console.log("at least one yes!");
// change value of voucher_reduction field
var reduction_total = 0;
for(var i = 0; i < voucher_reduction.length; i++) {
reduction_total += voucher_reduction[i];
}
console.log(reduction_total);
}
else
{
console.log("there are no yes's");
}
});
}
}
function blah(data, voucher, dates) {
var dfd = $.Deferred();
var voucher_yes_no = new Array();
var voucher_reduction = new Array();
var cycles = 0;
var dates_length = 0;
for(var prop in dates) {
++dates_length;
}
$.each(dates, function(room_id, these_dates) {
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_reduction.push(result.voucher_reduction);
voucher_yes_no.push('yes');
} else {
voucher_yes_no.push('no');
}
++cycles;
if(cycles == dates_length) {
data.push(voucher_yes_no);
data.push(voucher_reduction);
dfd.resolve();
}
}, 'json');
});
return dfd.promise();
}
Can you show how voucher_reduction is defined?
I am wondering where the second line of the debug output comes from, the one starting with '0'.
in this line:
console.log(vouncher_reduction[prop]);
^
The name of the variable is wrong (then) and probably that is breaking your code.
I think there are no problem with your loop.
But perhaps with your object.
Are you sure what properties has enumerable ?
Try to execute this to check :
Object.getOwnPropertyDescriptor(voucher_reduction,'0');
If it return undefined, the property was not exist.
Sorry for the lack of description in title, it's difficult to explain.
So I have a simple signup page and I made a bunch of functions in my code that check things such as the username length, make sure the passwords match, etc..
The problem is, if there is more than one error in the users input, it only displays one error at the bottom.
HEre is the JSfiddle: http://jsfiddle.net/LCBradley3k/xqcJS/19/
Javascript:
$('#join').on('click', function () {
var correct = true;
$('input[type="text"], input[type="password"]').each(function (indx) {
var $currentField = $(this);
if ($currentField.val() === '') {
$currentField.addClass('empty');
correct = false;
$currentField.one('keydown', function () {
$currentField.removeClass('empty');
});
} else {
$currentField.removeClass('empty');
}
});
function userLength() {
var x = $('input[name="user"]').val();
if (x.length < 6) {
$('#answer').html('Less than six characters.');
$('input[name="user"]').addClass('empty');
return false;
} else {
return true;
}
}
function passwordCheck() {
var x = $('input[name="password"]').val();
var y = $('input[name="passwordcheck"]').val();
if (x === y) {
return true;
} else {
$('#answer').html('Two different passwords');
$('input[name="password"], input[name="passwordcheck"]').addClass('empty');
return false;
}
}
function validateForm() {
var x = $('input[name="email"]').val();
if (x.indexOf('#') !== -1 && x.lastIndexOf(".") !== -1) {
return true;
} else {
$('#answer').html('Not a valid email');
$('input[name="email"]').addClass('empty');
return false;
}
}
if (correct) {
if (userLength()) {
if (passwordCheck()) {
if (validateForm()) {
$('#answer').html('Thank You!');
setTimeout(function () {
$('.inputs').hide("slide", {
direction: "up"
}, 1000);
}, 2000);
}
}
}
} else {
$('#answer').html('Please fill highlighted fields.');
}
});
You can see that all of them edit the #('#answer') div with .html(). But only one is displayed when there is more than one error. Once that error is fixed and the button is pressed, it will then display the next error. I want them all to be displayed in a list.
I created a fiddle that may be of some help. The idea is to create an array with the errors in it like so:
var errors = [];
errors.push("Error 1");
errors.push("Error 2");
As you step through the validation, every time an error is encountered you simply push the error string onto the array. When you get to the end of the validation you need to compile these errors into html like that can be appended to your $('#answer') element. In this case the items are compiled into an unordered list. You can change this to fit your needs.
var content = "<ul>";
for(var a = 0, len = errors.length; a < len; a++) {
content += "<li>" + errors[a] + "</li>";
}
content += "</ul>";
$('#answer').html(content);
The html is built dynamically and stored in the variable content. content is then appended to your html element that displays the errors (in your case answer).
You have 2 issues with doing what you want.
First, you are only continuing your checks if the first one passes, due to your nested if statements.
Second, you are replacing the #answer html with the message, which means even if you do each check, you will only see the results of the last one.
A simple fix would be to un-nest your if statements, and keep a variable that tracks the overall pass state. Secondly, instead of using .html(), use .append(), but make sure to clear out #answer before starting your checks.
correct &= checkFilled();
correct &= userLength();
correct &= passwordCheck();
correct &= validateForm();
if (correct) {
// ...
}
Fiddle: http://jsfiddle.net/jtbowden/9cFKW/
Note: I made your form filled check it's own function to work better with this method.
You can do some more fancy things, like pushing error messages on an array, and then checking the array for errors at the end and appending all of the messages, but this should get you started.
I have been trying to build a question and answer app with Ajax. I need help creating a particular function. I have created XML files with different questions and answers. The basic idea is to use the "get" function to (1) load an XML questions file and (2) use the "display" and "math.random" functions to display a random "question" element (the corresponding "answer" element will be shown at the same time, but hidden from view by Javascript.) This is the format of the XML files I am using. These nodes are enclosed by a parent node, Words..
<WordQuestions>
<Question>Question1</Question>
<Answer>Answer1</Answer>
</WordQuestions>
<WordQuestions>
<Question>Question2</Question>
<Answer>Answer2</Answer>
</WordQuestions>
I need to create a function that can choose a question & answer element at random from the XML file, show it to the user, but NOT show it again on subsequent clicks by the user. So, once a question is shown to the user, it needs to be removed from the list of questions to be shown to the user on the next click. Does anybody know how to do this?
I have created a similar function that works like a charm, but it is limited in that it is too random - a questions & answer element may never be selected to show to the user, or it could be selected a disproportionate number of times. The user needs to practice with all of the questions. Here is a stripped-down version of this function.
<script language = "javascript">
function getCategory()
{
var XMLHttpRequestObject = false;
if (window.XMLHttpRequest) {
XMLHttpRequestObject = new XMLHttpRequest();
XMLHttpRequestObject.overrideMimeType("text/xml");
} else if (window.ActiveXObject) {
XMLHttpRequestObject = new
ActiveXObject("Microsoft.XMLHTTP");
}
if(XMLHttpRequestObject) {
var P = document.LoadCategory.Load.value;
if (P == "Category1") {XMLHttpRequestObject.open("GET", "Catgory1.xml", true)}
if (P == "Category2") {XMLHttpRequestObject.open("GET", "Category2.xml", true)}
if (P == "Category3") {XMLHttpRequestObject.open("GET", "Category3.xml", true)}
XMLHttpRequestObject.onreadystatechange = function()
{
if (XMLHttpRequestObject.readyState == 4 &&
XMLHttpRequestObject.status == 200) {
var xmlDocument = XMLHttpRequestObject.responseXML;
displayCategory(xmlDocument);
}
}
XMLHttpRequestObject.send(null);
}
}
function displayCategory (xmldoc)
{
Questionnodes = xmldoc.getElementsByTagName("Question");
Answernodes = xmldoc.getElementsByTagName("Answer");
var i = Math.floor((Math.random()*1000)%Questionnodes.length);
var i = Math.floor((Math.random()*1000)%Answernodes.length);
var displayText1 =
Questionnodes[i].firstChild.nodeValue;
var target = document.getElementById("targetDiv1");
target.innerHTML=displayText1;
var displayText2 =
Answernodes[i].firstChild.nodeValue;
var target = document.getElementById("targetDiv2");
target.innerHTML=displayText2;
}
</script>
Right now, I do not know if I am able to alter this code to get the function I want. I have tried parsing an XML file into a javascript array (and then randomly select and remove an element) but have gotten nowhere atm. If anyone has a few suggestions, I would be most grateful. Once again, I want a function that can randomly select a question & answer element from an XML file, but only show it to the user ONCE.
Cheers guys. (sorry this was so long-winded).
write a class with a var hasbeenshown, hasbeenanswered, useranswer, function getquestion, function getanswer.
the instanciated classes, filled with values from your xml file on load you can add to an array and use your random number to choose a random question.
here is a link to an example of how I would do what you're trying to : http://jsfiddle.net/dievardump/xL5mg/4/
I commented some parts of the code and I 'simulate' your getCategory method.
Note : From my code, I think what didn't manage to do is the 'pickRandom' method. I think you have almost all you need to do other parts.
What I do in my code :
I have a collection of Question and Answers
I have a QuestionAndAnswer constructor
When the server result come, I 'parse' the xml file and fill the collection with QuestionAndAnswer objects.
In the HTML is a 'load a question' button. When you click on it, it call the displayQuestion method.
This method picks (get and remove from) a random QandA object from the collection, then display the question and a button to see the associated answer.
Like i said in the comments, i decided to add question the one after the other, but you can change that by having only one question and response handler and modify its content.
Here is the code if one day jsfiddle decide to not work anymore :
Javascript
(function() {
// Question and Answer collection
var oQandACollection = {
collection : [],
length : 0,
// get a QandA object
get : function(i) {
if (i < this.length) {
return this.collection[i];
}
return null;
},
// add a QandA object
add : function(qanda) {
this.collection.push(qanda);
this.length++;
},
// remove a QandA object
remove : function(i) {
if (typeof this.collection[i] !== 'undefined') {
this.collection.splice(i, 1);
this.length--;
}
},
// randomly pick an object from the collection
pickRandom : function() {
if (this.length === 0) return null; // return null if there is no object in the collection
var i = Math.floor(Math.random() * this.length);
var qanda = this.get(i);
this.remove(i);
return qanda;
}
};
// Question and Answer Object
var QandA = function(xmlNode) {
var question = xmlNode.getElementsByTagName('Question')[0] || null;
var answer = xmlNode.getElementsByTagName('Answer')[0] || null;
if (question && answer) {
this.question = question.textContent;
this.answer = answer.textContent;
} else {
return null;
}
};
// function to use as ajax request handler
function fillQandA(xmlDoc) {
// get all WordQuestions elements
var wrappers = xmlDoc.getElementsByTagName('WordQuestions');
for(var i = 0, l = wrappers.length, qanda = null; i < l; i++) {
// create a new question from the current wrapper
// we could have perfom the getElementsByTagName('Question') here
// but since the code is really specific to your example i putted it in the constructor of QandA
// You can change it
qanda = new QandA(wrappers[i]);
if (qanda) {
oQandACollection.add(qanda);
}
}
};
var eList = document.getElementById('qa-list'),
eLoadQuestion = document.getElementById('load-qanda');
// functions to display a question
// i choosed to add question the one after the others,
// so i re-create html elements at every display
// but you also can modify it to have just one question at a time
// matter of choice
function displayQuestion() {
var qanda = oQandACollection.pickRandom(); // get a question
if (qanda) { // if there is a question
// create elements
var eQuestion = document.createElement('p'),
eAnswer = document.createElement('p'),
eBtn = document.createElement('button');
eQuestion.textContent = qanda.question;
eAnswer.textContent = qanda.answer;
eQuestion.classNAme += ' question';
eAnswer.className += ' answer';
eBtn.textContent = 'Show Answer';
// add click event listener to the button to show the answer
eBtn.addEventListener('click', function() {
eAnswer.style.display = 'block';
eList.removeChild(eBtn);
}, false);
eList.appendChild(eQuestion);
eList.appendChild(eAnswer);
eList.appendChild(eBtn);
}
};
// add click event handler on display
eLoadQuestion.addEventListener('click', displayQuestion, false);
// simulate xhr request
function getCategory() {
// fill fake Q&A xml document
var xmlDoc = document.createElement('root');
for(var i = 0, wrapper = null, question = null, answer = null; i < 10; i++) {
wrapper = document.createElement('WordQuestions');
question = document.createElement('Question');
question.textContent = 'Question ' + (i+1);
answer = document.createElement('Answer');
answer.textContent = 'Answer ' + (i+1);
wrapper.appendChild(question);
wrapper.appendChild(answer);
xmlDoc.appendChild(wrapper);
}
// us as xhr request handler like : fillQandA(XMLHttpRequestObject.responseXML);
fillQandA(xmlDoc);
}
getCategory();
// test function
function test() {
for(var i = oQandACollection.length; i--; ) {
displayQuestion();
}
}
//test();
})();
HTML
<div class="wrapper">
<div id="qa-list">
</div>
<button id="load-qanda" value="Load new question">Load new question</button>
</div>
CSS
.wrapper {
width : 500px;
}
.wrapper > div {
position : relative;
width : 100%
}
.answer {
display : none;
}
I was trying to show a text gradually on the screen (like marquee). e.g. H.. He.. Hell.. Hello. when I'm tracing it in debug in VS2010 it's working! but when it's actually running it shows the whole sentence at once.
I made a certain "delay" for about 3 seconds between each letter so it would suppose to take a while, but in reality it's shows everything immediately.
Who's the genius to solve this mystery? (please don't give me advices how to create the marquee effect, it's not the issue anymore. now it's just a WAR between me and javascript!) I'm assuming that it has to do with synchronization when calling function from function?
Thanks to whomever will help me get my sanity back.
you can download the code from here (VS project):
http://pcgroup.co.il/downloads/misc/function_from_function.zip
or view it here:
<body>
<script type="text/javascript">
//trying to display this source sentence letter by letter:
var source = "hi javascript why are you being such a pain";
var target = "";
var pos = 0;
var mayGoOn = false;
//this function calls another function which suppose to "build" the sentence increasing index using the global var pos (it's even working when following it in debug)
function textticker() {
if (pos < source.length) {
flash();
if (mayGoOn == true) {
pos++;
mayGoOn = false;
document.write(target);
textticker();
}
}
}
function flash() {
//I tried to put returns everywhere assuming that this may solve it probably one of them in not necessary but it doesn't solve it
if (mayGoOn == true) { return; }
while (true) {
var d = new Date();
if (d.getSeconds() % 3 == 0) {
//alert('this suppose to happen only in about every 3 seconds');
target = source.substring(0, pos);
mayGoOn = true;
return;
}
}
}
textticker();
</script>
You're obviously doing it wrong. Take a look at this.
var message = "Hello World!";
function print(msg, idx) {
if(!idx) {
idx = 0;
}
$('#hello').html(msg.substring(0, idx));
if(idx < msg.length) {
setTimeout(function() { print(msg, idx + 1) }, 200);
}
}
print(message);
Demo: http://jsbin.com/evehus