I am trying to create a jquery questionnaire but my little jquery knowledge doesn't help me.
What I have until now is the following http://valogiannis.com/stackoverflow/quest.html
When you click Questions a popup open with two questions.
I want the following: when the user click one of the two answer, the script check his answer. The array CheckFirstAnswer is responsible to "tell" if the first answer is wrong or correct, 0 for wrong, 1 for correct. If user click the correct answer then I want to appear the next question with its answers from the arrays Question,FirstAnswer,SecondAnswer otherwise the corresponding Conclusion proportionately the i value.
I would appreciate any help.
Thanks
[Working demo]
Question manager
// question number
var currentQ = -1;
function showNewQuestion(el) {
currentQ++; // increment question number
$('.messagepop').html( Question[currentQ] + '<br />' +
'<a href="#" class="first">'
+ FirstAnswer[currentQ] + '</a><br />' +
'<a href="#" class="second">'
+ SecondAnswer[currentQ] + '</a><br />' +
'close' );
}
function validate(answer) {
var firstIsTrue = CheckFirstAnswer[currentQ];
// correct answer (new question)
if ( firstIsTrue && answer == 1
|| !firstIsTrue && answer == 2 ) {
showNewQuestion();
}
// incorrect answer (conclusion)
else {
$('.messagepop').html(Conclusion[currentQ]);
}
}
Click handler
$(function () {
$("#container_div").live('click', function (event) {
// which element was clicked
var el = $(event.target);
// first answer was clicked
if (el.hasClass("first")) {
validate(1);
}
// second answer was clicked
else if (el.hasClass("second")) {
validate(2);
}
// questions opener was clicked
else if (el.attr("id") == "questions") {
el.addClass("selected").parent()
.append('<div class="messagepop pop" />');
showNewQuestion();
$(".pop").slideFadeToggle();
}
// popup close was clicked
else if (el.hasClass("close")) {
$(".pop").slideFadeToggle();
$("#questions").removeClass("selected");
}
});
});
You should use $.ajax to send back the answer so that the server can evaluate the answer and send the next question.
Currently, any one with a basic knowledge of JS can see the CheckFirstSnswer array and know the correct answer.
You have an HTML page on the site, hence I don't know the server side programming language you are using.
Make a new page that accepts posts from this page and evaluates the request. This page will send the question id, answer/s selected and auth'ed userid to the new page. The new page will maintain the score at server side and send the next questions
Related
I am trying to get a current score to add up every time an answer is correct, what is happening is that I have the questions in a pagination set up and when this answer is correct it give me the score but then when it goes to the next page it refresh the score and if I got that one right it just give me the score for that one again but it doesn't add up.
JS code:
$(function() {
$('#author').on('change', function(event) {
var opt = this.options[ this.selectedIndex ];
var correct = $(opt).text().match (arr2);
var score = 0;
if (correct){
alert('Good job ' + arr2,);
score += 2;
alert (score);
currentScore = score++;
alert(currentScore);
display(currentScore);
}
else {
alert ('nice try ' + arr2);
}
});
});
Here is another option - local storage.
Here is a reference W3School Web storage
It's not the most ideal solution, but it can meet your criteria.
let score = localStorage.getItem('score')
score++;
localStorage.setItem('score', score);
Your pages will be able to access the localStorage so you can get the value of score and re-set it.
Hopefully the reference can answer further questions, else leave a comment!
Con: It may not be supported by all browsers.
EDIT:
Here is an example with your code.
$(function() {
let currentScore = localStorage.getItem('score'); // get score
if (currentScore === null){ // if score doesnt exist yet
localStorage.setItem('score', 0); // set score
currentScore = 0; // make currentScore 0
}
$('#author').on('change', function(event) {
var opt = this.options[ this.selectedIndex ];
var correct = $(opt).text().match (arr2);
if (correct){
alert('Good job ' + arr2);
currentScore += 2; //increment current score by 2
alert (currentScore);
localStorage.setItem('score', currentScore); // set the item again with new value
alert(currentScore);
display(currentScore);
}
else {
alert ('nice try ' + arr2);
}
});
});
Edit 2:
let currentScore = localStorage.getItem('score'); // get score
currentScore = parseInt(currentScore);
it give me the score but then when it goes to the next page it refresh the score and if I got that one right it just give me the score for that one again but it doesn't add up.
I think your problem is there.
If I understand correctly, when the answer is good, the page refresh and passes to the next question. Your problem is that the score doesn't add up to the previous one.
The score variable is only stored in the current page, like a temporary one. Without saving the score on the server, via ajax or another method, and getting it on the next page, it will not add up. Indeed, score will have a value of 0 due to the refresh.
A simple schema :
score = 0 -> correct answer -> +50 point -> score = 50 -> next page -> score = 0
As you can see, because the javascript you wrote is not assuring the persistance of your information, the previously stored score is lost.
You need to send the score on the server and then get it back when the new page is loaded or to avoid changing page and make your quizz on one and only page, without refreshing.
Keep in mind that everytime you are refresing a page, the javascript is starting again and therefore everything done before is lost.
I hope this was helpful.
Ps: You should place your code in the $( document ).ready(); block just like this :
$( document ).ready(function() {
console.log( "ready!" );
});
It will make your code start when the html DOM (the structure of the html file) is loaded and ready to be manipulated. It can avoid a lot of errors.
Edit2 : What it will look like in your code :
$( document ).ready(function() {
$('#author').on('change', function(event) {
var opt = this.options[ this.selectedIndex ];
var correct = $(opt).text().match (arr2);
var score = 0;
if (correct){
alert('Good job ' + arr2,);
score += 2;
alert (score);
currentScore = score++;
alert(currentScore);
display(currentScore);
}
else {
alert ('nice try ' + arr2);
}
});
});
Or, to make this more readable and to avoird having a lot of things in the document.ready block (when you will have a lot of lines/functions) :
$( document ).ready( myNiceFunction() );
var myNiceFunction = function(){
$('#author').on('change', function(event) {
var opt = this.options[ this.selectedIndex ];
var correct = $(opt).text().match (arr2);
var score = 0;
if (correct){
alert('Good job ' + arr2,);
score += 2;
alert (score);
currentScore = score++;
alert(currentScore);
display(currentScore);
}
else {
alert ('nice try ' + arr2);
}
}
Ps2 : I know this is not the best website to explain it but I think it is simple enough to make you understand the principle of ajax without losing you into a bunch of technical stuff : here and here
Edit : Grammar and second post-scriptum.
Not sure how you're doing pagination but it should be ajaxed, instead of a full postback, so you don't lose the values on your page.
I am new at AJAX and JQuery and trying to use them in the part of my website. Basically the website that I have, has this kind of design and currently it is functional (Sorry for my poor paint work :)
The items in the website are created by user. This means item number is not constant but can be fetched by db query.
Each item has a unique URL and currently when you click an item, all page is refreshing. I want to change the system to let the user have a chance to navigate quickly between these items by only chaning middle content area as shown above. However I also want to have a unique URL to each item. I mean if the item has a name like "stack overflow", I want the item to have a URL kind of dev.com/#stack-overflow or similar.
I don't mind about the "#" that may come from AJAX.
In similar topics I have seen people hold constant names for items. For instance
<a href="#ajax"> but my items are not constant.
WHAT I HAVE TRIED
Whats my idea is; while fetching all item's links, I'm holding links in $link variable and using it in <a href="#<?php echo $link; ?>">.
Inside $link it is not actual URL. it is for instance a name like "stack-overflow" as I ve given example above. Until this part there is no problem.
PROBLEM
In this topic a friend suggested this kind of code as an idea and I ve changed it for my purpose.
<script>
$(document).ready(function() {
var router = {
"<?php echo $link ?> ": "http://localhost/ajax_tut/link_process.php"
};
$(window).on("hashchange", function() {
var route = router[location.hash];
if (route === undefined) {
return;
} else {
$(".content-right").load("" + route + " #ortadaki_baslik");
}
});
});
</script>
I'm trying to post the value of $link to the link_process.php and at link_process.php I will get the value of $link and arrange neccessary page content to show.
The questions are;
- How should I change this code to do that?
- I couldnt see someone doing similar to take as an example solve this
issue. Is this the right way to solve this situation?
- Do you guys have a better solution or suggestion for my case?
Thanks in advance.
WHEN your server side AJAX call handler [PHP script - handling AJAX requests at server side] is constant and you are passing item_id/link as GET parameter...
For example:
localhost/ajax_tut/link_process.php?item_id=stack-overflow OR
localhost/ajax_tut/link_process.php?item_id=stack-exchange
Then you can use following code.
<script>
$(document).ready(function() {
var ajax_handler = "localhost/ajax_tut/link_process.php?item_id=";
$(window).on("hashchange", function() {
var route = location.hash;
if (route === undefined) {
return;
} else {
route = route.slice(1); //Removing hash character
$(".content-right").load( ajax_handler + route );
}
});
});
</script>
WHEN you are passing item_id/link as URL part and not parameter...
For example:
localhost/ajax_tut/stack-overflow.php OR
localhost/ajax_tut/stack-exchange.php
Then you can use following code.
<script>
$(document).ready(function() {
var ajax_handler = "localhost/ajax_tut/";
$(window).on("hashchange", function() {
var route = location.hash;
if (route === undefined) {
return;
} else {
route = route.slice(1); //Removing hash character
$(".content-right").load( ajax_handler + route + ".php");
}
});
});
</script>
WHEN Your server side AJAX handler script url is not constant and varies for different items...
For example: localhost/ajax_tut/link_process.php?item_id=stack-overflow OR localhost/ajax_tut/fetch_item.php?item_id=stack-exchange OR localhost/ajax_tut/stack-exchange.php
Then I suggest to change PHP script which is generating item's links placed on left hand side.
<?php
foreach($links as $link){
// Make sure that you are populating route parameter correctly
echo '<a href="'.$link['item_id'].'" route="'.$link['full_ajax_handler_route_url_path'].'" >'.$link['title'].'</a>';
}
?>
Here is Javascript
<script>
$(document).ready(function() {
var ajax_handler = "localhost/ajax_tut/"; //Base url or path
$(window).on("hashchange", function() {
var route = location.hash;
if (route === undefined) {
return;
} else {
route = route.slice(1); //Removing hash character
route = $('a [href="'+.slice(1)+'"]').attr('route'); //Fetching ajax URL
$(".content-right").load( ajax_handler + route ); //Here you need to design your url based on need
}
});
});
</script>
Section on my website with a list of fixtures.
When I click on one it loads the fixture information in a modal window - each club might have an image so I want to check if there is an image and if so display it otherwise display a generic image.
Code is below:
$('#fixModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var hclub = button.data('hclubid')
imgpath = "/images/clubcrests/"
homecrest = imgpath + hclub + '.jpg'
gencrest = imgpath + 'generic.jpg'
$.get(homecrest)
.done(function() {
homecrestsrc = "<img src='" + homecrest + "'>"
}).fail(function() {
homecrestsrc = "<img src='" + gencrest + "'>"
})
var modal = $(this)
modal.find('.fixmodhomec').html(homecrestsrc)
})
But first time I click on it I get the error:
homecrestsrc is not defined
$.get seems to run after the modal.find.
If I click on it again it displays but always the image it should have from the previous time the button was clicked.
How can I make sure the $.get bit runs first?
$.get is asynchronous - did you read the documentation? modal.find will have run long before the response from the AJAX call has come back.
You need to move your logic inside the callbacks.
$('#fixModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget),
hclub = button.data('hclubid'),
modal = $(this),
imgpath = "/images/clubcrests/",
homecrest = imgpath + hclub + '.jpg',
gencrest = imgpath + 'generic.jpg',
homecrestsrc;
$.get(homecrest).done(function () {
homecrestsrc = "<img src='" + homecrest + "'>"
}).fail(function () {
homecrestsrc = "<img src='" + gencrest + "'>"
}).always(function () {
modal.find('.fixmodhomec').html(homecrestsrc);
});
})
This is the confusing part of js/ajax. This code does not wait for an ajax reaponse, but instead jumps strait on to the next command. Meaning it will continue with your last 2 lines of code, and then the response will come thru, and then it will set homecrestsrc for the first time. Whatever you expect to be done AFTER you get a reaponse, you put in done and fail. So put your last or last 2 lines of code inside the done and fail functions.
Sry typing from phone so i cant explain too much, but hope you understand, it takes time to get it bcs this is not so obvious when you start
The other answer kind of covered this... basically, if the code below the get request depends on that result, it needs to be inside the .done() block.
However, I'd also like to point out that having your image displaying depend on the whether a get request fails or not is bad practice. You should instead have your api route return true if that image exists or false if it doesn't. Then you can filter the correct picture in a .success() block.
.fail() should be reserved for debugging only.
I'm trying to work through an assignment to further my understanding of js but I'm running into some issues that are keeping me from final code. The code executes a short quiz- inputs from radio buttons are taken in and matched to an object containing answers, then outputting a final score.
code at http://jsfiddle.net/8ax9A/3/
issues I'm aware of now :
my $response variable doesn't seem to work.
var $response = $('[name=rad]:checked').val();
counter is listening for clicks through questions. After the last question, I want to report final score. I can't get counter to reach the end of questions + 1, and I cant get an accurate final score listener reported (var finalScore).
if ($response == parseInt(questions[counter].answer, 10)) {
finalScore++;
}
Those are just snippets so check out the fiddle for full code. I'd love some suggestions on how to understand where I'm going wrong.
Here is one way you could do it:
//Initialization
var counter=0;
var score=0;
loadQuestion();
$('#next').on('click',answer);
//functions
function answer(){
// if the user did not answer
if ($('input:radio:checked').length == 0){
alert('You have to answer!');
return;
}
var currentQ=questions[counter];
// if answer is correct
if($('[name=rad]:checked').val()==currentQ.answer){score++;}
counter++;
// if there are no questions left
if(counter >= questions.length) {displayResults(); return;}
loadQuestion();
}
function loadQuestion(){
// clear the radio buttons
$("input:checked").removeAttr("checked");
var currentQ=questions[counter];
// display the question
$('h1').text(currentQ.question);
$('#a1').text(currentQ.choices[0]);
$('#a2').text(currentQ.choices[1]);
$('#a3').text(currentQ.choices[2]);
}
function displayResults(){
$("h1").text("You've finished with a score of " + score + "!");
$('[name=rad], #a1, #a2, #a3, #next').remove();
}
JS Fiddle
I've created a form that is used to calculate monthly expenses. The problem I'm having is on the last page I'm gathering information from previous pages (session to data) that auto fills the fields on the last page. I've created a Javascript that is suppose to subtract the five fields on the page for a grand total but this doesn't work. If I delete the session to data from the load section the Javascript works perfectly.
Page in Question:
http://www.garranteedsolutions.com/budget?chronoform=BudgetPage7
Javascript:
window.addEvent('domready', function() {
$('spendable').addEvent('change', rekenen1);
$('housetotal').addEvent('change', rekenen1);
$('cartotal').addEvent('change', rekenen1);
$('creditortotal').addEvent('change', rekenen1);
$('misctotal').addEvent('change', rekenen1);
});
function rekenen1(){
$('grandtotal').value = Number($('spendable').value) + Number($('housetotal').value) + Number($('cartotal').value) + Number($('creditortotal').value) + Number($('misctotal').value) ;
}
This is the code that I had been using but it requires a change in the form box to perform the action. I've tried this
Javascript:
window.addEvent('domready', function() {
rekenen1;
$('spendable').addEvent(rekenen1);
$('housetotal').addEvent(rekenen1);
$('cartotal').addEvent(rekenen1);
$('creditortotal').addEvent(rekenen1);
$('misctotal').addEvent(rekenen1);
});
function rekenen1(){
$('grandtotal').value =
Number($('spendable').value) + Number($('housetotal').value)
+ Number($('cartotal').value) + Number($('creditortotal').value)
+ Number($('misctotal').value);
}
This is a continuation of me searching for help starting here: http://www.chronoengine.com/forums/viewtopic.php?f=2&t=67427&p=269741#p269741
I don't know Javascript very well and I'm so close to having this form completed. I just can't get the Grand Total to tally up.
The problem is that the events are only firing when you change the values of the form. The form its readonly so they cannot be changed.
Anyway, here is the code optimized:
window.addEvent('domready', function() {
var rekenen1 = function(){
var grandTotal = 0;
$$('#spendable, #housetotal, #cartotal, #creditortotal, #misctotal').each(function(el){
if(el.value.length > 0) grandTotal += el.value.toFloat();
});
$('grandtotal').value = grandTotal;
};
$$('#spendable, #housetotal, #cartotal, #creditortotal, #misctotal').addEvent('onchange', refenen1);
});
That should work. The function checks if the fields have value on them and if they have, they are included in the calculation.
The second code you made fires the error because you are missing a parameter in the addEvent function.
I hope that this can help you :)
This seemed to work! So now I'm trying to figure out how to get commas for the thousands. So if I input 1200 it displays 1,200.
window.addEvent('domready', function() {
$('grandtotal').value = Number($('spendable').value) + Number($('housetotal').value) + Number($('cartotal').value) + Number($('creditortotal').value) + Number($('misctotal').value);
});
Thank you so much for your help!