Can someone say whats wrong with this lane data:... inside saveForm function?
I have list of tasks in my page. Every task has there own form where users can send comments. It means that I have several forms in one page. When I add new task AJAX update list of comments and then I try to send comment by one of the form and it raise error : “CSRF token missing or incorrect”. I have {% csrf_token %} in all my forms.
It seems like I need send CSRF in AJAX. Where I did mistake?
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// TASK
$(function () {
var loadForm = function () {
var btn = $(this);
$.ajax({
url: btn.attr("data-url"),
type: 'get',
dataType: 'json',
beforeSend: function () {
$("#modal").modal("show");
},
success: function (data) {
$("#modal .modal-content").html(data.html_group_task_form);
}
});
};
var saveForm = function () {
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize().append('csrfmiddlewaretoken', getCookie(csrftoken)),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
if (data.form_is_valid) {
$("#task-list").html(data.html_task);
$("#modal").modal("hide");
}
else {
$("#modal .modal-content").html(data.html_task_form);
}
}
});
return false;
};
// Create task
$("#task-add-button").click(loadForm);
$("#modal").on("submit", ".js-task-add-form", saveForm);
// Update task
$("#task-list").on("click", "#js-edit-task-button", loadForm);
$("#modal").on("submit", ".js-task-edit-form", saveForm);
});
//TASK COMMENT ADD
$(".task-comment-form").submit(function(event) {
event.preventDefault();
console.log(event.preventDefault());
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize().append('csrfmiddlewaretoken', getCookie(csrftoken)),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
var current_group = form.closest('.custom-list-group');
if (data.form_is_valid) {
current_group.find(".task-comments").html(data.html_task_comment);
}
else {
current_group.find(".task-comment-form").html(data.html_task_comment_form);
}
},
});
form[0].reset();
return false;
});
CODE ABOUT COMMENT ADD:
views.py:
def task_comment_add(request, project_code, task_code):
data = dict()
project = get_object_or_404(Project, pk=project_code)
task = get_object_or_404(Task, pk=task_code)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.author = request.user
comment.save()
task.comments.add(comment)
data['form_is_valid'] = True
data['html_task_comment'] = render_to_string('project/task_comment_list.html' {'task': group_task})
else:
data['form_is_valid'] = False
else:
form = CommentForm()
context = {'project': project, 'task': task, 'form': form}
data['html_task_comment_form'] = render_to_string('project/task_comment_form.html', context, request=request)
return JsonResponse(data)
JS:
// TASK COMMENT ADD
$(".task-comment-form").submit(function(event) {
event.preventDefault();
console.log(event.preventDefault());
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize(),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
var current_group = form.closest('.custom-list-group');
if (data.form_is_valid) {
current_group.find(".task-comments").html(data.html_task_comment);
}
else {
current_group.find(".task-comment-form").html(data.html_task_comment_form);
}
}
});
form[0].reset();
return false;
});
.append is for DOM elements.
The result of .serialize is a string.
Why don't you just put the token in a hidden input in the form with a 'name' attr of 'csrfmiddlewaretoken'?
That will serialize it with the rest of your form data.
Here's what I did that worked for ajax forms with Django:
$('#ajax_form').submit(function(e){
e.preventDefault();
var form = this;
var action = $(form).attr('action'); // grab the action as url
var form_array = $(form).serializeArray(); // use serializeArray
form_array.push({ // *expand the array to include a csrf token*
name: 'csrfmiddlewaretoken',
value: getCookie('csrftoken') // getCookie function from django docs
});
var form_data = $.param(form_array); // set it up for submission
$.post(action,form_data,function(resp){
// do stuff after receiving resp
});
});
Basically, I used jquery's .serializeArray() instead of serialize.
.serializeArray() gives you an array of objects like this:
[{name:'name1',value:'value1'},{name:'name2',value:'value2'}]
calling $.param(serilaized_array_data) turns it into a string for submitting. So the key is to add the csrf token to the array. I did that in the code above on the line from_array.push({... with the *'s in the comments.
The problem was in my view. I use this and error disappeared:
context = {...}
context.update(csrf(request))
Related
I have a form that submits through ajax. At first click it sends the request to php but doesnt send post variables and however when i submit form for second or third time it submits the form and gets the success response. The ajax request doesn't fail on first click it just doesnt send data to php.When i check the network tab request fields show up there on the first click and have correct values but doesnt reach php. Here is my code
jQuery("#bidding-form").on('submit', function(e) {
var request_english_level = jQuery('#request_english_level').val();
var job_title = jQuery('#job_title').val();
var request_type = jQuery('#request_type').val();
var estimated_hours = jQuery('#estimated_hours').val();
var designation = jQuery('#designation').val();
var service_type = jQuery('#service_type').val();
var budget = jQuery("#budget").val();
var user_id = jQuery('#user_id').val();
var locations = jQuery('#location').val();
var payment_terms = jQuery('#payment_terms').val();
var application_no = jQuery('#application_no').val();
var deadline_apply = jQuery('#deadline_apply').val();
var close_date = jQuery('#close_date').val();
var delivery_deadline = jQuery('#delivery_deadline').val();
var experience = jQuery('#consultant_experience').val();
var description = jQuery('#request_description').val();
var formdata = new FormData();
var length = jQuery(".attachment")[0].files.length;
for (i = 0; i < length; i++) {
formdata.append('file[]', jQuery(".attachment")[0].files[i]);
}
formdata.append('action', 'save_bid_info');
var checked_skills = []
jQuery("input[name='request_skills[]']:checked").each(function() {
//checked_skills.push(parseInt(jQuery(this).val()));
formdata.append('request_skills[]', parseInt(jQuery(this).val()));
});
var languages = []
jQuery("input[name='languages[]']:checked").each(function() {
//languages.push(parseInt(jQuery(this).val()));
formdata.append('languages[]', parseInt(jQuery(this).val()));
});
formdata.append('designation', designation);
// formdata.append('request_skills', checked_skills);
formdata.append('request_type', request_type);
formdata.append('estimated_hours', estimated_hours);
formdata.append('service_type', service_type);
formdata.append('delivery_deadline', delivery_deadline);
formdata.append('job_title', job_title);
formdata.append('locations', locations);
formdata.append('request_type', request_type);
formdata.append('payment_terms', payment_terms);
formdata.append('application_no', application_no);
formdata.append('deadline_apply', deadline_apply);
formdata.append('close_date', close_date);
formdata.append('experience', experience);
formdata.append('description', description);
formdata.append('budget', budget);
// formdata.append('languages', languages);
formdata.append('request_english_level', request_english_level);
e.preventDefault();
jQuery.ajax({
url: ajax_url,
type: 'post',
dataType: 'json',
contentType: false,
cache: false,
processData: false,
data: formdata,
beforeSend: function() {
jQuery(".loader").show();
},
complete: function(data) {
jQuery('.loader').hide();
}
})
.done(function(response, textStatus, jqXHR) {
if (response.success == true) {
jQuery(".ajax-processor").hide();
} else {
jQuery(".ajax-processor").find('p').html(response.msg);
}
})
.fail(function(jqXHR, textStatus, errorThrown) {
console.log(errorThrown);
})
});
// PHP CODE
if(isset($_POST['budget']) && !empty($_POST['budget']))
{
// on second click this is executed
}
else
{
// on first click this is executed
}
let getLoginPassSystem = function (getPassForgotSystem, getLoginCheckSystem) {
$(document).ready(function () {
$('#login,#lostpasswordform,#register').submit(function (e) {
e.preventDefault();
$.ajax({
type: "POST",
url: 'http://www.virtuelles-museum.com.udev/spielelogin/logsystem.php',
data: $(this).serialize(),
success: function (response) {
var data = JSON.parse(response);
if (data.success == "accepted") {
document.getElementById('inner').innerHTML = 'Herzlich Willkommen';
// location.href = 'index.php';
} else {
alert('Ungültige Email oder Password!');
}
}
});
});
})
}
Well, I want to have for every form(#login,#lostpasswordform,#register) an different "alert". Is it actually possible?
You can save an alert massage in each div tag as data attribute. For example:
<div id="login" data-msg="message1"></div>
<div id="lostpasswordform" data-msg="message2"></div>
<div id="register" data-msg="message3"></div>
// then you can invoke them like this
let getLoginPassSystem = function (getPassForgotSystem, getLoginCheckSystem) {
$(document).ready(function () {
$('#login,#lostpasswordform,#register').submit(function (e) {
e.preventDefault();
let current_form = $(this);
$.ajax({
type: "POST",
url: 'http://www.virtuelles-museum.com.udev/spielelogin/logsystem.php',
data: $(this).serialize(),
success: function (response) {
var data = JSON.parse(response);
if (data.success == "accepted") {
document.getElementById('inner').innerHTML = 'Herzlich Willkommen';
// location.href = 'index.php';
} else {
alert(current_form.attr('data-msg'));
}
}
});
});
})
}
It seems like you can simply check the e.target - it will be different for every form.
You can get more information about Event.target here: https://developer.mozilla.org/en-US/docs/Web/API/Event/target
Im quiet confused with this code. Im reading this code of ajax which inserts the data automatically. but what im confused is this line if(result=='12') then trigger ajax what does 12 means why it should be 12 then conditioned to before ajax. Apparently im still learning ajax thanks. P.S this is working well btw im just confused with the code
here is the full code of the create function javascript / ajax
$('#btnSave').click(function(){
var url = $('#myForm').attr('action');
var data = $('#myForm').serialize();
//validate form
var empoyeeName = $('input[name=txtEmployeeName]');
var address = $('textarea[name=txtAddress]');
var result = '';
if(empoyeeName.val()==''){
empoyeeName.parent().parent().addClass('has-error');
}else{
empoyeeName.parent().parent().removeClass('has-error');
result +='1'; //ALSO THIS NUMBER 1 WHY SHOULD IT BE 1?
}
if(address.val()==''){
address.parent().parent().addClass('has-error');
}else{
address.parent().parent().removeClass('has-error');
result +='2'; //ALSO THIS NUMBER 2 WHY SHOULD IT BE 2?
}
if(result=='12'){ //HERE IS WHAT IM CONFUSED
$.ajax({
type: 'ajax',
method: 'post',
url: url,
data: data,
async: false,
dataType: 'json',
success: function(response){
if(response.success){
$('#myModal').modal('hide');
$('#myForm')[0].reset();
if(response.type=='add'){
var type = 'added'
}else if(response.type=='update'){
var type ="updated"
}
$('.alert-success').html('Employee '+type+' successfully').fadeIn().delay(4000).fadeOut('slow');
showAllEmployee();
}else{
alert('Error');
}
},
error: function(){
alert('Could not add data');
}
});
}
});
As I have explained in my commentaries, and since you wanted an example. This is how I will proceed in order to avoid checking for result == '12':
$('#btnSave').click(function()
{
var url = $('#myForm').attr('action');
var data = $('#myForm').serialize();
// Validate form
var empoyeeName = $('input[name=txtEmployeeName]');
var address = $('textarea[name=txtAddress]');
var formValid = true;
if (empoyeeName.val() == '')
{
empoyeeName.parent().parent().addClass('has-error');
formValid = false;
}
else
{
empoyeeName.parent().parent().removeClass('has-error');
}
if (address.val() == '')
{
address.parent().parent().addClass('has-error');
formValid = false;
}
else
{
address.parent().parent().removeClass('has-error');
}
// If form is not valid, return here.
if (!formValid)
return;
// Otherwise, do the ajax call...
$.ajax({
type: 'ajax',
method: 'post',
url: url,
data: data,
async: false,
dataType: 'json',
success: function(response)
{
if (response.success)
{
$('#myModal').modal('hide');
$('#myForm')[0].reset();
var type = '';
if (response.type=='add')
type = 'added';
else if (response.type=='update')
type ="updated";
$('.alert-success').html('Employee ' + type + 'successfully')
.fadeIn().delay(4000).fadeOut('slow');
showAllEmployee();
}
else
{
alert('Error');
}
},
error: function()
{
alert('Could not add data');
}
});
});
It's just checking existence of values and appending string to it.
if(empoyeeName.val()=='')
This check empty name and add error if name is empty. else it concat 1 to result.
if(address.val()=='')
This check empty address and add error if address is empty. else it concat 2 to result.
So if both of them are non empty that means result will be 12 and than only you make ajax call else show error.
Having a real discouraging time trying to update a django field by saving a blob stored in JS variable via AJAX. Here's my view:
def update_audio(pk, request):
if request.method == 'POST':
form = UpdateAudio(data= request.POST, files= request.FILES)
if form.is_valid():
print('valid form')
else:
print ('invalid form')
print (form.errors)
return HttpResponseRedirect('/')
the url:
url(r'^update_audio/(?P<pk>[\w-]+)$', views.update_audio, name='update_audio'),
The form:
class UpdateAudio(forms.ModelForm):
class Meta:
model = Sounds
fields = [
'sound',
]
The form on the page:
<form id='update_audio' enctype="multipart/form-data" method="post" class="">
<input type="file" name="sound" id="id_sound" value=''>
<input class="btn btn-primary" type="submit" value="Save" onclick='upload()'/>
</form
And the AJAX:
function upload(event) {
event.preventDefault();
var csrftoken = getCookie('csrftoken');
var data = new FormData();
data.set('sound', blob);
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// debugger;
$.ajax({
url: "{% url 'posts:update_audio' instance.pk %}",
type: 'POST',
data: data,
cache: false,
processData: false,
contentType: false,
success: function(data) {
alert('success');
}
});
return false;
}
$(function() {
$('#update_audio').submit(upload);
});
The blob is stored in the global var blob, which is being appended to the var data, which is a FormData instance. I'm getting a POST 403 Forbidden when trying to post. Any clues as to where I'm going wrong? Have been working on this for several days now and would really appreciate some pointers.
EDIT: was able to to pass the CSRF with the snippets suggested in the django docs Here
So with this example I have form with a hidden field and a button called ban user. When the ban user button is clicked, it submits the value in the hidden field and sends the ajax request to a java servlet. If it is successful, the user is banned and the button is changed to "unban user". The problem is when I click the button once and ban a user and I try to click it again to unban, I'm still inside the click event for the ban user and I get the alert "Are you sure you want to ban the user with the id of ...?". How do I exit the click event to make sure when the button is clicked a second time, it starts at the beginning of the function and not inside the click function? I have tried using 'return;' as you can see below but that doesn't work.
$(document).delegate('form', 'click', function() {
var $form = $(this);
var id = $form.attr('id');
var formIdTrim = id.substring(0,7);
if(formIdTrim === "banUser") {
$(id).submit(function(e){
e.preventDefault();
});
var trimmed = id.substring(7);
var dataString = $form.serialize();
var userID = null;
userID = $("input#ban"+ trimmed).val();
$("#banButton"+ trimmed).click(function(e){
e.preventDefault();
//get the form data and then serialize that
dataString = "userID=" + userID;
// do the extra stuff here
if (confirm('Are you sure you want to ban the user with the id of ' + trimmed +'?')) {
$.ajax({
type: "POST",
url: "UserBan",
data: dataString,
dataType: "json",
success: function(data) {
if (data.success) {
//$("#banUser"+trimmed).html("");
$('#banUser'+trimmed).attr('id','unbanUser'+trimmed);
$('#ban'+trimmed).attr('id','unban'+trimmed);
$('#banButton'+trimmed).attr('value',' UnBan User ');
$('#banButton'+trimmed).attr('name','unbanButton'+trimmed);
$('#banButton'+trimmed).attr('id','unbanButton'+trimmed);
$form = null;
id = null;
formIdTrim = null;
return;
}else {
alert("Error");
}
}
});
} else {
}
});
}
else if(formIdTrim === "unbanUs") {
//Stops the submit request
$(id).submit(function(e){
e.preventDefault();
});
var trimmed = id.substring(9);
var dataString = $form.serialize();
var userID = null;
userID = $("input#unban"+ trimmed).val();
$("#unbanButton"+ trimmed).click(function(e){
e.preventDefault();
//get the form data and then serialize that
dataString = "userID=" + userID;
// do the extra stuff here
if (confirm('Are you sure you want to UNBAN the user with the id of ' + trimmed +'?')) {
$.ajax({
type: "POST",
url: "UserUnban",
data: dataString,
dataType: "json",
success: function(data) {
if (data.success) {
//$("#banUser"+trimmed).html("");
$('#unbanUser'+trimmed).attr('id','banUser'+trimmed);
$('#unban'+trimmed).attr('id','ban'+trimmed);
$('#unbanButton'+trimmed).attr('value',' Ban User ');
$('#unbanButton'+trimmed).attr('name','banButton'+trimmed);
$('#unbanButton'+trimmed).attr('id','banButton'+trimmed);
$form = null;
id = null;
formIdTrim = null;
return;
}else {
alert("Error");
}
}
});
} else {
}
});
}
});
Try with:
$("#banButton"+ trimmed).off('click').on('click', (function(e){......
I had similar problem and this was solution