Block Javascript function after 1 call - javascript

I am working on a multiple-choice question app and I am a database where I am storing the users answers. I just want to store the first answer they select to store it in the database. After the first selection, they can still click on the other answers to run the checkAnswer() but the storeAnwserStats() should not run. How can I do that?
app.js
function storeAnwserStats(questionId, answerId){
$.ajax({
url : "/store_stats",
type : "POST",
data : JSON.stringify({
question_id: questionId,
answer_id:answerId,
}),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
})
.done(function(data){
console.log("After " +data["correct_answer"]);
});
}
function checkAnswer(divSelected, answerId, questionId, isCorrect){
if(isCorrect == 1){
divSelected.style.backgroundColor = "green";
}
else{
divSelected.style.backgroundColor = "red";
}
storeAnwserStats(questionId, answerId)
}
[1]: https://i.stack.imgur.com/xyZfY.png

You can do multiple things for this.
METHOD 1
Disable the options: After the person has answered you can make the the sibling options disabled.
DOWNSIDE: the person can make the element enabled again by inspecting the element.
METHOD 2
Server side validation: check from server side if the answer has been answered or not on each call.
DOWNSIDE: server calls are increased.
METHOD 3
Remove the onclick along with onClick: After the person has answered you can make the the sibling options disabled AND remove the onClick call from them.
DOWNSIDE: Not sure of any yet.
EDIT 1
Server side validation is still important
Even after you do all those things above if the person really wants to be fishy
they can still send answers to your server by calling the function from console.
suppose in the OnClick function of the option you are calling your storeAnwserStats(), and since they are client side JS files I can easily check it and send the request by going to the console and typing storeAnwserStats(question_id, answer_id) (and question ID can be seen in the network tab)
good luck!

Related

Hide div after click of button with mysql

I want to hide a 'div' after a button is clicked. I don't want to use .remove() because when you refresh the app it comes back. I have the information about this div on the database and I wanna work with it.
I tried already creating an Ajax call to select the information that I'm looking at and then on the front-end I'm telling if it exist then delete it. But I feel like I'm missing something and I don't know why.
Frontend:
$('#deletePromo').on('click', function(res){
let success = function(res){
if (eventName && customerID){
$(`#promotion-container .promo${i}`).remove();
}
}
$.ajax({
type: 'POST',
url: '/api/promotions-done',
crossDomain: true,
//success: success,
dataType: 'json',
data: {
customerID : customerID,
eventName : eventName,
}
}).done(function(res){
console.log('res', res)
if (res != null){
$(`#promotion-container .promo${i}`).remove();
//$(`#promotion-container .promo${i}`).css('display', 'none')
}
})
})
})
Backend:
router.post('/promotions-done', function(req, res) {
let customerID = req.user.customer_id
let restaurantGroupId = req.user.restaurant_group_id
let eventName = req.body.eventName
db.task(t => {
return t.any(`SELECT * FROM promotions_redemption WHERE (customer_id = '${customerID}' AND event_name = '${eventName}' AND restaurant_group_id = ${restaurantGroupId})`).then(function(promotionsDone) {
return res.json({'promotionsDone': promotionsDone})
})
.catch((err) =>{
console.log(err)
})
})
})
What I'm trying to do here is saying if the customerID and eventName already exist on the table then remove div from the person. I don't have much experience working with backend so is there a way to tell the program to check the database for this information and if it exists then remove the div.
You probably have some HTML in a template file, or in the database that has the button there to start with. Since your AJAX code will only run when the button is clicked, you will need to either do 1 of 2 things:
Add an AJAX call on page load
Handle looking for the button and hide/show it in your templating language/platform (think asp.net, python django, php laravel etc) to avoid the AJAX request.
Since we don't know your platform, I will show you option 1
First, I would change the initial state of your HTML to NOT show the button by default. This would look something like this:
<div id="promotion-container">
<button class="promo" style="display: none" />
</div>
Otherwise you will have the button be shown for the amount of time the AJAX request takes.
Next, you will want to add this function call to the page. I have reversed the login in the done function to "show" the button or unhide it.
$(document).ready(function(){
let success = function(res){
if (eventName && customerID){
$(`#promotion-container .promo${i}`).remove();
}
}
$.ajax({
type: 'POST',
url: '/api/promotions-done',
crossDomain: true,
//success: success,
dataType: 'json',
data: {
customerID : customerID,
eventName : eventName,
}
}).done(function(res){
console.log('res', res)
if (res === null){
//$(`#promotion-container .promo${i}`).remove();
$(`#promotion-container .promo${i}`).css('display', 'block')
}
})
})
})
The easiest solution to your problem would be to use a client-side cookie. If you don't have a cookie package already, I'd recommend js-cookie.
On your html page:
<div id="promotion-container" hidden> //you want it hidden by default
//if it is shown by default there will be an annoying screen flicker when the pages loads
<script src="/path/to/js.cookie.js"></script>
On jQuery page:
$(document).ready( function() {
if (!Cookies.get('name1') || !Cookies.get('name2')) {
$('#promotion-container').show();
};
Cookies.set('name1', customerId, {expires:14} ); //must include expiration else the cookie will expire when the browser closes.
Cookies.set('name2', eventName, {expires:14} ); //you might need to make an eventId if eventName is too large
});
The second input for Cookies.set is the 'value' for the cookie. if 'value' = null, then Cookies.get('name') = null.
This is assuming you already have the means to set customerId and eventName for each user. Also you might need to modify where the Cookies are set based on when the customerId is created on the page.
EDIT:
There are 2 ways you can run a query the way you describe, both of which won't work they way you want unless you use a session cookie.
1) You have res.render inside of a query.
This would ensure the div is never shown to a user that has already clicked on it, but would significantly hurt your site's performance. The query would run every time the page is rendered, regardless of whether or not the client has a customerId. Your site would would be painfully slow with a large amount of traffic.
2) You run a POST request through client-side js with ajax and compare the customerId with your db; if a result is found, you remove the div.
This would function the way you want it to, and wouldn't hurt performance, but nothing is stopping a customer from using something like burp to intercept the POST request. They could change the data argument to whatever they want and make sure the div loads for them.
The only solution to these problems that I see would be to validate a user when they click on the div AND on the server with a session cookie. (for user validation I use passport and express-session).
I can show you how I set this up, but to make it specific to your needs I would need to know more about how your site is setup.
PS I misunderstood why you needed to hide the div, and using a client-side cookie would be a terrible idea in hindsight.

Lock form if any user is on page [duplicate]

This question already has answers here:
Can the unload Event be Used to Reliably fire ajax Request?
(5 answers)
Closed 4 years ago.
I'm creating a queue-like page where only 1 person should be able to edit information about a specific database entry at a time.
Let's say a user is on page profile.php?id=1 - only the very first person who loaded this page should be able to make changes to it.
I've attempted to do this with JavaScript/jQuery, but am facing a problem.
On page load, I send an AJAX request to a PHP file that essentially sets a table cell to true for a specific ID. Then, I use a beforeunload event to set this cell to false when the page is unloaded. With this specific implementation, there is a problem though. The beforeunload event is either not fired when the tab is closed, or it is fired and the AJAX request does not have time to complete. This is a big problem because a user could potentially load up the page, see there is nothing to edit, and then close the tab without thinking about it, thus locking the page indefinitely until I reverse the lock in the database manually - and I would hate to have to force people to not use their browser the way they want to.
Here is my code:
$( document ).ready(function() {
var locked = <?=json_encode($data['in-review']);?>;
if(locked) {
$('input').attr('disabled', true);
$('#delete-model-button').attr('disabled', true);
$('#uidfield').attr('disabled', true);
$('#submitbutton').attr('disabled', true).text("This model is in review by another reviewer.");
} else {
$.ajax({
url: 'process/in-review.php',
type: 'POST',
data: {uid: $("#uidfield").val(), value: 1},
success: function (result) {
console.log("Model Locked in Review");
}
});
$(window).on('beforeunload', function() {
$.ajax({
url: 'process/in-review.php',
type: 'POST',
data: {uid: $("#uidfield").val(), value: 0},
success: function (result) {
console.log("Model Unlocked");
}
});
});
}
});
As you can see, if a user loads into a page that is already review locked, the beforeunload process is not called at all because that would allow users to unlock a form that another user may be working on.
How can I effectively unlock these pages if a user closes their tab or browser?
In case it matters, here is my in-review.php page:
<?php
include('db.php');
$uid = $_POST['uid'];
$value = $_POST['value'];
$db->run("UPDATE `devices` SET `in-review`=? WHERE `uid`=?", [$value, $uid]);
--EDIT:
This is commented as a duplicate question, but I disagree with this. That question is specifically asking "Can the unload Event be Used to Reliably fire ajax Request?" - I already know the answer to that is "Yes", because that is the method I am currently using, I also know it does not work at all for closing tabs/browser, therefore my question is not if this is a reliable method for what I want to do (I already know it is not), I'm asking for a different method that I can use to do this.
have you tried making a synchronous call of Ajax in beforeunload event?
i.e.
$(window).on('beforeunload', function() {
$.ajax({
url: 'process/in-review.php',
type: 'POST',
async: false,
data: {uid: $("#uidfield").val(), value: 0},
success: function (result) {
console.log("Model Unlocked");
}
});
});
The problem here is browser needs to keep connect alive with the server until the request is completed.
When the user clicks on other pages in your application that means connection to the server is alive and operation can be completed, and in case of browser/tab close connection to server is lost.
This might work on some situations i.e. your server was fast enough to respond before complete browser closure i.e. destruction in window object

Confirmation Dialog with Bootstrap/jQuery/ASP.MVC

I have a simple table with records and each of them has a btn with data-id attribute to run the confirmation dialog:
#foreach (var dog in Model)
{
<tr>
<td>#dog.Name</td>
<td>#dog.Age</td>
<td>Delete</td>
</tr>
}
After clicking the delete btn, this code is running :
$('.deleteBtn').on('click', function () {
$.ajax({
url: '#Url.Action("DeleteConfirm", "Home")',
data: {
id : $(this).attr('data-id')
},
success: function(data)
{
$('#myModal').empty().html(data).modal('show');
}
});
});
As you can see, its Ajax request to my Action in HomeController. It returns PartialView that is loaded to my Bootstrap dialog:
<div class="modal fade" id="myModal">
</div>
After showing the dialog, the user can click confirm to delete the row via button with class saveBtn. Thats what happens after I click it :
$('#myModal').on('click', '.saveBtn', function () {
var numer = $(this).attr('data-id');
$.ajax({
url: '#Url.Action("DeleteDog", "Home")',
type: 'POST',
dataType: 'JSON',
data: {
id: numer
},
success: function (data)
{
if (data = 'true')
$('a[data-id=' + numer + ']').closest('tr').remove();
}
});
});
So as you can see there is another Ajax (POST this time) request to delete the row.
So here is my question. Is this approach good practice? I'm not sure because in order to delete a row i have to send 2 ajax request (to load confirm dialog, and delete after confirm). Can anyone experience developer comment this code and say whether im doing it good or bad? I would be grateful.
It's always a good idea to challenge whether or not you could do things more effectively (as you have here.) So, let's think about it...
The Question:
Is it a good approach to send to two ajax requests - one to load a partial view and the second to post a delete request from the partial - for a single "user action"?
The Answer:
Maybe.
Why?
Based your example, if your goal is to simply confirm with the user whether or not they want to "Delete Dog ID: foo?" You can absolutely do that without making a trip to the server for a partial view. Presumably, in your first ajax call - $(this).attr('data-id'); - is the dog's Id. You already have it!
In most circumstances, when you make a get request with an identifier, like /dogs/id?='foo' you're using foo to access some additional information about the object from a persistent data store. Like, for example, the dog's owners, similar dog breeds, last visit to the vet, etc.
If additional information about the dog (owners, other dogs, vet) is an important part of deciding whether or not to delete the dog AND there's a good reason not to load it when the page loads intially then it totally makes sense to issue two ajax calls.
It could also make sense to issue two ajax calls just to get the partial view html, even if you don't need additional "dog" data, if you simply don't want the "parent" page to be to big (hence, slowing it's loading time.)
Ultimately, though if you're not retrieving additional data, and there's no specific reason to load additional html, it's probably best in this case to just update the modal dialog using javascript/jquery:
Example fiddle

Access-Control-Allow-Origin header is not present on the requested resource

DISCLAIMER: This question is a question about question. So that makes this question a meta question. It does not have any connection to the previously asked questions. If you find any resemblance, lemme tell you one thing- it's purely coincidental.
I want to make an AJAX request from my web page. I have been trying to do this, but none of the methods worked perfectly. The only post that I found something close to reality is this.
I tried various other methods from SO & other similar sites, but all of those posts said only one thing to me.
"No 'Access-Control-Allow-Origin' header is present on the requested resource."
I know now you are gonna mark this question as duplicate since there are loads of questions similar to this. Now..Lemme tell ya' one thing. I tried every piece of sh*t I found in SO, but none of 'em gave me the result that I was looking for. It's not because they all are wrong. It because I ain't got no knowlegde on how to use 'em. Then finally...I settled on the link I provided above. It's easy..but I need to know certain things about the code.This is the first time I am hearing the beautifully sodding acronym- CORS. So, if anyone can help me understand the questions I raise, Up votes for all of ya'. I wanna resolve this son-of-a-b*tch question before I celebrate my birthday for the third time this year. I will tell ya' what all I have-in form of resources & questions.
1) A rotten server located at Elizabeth town.
2) I need to access it.
3) I am planning to make a HTTP GET request.
4) I have a url. (eg. http://whereismyweed.com)
5) I store it into a JavaScript variable. var stoner='http://whereismyweed.com'
6) I have a HTML div tag in my webpage. (<div id="myprecious"></div>)
7) I wanna display the response I get from the server inside of 'myprecious' div.
8) And last but not the least... my AJAX function. (Courtesy: some website I visited)
$.ajax({
url: stoner,
data: myData,
type: 'GET',
crossDomain: true, // enable this
dataType: 'jsonp',
success: function() { alert("Success"); },
error: function() { alert('Failed!'); },
beforeSend: setHeader
});
What is 'myData'?? What does it contain. How can I get the response for this request? What is 'setHeader'?? Does it have any significance??? How can I display the response inside myprecious div? What changes should I make in the function? Is this function correct?
Too many question, Right???? Well...I need only one common answer for it?
Your function is correct.Follow below steps do achieve your goal-
//for getting response modify your code like
success:function(response){
alert(response);
$('#myprecious').html(response); //myprecious is id of div
}
// myData variable is jSon object which contains request parameter has to send.Eg.
var myData = {'first_name':'Foo','last_name':'Bar'} // now on server first_name and last_name treated as request parameter.
// If server not required any special headers to validate request 'setHeader' does not require. by default $.ajax will take care of it. you can remove it.
/// final code looks like
$.ajax({
url: stoner,
data: myData,
type: 'GET',
crossDomain: true, // enable this
dataType: 'jsonp',
success: function(response ) { $('#myprecious').html(response);
},
error: function() { alert('Failed!'); }
});

how to run an onchange function when page is loaded if the selected box is already selected

Im running into a problem where i have an ajax driven page that is drawn when a user selects something from a simple drop down:
<select id = "selectdepartment">
<option id = "default">Select an option...</option>
....
</select>
and the remainder of the page is drawn using the jquery .change() :
$('#selectdepartment').change(function(){
});
Which then runs some ajax to php script. everything works great, the problem is when i submit a form that was drawn with ajax (using $_SERVER['PHP_SELF'];), the data gets submited, the page reloads, and the page is cleared but the select box is still left where it was. The user has to move to a different option then back to the one the selected originally to re-fire the .change(). that sucks.
I could fix this by passing a php variable in all of my forms, then checking to see the variable set on every page load and if it is draw the page parts then, but this would lead to pretty messy code and it's less than desirable.
There has to be a way to do this with the jquery library, though my knowledge of the javascript language in general is not what i would like it to be. If anyone has any helpful hints please share, dont do it for me though, i wont learn that way :)
edit: code with .trigger
$('#selectdepartment').change(function(){
var department = $('#selectdepartment').val();
var day = $('#data').data('day');
var month = $('#data').data('month');
var year = $('#data').data('year');
//alert (department);
if(department === "Select an option..."){
$('.hiddenuntildepartmentisselected').css({"display":"none"});
}
else{
$('.hiddenuntildepartmentisselected').css({"display":"block"});
}
showpoints(department);
drawpointstable(department, day, month, year);
displaytheuseresforselecteddepartment(department, '');
$('#sendthedepartment').val(''+department+'');
$('#hiddendepartmentidforaddinganewpoint').val(''+department+'');
}).trigger('change');//end run functions
You can use the .trigger() function to immediately trigger the change event handler when the page has loaded:
$('#selectdepartment').change(function() {
// code here
}).trigger('change');
Or if you need to call it elsewhere via JavaScript/jQuery:
$('#selectdepartment').trigger('change'); // or just .change() as a shorthand
Updated
Your button for the form could make use of the onClick attribute, which would invoke a method to parse the form fields and post the data to your php script via .ajax().
In the success event method you then check any flags you need to and modify the element as you desire if needed.
Basic example:
Inside of .ajax():
...
url: 'xxx.xxx.xxx',
async: true,
type: 'POST',
dataType: 'html',
data: JSON.stringify( form_fields ),
beforeSend: function()
{
// Pre send stuff, like starting a loading gif
},
success: function( data, textStatus, xhr )
{
// Be sure you load the page with the content first
$( '#containing-div' ).html( data );
// Do your check here, and modify your element if needed here
if( flagtocheck === 'xxx' )
{
// Modify the element in question...
}
// I call a custom method termed `.ctrls()` here that makes any
// adjustments to the DOM once its loaded/updated.
},
error: function( xhr, textStatus, errorThrown )
{
}
Of course, you'll want to set flagtocheck appropriately in your case.
Hope that helps!
Note regarding edit
This post was edited to be a little more descriptive and more easily understood. Since the person asking the question is already using the .ajax() method, the success event method is the ideal place for doing what the person asking the question is requesting. It is 1 less method invocation to directly modify the element there than using it to call .trigger() or .change() which then also directly modifies the element.

Categories

Resources