I have an app that allows users at the same company on the same login to vote on specific items, therefore I'm unable to use IP to control how many times the user votes. How can I use jQuery to allow the user to only vote once?
jQuery:
$("#xmlDiv").on("click", ".upvote", function(e) {
var id = $(this).attr("id");
var main = $(this);
$.ajax({
type: 'post',
url: 'includes/upvote.php',
data: { "id":id },
success(data) {
main.parent().find("div.votenum").html(data);
},
error: function (xhr, textStatus, error) {
alert("Sorry!");
}
});
});
$("#xmlDiv").on("click", ".downvote", function(e) {
var main = $(this);
var id = $(this).attr("id");
$.ajax({
type: 'post',
url: 'includes/downvote.php',
data: { "id":id },
success(data) {
main.parent().find("div.votenum").html(data);
},
error: function (xhr, textStatus, error) {
alert("Sorry!");
}
});
});
HTML:
<img src="arrow-up-01-20.png" style="float:right;" class="upvote" id="5">
<img src="arrow-down-01-20.png" id="5" class="downvote" style="float:right;">
<div class="votenum" style="float:right;" id="5">12</div>
When the user click on upvote, you can add a class to the div voted
main.addClass("voted");
and you can check with hasClass("voted")
$("#xmlDiv").on("click", ".upvote", function(e) {
var id = $(this).attr("id");
var main = $(this);
if(main.hasClass("voted"))
return;
main.addClass("voted");
$.ajax({
type: 'post',
url: 'includes/upvote.php',
data: { "id":id },
success(data) {
main.parent().find("div.votenum").html(data);
},
error: function (xhr, textStatus, error) {
alert("Sorry!");
}
});
});
I suggest to control again at server side
jQuery can't retain memory across page loads. Refreshing the page makes any logic start from the start. You're solution is going to have to involve server logic.
As far as how to actually do this, if you can't use separate accounts or IPs, perhaps you could identify user by device, browser, and other identifying digital fingerprints. There are a lot and you can make a relatively secure vote, however, anyone with know how would be able to cheat on a vote that doesn't involve secure separate accounts.
Related
I'm outputting API data on separate pages coming from different end point urls, ie. https://api.server.com/first, https://api.server.com/second, etc.
The code is working, but it seems awfully redundant and I'm sure there's a better way of expressing this that's more optimal and faster:
var $rubys = $('#rubys');
$(function () {
$('#loading-rubys').show();
$.ajax({
type: 'GET',
url: 'https://api.server.com/first/',
success: function(rubys) {
$.each(rubys, function(i, ruby) {
$rubys.append('$'+parseFloat(ruby.price).toFixed(2)+' |
$'+parseFloat(ruby.attribute).toFixed(0));
});
},
complete: function(){
$('#loading-rubys').hide();
}
})
});
var $emeralds = $('#emeralds');
$(function () {
$('#loading-emeralds').show();
$.ajax({
type: 'GET',
url: 'https://api.server.com/second/',
success: function(emeralds) {
$.each(emeralds, function(i, emerald) {
$emeralds.append('$'+parseFloat(emerald.price).toFixed(2)+' |
$'+parseFloat(emerald.attribute).toFixed(0));
});
},
complete: function(){
$('#loading-emeralds').hide();
}
})
});
The following:
var $rubys = $('#rubys');
$('#loading-rubys').show();
are set for each post page using YAML front-matter (Jekyll) like so:
---
title: Post about Ruby
var-id: rubys
load-id: loading-rubys
---
and output them in HTML:
<div id="{{ page.var-id }}">
<div id="{{ page.load-id }}">
<img src="/assets/img/loading.svg"/>
</div>
</div>
Current workflow
So basically whenever I create a new post, I:
Set the var-id and load-id custom parameters for each post in the front-matter
Create a new function to include those and make a new GET request to the respective url, ie. https://api.server.com/third/, https://api.server.com/fourth/.
How would you write this better?
Something like this could help.
function getGems(gems,gemsURL) {
var $gems = $('#'+gems);
$('#loading-'+gems).show();
$.ajax({
type: 'GET',
url: gemsURL,
success: function(data) {
$.each(data, function(i, v) {
$gems.append('$'+parseFloat(v.price).toFixed(2)+' |
$'+parseFloat(v.attribute).toFixed(0));
});
},
complete: function(){
$('#loading-'+gems).hide();
}
});
}
$(function () {
getGems('rubys','https://api.server.com/first/');
getGems('emeralds','https://api.server.com/second/')
});
I have basically the same problem as the one described in the link below, but I dont find the solution to be very clear. I want my ajax success function to wait until the window function is finished executing, THEN modify the divs. Instead, it modifies the divs of the current page, then redirects. AJAX: on success redirect then modify new page
main.js
$("#form").submit( function(e) {
e.preventDefault();
var id = $('#searchbar').val(); // store the form's data.
$.ajax({
url: '/search',
type: 'POST',
data: {id:id},
dataType: 'text',
success: function(data) {
//Redirect to the page where we want to display the data
window.location.href = '/test';
data = JSON.parse(data);
console.log(data);
$("#count").text("we analyzed...");
$("#result1").text(data.county);
$("#totals").text("with a score of..");
$("#result2").text(data.totalSentiments);
},
error: function(jqXHR, textStatus, errorThrown){
console.log("error")
alert(textStatus, errorThrown);
}
});
});
I Will Suggest you Javascript Local Storage .
main.js
$("#form").submit( function(e) {
e.preventDefault();
var id = $('#searchbar').val(); // store the form's data.
$.ajax({
url: '/search',
type: 'POST',
data: {id:id},
dataType: 'text',
success: function(data) {
//Redirect to the page where we want to display the data
window.location.href = '/test';
data = JSON.parse(data);
console.log(data);
// Store
localStorage.setItem("count", "we analyzed...");
localStorage.setItem("result1", data.county);
localStorage.setItem("totals", "with a score of..");
localStorage.setItem("result2", data.totalSentiments);
},
error: function(jqXHR, textStatus, errorThrown){
console.log("error")
alert(textStatus, errorThrown);
}
});
});
On Ready on same page:
jQuery(document).ready(function(){
if (localStorage.count) {
$("#count").text(localStorage.count);
}
if (localStorage.result1) {
$("#result1").text(localStorage.result1);
}
if (localStorage.totals) {
$("#totals").text(localStorage.totals);
}
if (localStorage.result2) {
$("#result2").text(localStorage.result2);
}
});
Local Storage Store Data in Browser Storage. You Also Can Remove Data From Local Storage.
setting the value of location.href will cause a full page refresh.
Therefore all your scripts will be wiped out.
If you REALLY wants to use the result of a ajax call to a redirected page, you should store this response data somewhere, then reuse it on your new page.
//save "data" in localSotorage
localStorage.myAjaxResponse = data; //if data is JSON then use: JSON.stringify(data) instead.
Then on your "/test" page, create a script to check for the value on the localStorage then display it.
data = JSON.parse(localStorage.myAjaxResponse);
console.log(data);
$("#count").text("we analyzed...");
$("#result1").text(data.county);
$("#totals").text("with a score of..");
$("#result2").text(data.totalSentiments);
Although, there are other better ways to accomplish what you want.
You can do something like this:
On your ajax success:
data = JSON.parse(data);
console.log(data);
window.location.href = '/test?county='+data.county+'&sentiment='+totalSentiments;
Then on your test page write in javascript block:
var params={};
window.location.search
.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(str,key,value) {
params[key] = value;
}
);
if (params.length > 0) {
$("#count").text("we analyzed...");
$("#result1").text(params['county']);
$("#totals").text("with a score of..");
$("#result2").text(params['sentiments']);
}
I'm trying to load different templates through $.ajax based on what buttons a user clicks. I know how to do it with one template file, but can't seem to find a way to adjust the code to load different template based on click (without repeating the code).
Here's the relevant part of the ajax call:
var $this = $('#my-data');
$('#button-foo').click(function() {
$.ajax({
url: myAjax.ajax_url,
data: {
action: 'my_ajax_action'
},
cache: true,
beforeSend: function(){
$this.empty();
$this.addClass('loading');
},
complete: function(){
$this.removeClass('loading');
},
success: function(data) {
$this.append(data);
},
error: function(MLHttpRequest, textStatus, errorThrown){
alert(errorThrown);
}
});
});
And here's my Wordpress function:
function my_ajax_action() {
include(locate_template( 'part-template-foo.php' ));
die();
}
add_action('wp_ajax_nopriv_my_ajax_action', 'my_ajax_action');
add_action('wp_ajax_my_ajax_action', 'my_ajax_action');
Now what I need would be to include 4 different templates (part-template-bar.php, part-template-foobar.php, etc) based on user click. Something like:
function my_ajax_action() {
if ($_REQUEST['template'] == 'foo') {
include(locate_template( 'part-foo.php' ));
die();
}
if ($_REQUEST['template'] == 'bar') {
include(locate_template( 'part-bar.php' ));
die();
}
...
}
Any hint on how could I do this without having to repeat the js code and wp function four times? Thank you.
I want to reuse a javascript function using a scala template so I would only have to pass a different success/failure function, but I don't seem to be able to able to pass a javascript function to a scala template.
Please note I'm veeeeerry new to this and don't even know if what I am doing is possible.
This is kind of what I'm trying to achieve:
#(formId: String, success: JavaScript, fail: JavaScript)
<script type="text/javascript">
$("#formId").submit(function(e)
{
var data = $(this).serializeArray();
var action = $(this).attr("action");
$.ajax(
{
url : action,
type: "POST",
data : data,
success:function(data, textStatus, jqXHR) // Change contents to dynamic parameter for scala??? perhaps a javascript function to execute???
{
#success()
/*console.log("save succesfull, progress!")
alert('Save successfull, now move on!');*/
},
error: function(jqXHR, textStatus, errorThrown) // Change contents to dynamic parameter for scala??? perhaps a javascript function to execute???
{
//if fails
#fail()
/*console.log(jqXHR.responseText);
var errors = JSON.parse(jqXHR.responseText);
console.log(errors);
alert('Woops, something went wrong: ' + jqXHR.responseText);*/
}
});
e.preventDefault();
});
</script>
How it would be used:
#snippets.ajaxFormSubmit("#form",
function()
{
alert("Save successfull, now move on!");
},
function()
{
alert("Save failed!");
}
)
You can pass any content to a template via Html type.
#(formId: String, success: Html, fail: Html)
<script type="text/javascript">
$("#formId").submit(function(e)
{
var data = $(this).serializeArray();
var action = $(this).attr("action");
$.ajax(
{
url : action,
type: "POST",
data : data,
success:function(data, textStatus, jqXHR) // Change contents to dynamic parameter for scala??? perhaps a javascript function to execute???
{
#success
},
error: function(jqXHR, textStatus, errorThrown) // Change contents to dynamic parameter for scala??? perhaps a javascript function to execute???
{
#fail
}
});
e.preventDefault();
});
</script>
In a client view you can user it as follows:
#successFunc = {
alert("Save successfull, now move on!");
}
#failureFunc = {
alert("Save failed!");
}
#snippets.ajaxFormSubmit("#form", successFunc, failureFunc)
I'm using jQuery 1.11.1 and jQuery validation plugin
I have added the following script to my contact form to validate it and send via AJAX ({{hash_tag}} in code is Twig variable):
<script>
$("#contactform").validate({
rules: {
content_{{ hash_tag }}: {
required: true,
minlength: 20
},
name_{{ hash_tag }}: {
required: true,
minlength: 2
},
subject_{{ hash_tag }}: {
required: true,
minlength: 10
},
email_{{ hash_tag }}: {
required: true,
email: true
}
},
submitHandler: function(form) {
var postData = $(form).serializeArray();
var formURL = $(form).attr("action");
$.ajax(
{
url : formURL,
type: "POST",
data : postData,
success:function(data, textStatus, jqXHR)
{
$('#articlecontent').html(data.content);
$("html, body").animate({ scrollTop: 0 });
},
error: function(jqXHR, exception)
{
$(form).submit();
}
});
}
});
</script>
The script (after small testing) seems to work. But the problem is - when user have filled in form correctly and when PHP is sending email it may take a few seconds. User after clicking submit button of course doesn't have to know that form is send via AJAX and may think that something is not working ok and may for example click again or do something else.
The question is - how to show user that after clicking something is happening and email will be send in a few seconds? I don't know what's the best practice to do that. Please give me some nice solution. Progress bar is not necessary I think (it's probably hard to determine how long it would take) but maybe some other effect would be fine.
EDIT
After changing submitHandler I have now:
submitHandler: function(form) {
var postData = $(form).serializeArray();
var formURL = $(form).attr("action");
$.ajax(
{
url : formURL,
type: "POST",
data : postData,
beforeSend: function (){
$(form).hide();
$("#formsending").show();
},
success:function(data, textStatus, jqXHR)
{
$('#articlecontent').html(data.content);
$("html, body").animate({ scrollTop: 0 });
},
error: function(jqXHR, exception)
{
$(form).submit();
},
complete: function (){
$("#formsending").hide();
$(form).show();
}
});
}
It works somehow but still not exactly 100% I wanted. When I click send, form is being hidden and info that email is sending is being displayed but on server-site I have also data validation. Let's assume some complex validation cannot be done by jQuery/HTML5 and it must be done in PHP. When user clicks submit even form is invalid for a small time info that email is being sent is displayed. Is it possible somehow to launch beforeSend (or maybe some similar action) for example after second or 0.5 second to make sure that email is in fact being sent?
There is a nice plug in to show a progress wheel whenever an ajax request is in progress.
jQuery BlockUI
This is especially nice since it will automatically show a progress wheel for any ajax request, so you don't have to specifically set it up everywhere you make ajax calls.
Using this plug in the only code you need to write is
$(document).ajaxStart($.blockUI).ajaxStop($.unblockUI);
EDIT (from question update)
If you want to only show the progress spinner when the validation is successful and the email is actually being sent then you could have a separate ajax call that just performs validation and doesn't show any kind of progress (it should not take too long just to validate) and then if that call is successful make a separate ajax call that actually sends the email and does show the spinner.
Example:
submitHandler: function(form) {
var postData = $(form).serializeArray();
var formURL = $(form).attr("action");
var validateURL = "something else";
$.ajax({
url : validateURL,
type: "POST",
data : postData,
success:function(data, textStatus, jqXHR)
{
if(data.MyFieldThatIndicatesSuccess) {
$.ajax({
url : formURL,
type: "POST",
data : postData,
beforeSend: function (){
$(form).hide();
$("#formsending").show();
},
success: function(data, textStatus, jqXHR) {
$('#articlecontent').html(data.content);
$("html, body").animate({ scrollTop: 0 });
},
error: function(jqXHR, exception) {
//handle error
}
complete: function (){
$("#formsending").hide();
$(form).show();
}
});
}
},
error: function(jqXHR, exception)
{
//handle error
}
});
}
If I understand your problem correctly, what you would like is some message or animation to show when the user presses submit and it to go away again once the php has done its thing?
If so you would just have to add some code at the commented areas to show/hide an element that shows a message or a spinner.
submitHandler: function(form) {
var postData = $(form).serializeArray();
var formURL = $(form).attr("action");
//Some code to make a div appear e.g.
//$("#contactform").append("<div class='loading'><img src='spinner.gif'></div>");
$.ajax(
{
url : formURL,
type: "POST",
data : postData,
success:function(data, textStatus, jqXHR)
{
//some code to make the div disapear e.g.
//$(".loading").remove();
$('#articlecontent').html(data.content);
$("html, body").animate({ scrollTop: 0 });
},
error: function(jqXHR, exception)
{
$(form).submit();
}
});
}