How do i include the csrf_token to dropzone Post request (Django) - javascript

Allright this is resolved. Just editing in case anyone runs into the same problem.
Add the Code posted in Comment marked as answer in the same javascript file.
When defining
var myDropzone = new Dropzone(...
...//More stuff here
headers:{
'X-CSRFToken' : csrftoken
}
And thats it.
So im getting a 403 Forbidden when submitting the POST request through dropzone.js to django.Django displayed the message saying that I didnt include the CSRF token, but I don't know how to actually include it if im not using a form in the HTML.
document_form.html
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}Add files{% endblock %}
{% block files %}
<div class="container-fluid" id="container-dropzone">
<div id="actions" class="row">
<div class="col-lg-7">
<span class="btn btn-success file-input-button">
<i class="glyphicon glyphicon-plus"></i>
<span>Add files...</span>
</span>
<button type="submit" class="btn btn-primary start">
<i class="glyphicon glyphicon-upload"></i>
<span>Start upload</span>
</button>
<button type="reset" class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel upload</span>
</button>
</div>
<div class="col-lg-5">
<!-- file processing state -->
<span class="fileupload-process">
<div id="total-progress" class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
<div class="progress-bar progress-bar-success" style="width:0%;" data-dz-uploadprogress></div>
</div>
</span>
</div>
</div>
<div class="table table-striped files" id="previews">
<div id="template" class="file-row">
<div>
<span class="preview"><img data-dz-thumbnail></span>
</div>
<div>
<p class="name" data-dz-name></p>
<strong class="error text-danger" data-dz-errormessage></strong>
</div>
<div>
<p class="size" data-dz-size></p>
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0"
aria-valuemax="100" aria-valuenow="0">
<div class="progress-bar progress-bar-success" style="width:0%"
data-dz-uploadprogress>
</div>
</div>
</div>
<div>
<button class="btn btn-primary start">
<i class="glyphicon glyphicon-upload"></i>
<span>Start</span>
</button>
<button data-dz-remove class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel</span>
</button>
<button data-dz-remove class="btn btn-danger delete">
<i class="glyphicon glyphicon-trash"></i>
<span>Delete</span>
</button>
</div>
</div> <!-- /table-striped -->
</div> <!-- /container-fluid -->
</div>
{% endblock %}
{% block dz-add %}
<script src="{% static 'js/dropzone-bootstrap.js' %}"></script>
{% endblock %}
dropzone-bootstrap.js
$(function() {
var previewNode = document.querySelector("#template");
previewNode.id = "";
var previewTemplate = previewNode.parentNode.innerHTML;
previewNode.parentNode.removeChild(previewNode);
var myDropzone = new Dropzone(document.querySelector("#container-dropzone") , {
url: "/dashby/files/add/", //url to make the request to.
thumbnailWidth: 80,
thumbnailHeight: 80,
parallelUploads: 20,
previewTemplate: previewTemplate,
autoQueue: false,
previewsContainer: "#previews",
clickable: ".file-input-button",
headers: { // Tried to apply the token this way but no success.
'X-CSRFToken': $('meta[name="token"]').attr('content')
}
});
myDropzone.on("addedfile", function(file){
file.previewElement.querySelector(".start").onclick = function(){
myDropzone.enqueueFile(file);
};
});
myDropzone.on("totaluploadprogress", function(progress){
document.querySelector("#total-progress .progress-bar").style.width = progress + "%";
});
myDropzone.on("sending", function(file){
// Show total progress on start and disable START button.
document.querySelector("#total-progress").style.opacity = "1";
file.previewElement.querySelector(".start").setAttribute("disabled", "disabled");
});
// Hide progress bar when complete.
myDropzone.on("queuecomplete", function(progress){
document.querySelector("#total-progress").style.opacity = "0";
});
// Setup buttons for every file.
document.querySelector("#actions .start").onclick = function(){
myDropzone.enqueueFiles(myDropzone.getFilesWithStatus(Dropzone.ADDED));
};
document.querySelector("#actions .cancel").onclick = function(){
myDropzone.removeAllFiles(true);
};
});
In my base.html im adding all the required files (dropzone, jquery, bootstrap and my custom javascript file)
For the django form handling:
views.py
class DocumentCreate(CreateView):
model = Document
fields = ['file']
def form_valid(self, form):
self.object = form.save()
data = {'status': 'success'}
response = JSONResponse(data, mimetype =
response_mimetype(self.request))
return response
My "Document" model
class Document(models.Model):
file = models.FileField(upload_to = 'files/',
validators=[validate_file_type])
uploaded_at = models.DateTimeField(auto_now_add = True)
extension = models.CharField(max_length = 30, blank = True)
thumbnail = models.ImageField(blank = True, null = True)
def clean(self):
self.file.seek(0)
self.extension = self.file.name.split('/')[-1].split('.')[-1]
if self.extension == 'xlsx' or self.extension == 'xls':
self.thumbnail = 'xlsx.png'
elif self.extension == 'pptx' or self.extension == 'ppt':
self.thumbnail = 'pptx.png'
elif self.extension == 'docx' or self.extension == 'doc':
self.thumbnail = 'docx.png'
def delete(self, *args, **kwargs):
#delete file from /media/files
self.file.delete(save = False)
#call parent delete method.
super().delete(*args, **kwargs)
#Redirect to file list page.
def get_absolute_url(self):
return reverse('dashby-files:files')
def __str__(self):
#cut the 'files/'
return self.file.name.split('/')[-1]
class Meta():
#order by upload_date descending
#for bootstrap grid system. (start left side)
ordering = ['-uploaded_at']
I created a Json response to handle the dropzone.
response.py
from django.http import HttpResponse
import json
MIMEANY = '*/*'
MIMEJSON = 'application/json'
MIMETEXT = 'text/plain'
# Integrating Dropzone.js with Django.
def response_mimetype(request):
can_json = MIMEJSON in request.META['HTTP_ACCEPT']
can_json |= MIMEANY in request.META['HTTP_ACCEPT']
return MIMEJSON if can_json else MIMETEXT
# Custom HttpResponse
class JSONResponse(HttpResponse):
def __init__(self, obj='', json_opts=None, mimetype=MIMEJSON,
*args, **kwargs):
json_opts = json_opts if isinstance(json_opts, dict) else {}
content = json.dumps(obj, **json_opts)
super(JSONResponse, self).__init__(content, mimetype,
*args, **kwargs)
I've been stuck with this problem for a day now, so decided to ask for help here as I havn't been able to find one.
Thanks to anyone that takes the time to read and for any help/tips that I can get.

I have just figured this out, all you need to do is add this to your dropzone config:
headers: {'X-CSRFToken': '{{ csrf_token }}'},
good luck!

just place {% csrf_token %} anywhere in your Html file . it's automatically add
<input type="hidden" name="csrfmiddlewaretoken" value="**************" />
Before sending data to the server just add extra field csrf_token which value is $("input[name='csrfmiddlewaretoken']").val();

Django’s docs have a reference for this:
While [a special parameter] can be used for AJAX POST requests, it has some inconveniences: you have to remember to pass the CSRF token in as POST data with every POST request. For this reason, there is an alternative method: on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token. This is often easier, because many JavaScript frameworks provide hooks that allow headers to be set on every request.
[…]
Acquiring the token is straightforward:
// using jQuery
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');
[…]
Finally, you’ll have to actually set the header on your AJAX request, while protecting the CSRF token from being sent to other domains using settings.crossDomain in jQuery 1.5.1 and newer:
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);
}
}
});
If you run these two code blocks before you start to make requests, it should Just Work™.
In summary, just use this code block:
// from https://docs.djangoproject.com/en/1.10/ref/csrf/ via http://stackoverflow.com/a/39776325/5244995.
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) {
// 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);
}
}
});

The docs recommend getting the CSRF token from the cookie, not the DOM. Try that.

While this is an old thread, I thought I'd share the solution that worked for me.
var myDropzone = $("#file-upload").dropzone({
url: "/dashboard/api/v1/upload/",
// addRemoveLinks : true,
maxFilesize: 5,
dictResponseError: 'Error uploading file!',
headers: {'X-CSRFToken': window.CSRF_TOKEN},
success: (file, response) => {
console.log(JSON.parse(file.xhr.response));
}
});

Related

How to use csrf-token in POST-hyperlink?

I need to make a hyperlink in Django for a POST-request. For example, "Add to blacklist" in the menu. It's easy to do with a form with a submit button but I need a menu item not button. I found Javascript code for doing this but it gives me an error 403: CSRF token missing or incorrect. And I couldn't find understable for me information how to insert csrf-token into the Javascript function. I don't know Javascript, I write in Python.
Here's the function from https://ru.stackoverflow.com/questions/65237/Вызов-метода-post-через-ссылку:
<script type="text/javascript">
function postToUrl(path, params, method) {
method = method || "post";
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
for(var key in params) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
document.body.appendChild(form);
form.submit();
}
</script>
Here's how I call it:
To blacklist
This is my view:
class AddToBlacklistView(View):
def post(self, request, watched_user_id, next_url=None, *args, **kwargs):
if not next_url:
next_url = '../profile.html/user_id{0}'.format(watched_user_id)
if request.user.is_authenticated:
try:
user = User.objects.select_related("profile").get(username=request.user)
watched_user = User.objects.select_related("profile").get(id=watched_user_id)
except User.DoesNotExist:
raise Http404
if watched_user.id == user.id:
return redirect(next_url)
if watched_user not in user.profile.blacklist.all():
user.profile.blacklist.add(watched_user)
user.save()
if watched_user.profile in user.profile.friends.all():
user.profile.friends.remove(watched_user.profile)
if user.profile in watched_user.profile.friends.all():
friendship = Friendship.objects.get(user=watched_user.profile, friend=user.profile)
if friendship.status != 3:
friendship.status = 2
friendship.save()
if watched_user in user.profile.bookmarks.all():
user.profile.bookmarks.remove(watched_user)
return redirect(next_url)
else:
return redirect(next_url)
I tried this and it didn't help:
<meta name="csrf-token" content="{{ csrf_token }}">
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
</script>
I also tried to pass as params this and it didn't help:
csrfmiddlewaretoken: '{{ csrf_token }}'
Upd:
I also tried to add the decorator for a view and it continued to throw the same error:
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
#method_decorator(csrf_protect)
def post ...
I also tried # method_decorator(ensure_csrf_cookie) on the view that renders the page with HTML that calls the Javascript function and I still get 403 error.
I also tried this code from https://docs.djangoproject.com/en/3.0/ref/csrf/ and it continued to throw the same 403 error.
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// 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;
}
const csrftoken = getCookie('csrftoken');
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);
}
}
});
Please help me!
I found a solution here:
submitting a hyperlink by GET or POST
I had to modify it because on my page there is a list of people with a menu for each one of them in such a way:
<form id="myform1_{{ message.recipient.user.id }}" method="post" action="/account/add_to_blacklist/watched_user_id{{ message.recipient.user.id }}/next={{ request.get_full_path }}" >
{% csrf_token %}
</form>
Add to blacklist

How to send javascript variable to django

I am building a web app, where a user can set a value to a specific number. It looks like that
<button type="button" class="btn btn-outline-primary" onclick="decrease()"> +1 </button>
<button type="button" class="btn btn-outline-primary" onclick="increase()"> -1 </button>
<script>
var a = 0;
function increase()
{
a--;
document.getElementById("val").innerHTML = a;
}
function decrease()
{
a++;
document.getElementById("val").innerHTML = a;
}
</script>
Now I would like add an other button like:
<button type="button" class="btn btn-outline-primary" onclick="send()"> send it </button>
But I don't really now how to send it (maybe I should use axaj and POST). I would like to access the value from my django view.py file and process it further and send it back (here it's GET).
How can I do it?
Appreciate any help here
So I have found out how to do it.
html:
<button id="post-btn" class="btn btn-outline-primary"> test </button>
js:
var data = new FormData()
var a = 50;
var b = 100;
const button = document.getElementById('post-btn');
button.addEventListener('click', async _ => {
try {
data.append( "json", JSON.stringify(
{
'data1': a, /* var a = whatever */
'data2': b /* var b = whatever */
}
));
const response = await fetch('{% url "pulsox" %}', {
method: 'post',
headers: {
"X-Requested-With": "XMLHttpRequest"
},
body:data
});
}
catch(err)
{ window.alert('sth was wrong!'); }
});
view.py
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
#method_decorator(csrf_exempt, name='dispatch')
def pulsox_view(request, *args, **kwargs):
if request.method == 'POST':
print(request.POST.get('json'))
a = request.POST.get('json')
print(a)
if request.POST.get( youritem):
# do you stuff
return render(request, your_page ,obj)
else:
return render(request,your_page,obj)
return render(request,your_page,obj)

How to add element without submitting to another page

I would like to add a topping to my pizza using XMLHttpRequest without submitting to another page but I can't wrap my mind around how to implement it. So far I'm posting to add_topping route and getting a JsonResponse without any problem. But instead of going to the view, I would like to do it with JavaScript. I have already searched for similar problems but or they are all with PHP or with jquery but I would like to implement it using normal JavaScript with XMLHttpResponse.
HTML
<form id="add_topping" action="{% url 'orders:add_topping' %}" method="post">
{% csrf_token %}
<div class="form-row align-items-center">
<div class="form-group col-auto">
<select class="form-control" name="topping_selected" id="topping_selected">
{% for topping in topping_list %}
<option value="{{ topping }}">{{ topping }}</option>
{% endfor %}
</select>
</div>
<div class="form-group col-auto">
<button class="btn btn-secondary" type="submit">Add topping</button>
</div>
</div>
</form>
views.py
def add_topping(request):
# If request is not a POST request, return index
if request.method == 'POST':
# Get the data from the POST request
topping_selected = request.POST.get('topping_selected')
return JsonResponse({"success":True, "topping_added": topping_selected})
# Else return false
return JsonResponse({"success":False})
JavaScript
// Function to add topping
document.querySelector('#add_topping').onsubmit = function() {
// Create request object
const request = new XMLHttpRequest();
// Variables to determine the size and topping selected from the document
let topping_selected = document.querySelector('#topping_selected').value;
// Initialize the request
request.open('POST', '/add_topping', true);
// Callback function when the function completes
request.onreadystatechange() = () => {
// Extract JSON data from the request object
const data = JSON.parse(this.responseText);
console.log(data);
// Give feedback to user upon success/failure
if(data.success) {
const p = document.createElement("p");
p.innerHTML = "Topping added.";
// p.append();
// Append it to the #summary_before_add_to_cart div
document.querySelector('#summary_before_add_to_cart').append(p);
}
else {
const p = document.createElement("p");
p.innerHTML = "No topping added yet.";
// Append it to the #summary_before_add_to_cart div
document.querySelector('#summary_before_add_to_cart').append(p);
}
// Add data to send with the request
const data = new FormData();
data.append('topping_selected', topping_selected);
// Send the request
request.send(data);
// Stop submitting to another page
return false;
};
};
Thanks for any kind of help/advice. I know that this is basic stuff but I have to understand how to implement this. Thanks for your time!
here is the code that can help you do not forget to set RequestHeader as csrftoken else it will give you error
var xhr = new XMLHttpRequest();
xhr.open('POST', '{% url 'app:current_url' %}');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
console.log('Signed in as: ' + xhr.responseText);
};
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
xhr.send();
so in your case :
document.querySelector('#add_topping').onsubmit = function() {
const request = new XMLHttpRequest();
let topping_selected = document.querySelector('#topping_selected').value;
request.open('POST', '/add_topping', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.onload = function() {
const data = JSON.parse(this.responseText);
console.log(data);
if(data.success) {
const p = document.createElement("p");
p.innerHTML = "Topping added.";
document.querySelector('#summary_before_add_to_cart').append(p);
}
else {
const p = document.createElement("p");
p.innerHTML = "No topping added yet.";
document.querySelector('#summary_before_add_to_cart').append(p);
}
const data = new FormData();
data.append('topping_selected', topping_selected);
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;
}
request.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
request.send(data);
return false;
};
};

Upload file with text using AJAX & ASP.NET

I am having trouble uploading a file and value from a textbox/textarea in a single AJAX post. The entire project was created with AJAX posts to send data and receive resulting html/data. This means every button is handled with javascript/jquery and not asp.net's default onClick. Searches online yield answers with file upload but none of them show or explain any way to pass other parameters/data along with it.
*EDIT - I am not receiving any specific errors or crash attempting this. I try to run the file upload code in the success of the note upload or vice versa. It doesn't seem to be able to run both even if I switch it to asynchronous. I am more trying to get ONE single AJAX post to send both the file and the note to be handled in one codebehind function.
*EDIT(due to duplicate flag) - This is ASP.NET, not php. Please fully read questions before jumping to duplicate/closed conclusions.
Below is code/example of what I have so far.
HTML :
<div id="Modal_New_Document" class="modal fade" role="dialog">
<div class="modal-dialog Modal-Wrapper">
<div class="modal-content">
<div class="modal-header Modal-Header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3 class="modal-title">Upload New Document</h3>
</div>
<div class="modal-body Modal-Body">
<table>
<tr>
<th>Document :</th>
<td>
<input type="file" id="FileUpload_Modal_Document" />
</td>
</tr>
<tr>
<th>Note :</th>
<td>
<textarea id="TextArea_Modal_Document_Note" style="width: 400px;"></textarea>
</td>
</tr>
</table>
</div>
<div class="modal-footer Modal-Footer">
<button type="button" class="btn btn-success" onclick="enterDocumentInfo()">Upload</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
This is the most important part. I prefer to upload using the $.Ajax such as the example below. I was able to get only the file upload to work with the submitDocument()
Javascript :
function submitDocument()
{
var fileUpload = $("#FileUpload_Modal_Document").get(0);
var files = fileUpload.files;
var data = new FormData();
for (var i = 0; i < files.length; i++) {
data.append(files[i].name, files[i]);
}
var options = {};
options.url = "FileUploadHandler.ashx";
options.type = "POST";
options.data = data;
options.contentType = false;
options.processData = false;
options.success = function (result) { alert("Gud"); };
options.error = function (err) { alert(err.statusText); };
$.ajax(options);
}
$.ajax({
type: "POST",
url: "Lease_View.aspx/enterDocument",
data: JSON.stringify({
leaseID: leaseID,
userID: userID,
note: note
}),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function ()
{
// Gud
},
error: function ()
{
// Bad
}
});
Codebehind FileUpload
public class FileUploadHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.Files.Count > 0)
{
HttpFileCollection files = context.Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFile file = files[i];
// Upload code here
}
}
context.Response.ContentType = "text/plain";
context.Response.Write("File(s) Uploaded Successfully!");
}
public bool IsReusable
{
get
{
return false;
}
}
}
WebMethod Codebehind
I prefer to be able to upload file through this instead of above.
[System.Web.Services.WebMethod]
public static void enterDocument(string leaseID, string userID, string note)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString);
SqlCommand cmd;
cmd = new SqlCommand("INSERT INTO Lease_Documents " +
"(File_Name) " +
"VALUES " +
"(#File_Name)", conn);
cmd.Parameters.AddWithValue("#File_Name", note);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
I figured it out. Basically how to pass additional parameters is using data.append(name, value) in the javascript. You can receive the value in the .ashx handler by using (HttpContext)context.Request.Form["name"]. Unfortunately it is using the handler instead of the webmethod, but at least it works.
In Javascript
var data = new FormData();
for (var i = 0; i < files.length; i++) {
data.append(files[i].name, files[i]);
}
data.append("Note", note);
In Codebehind
string note = context.Request.Form["Note"].ToString();

Convert post-back to PHP via json to Ajax post

I am trying to integrate a Codeigniter application into Wordpress through a plugin. The codeigniter program is having difficulty in the control at this point when the customer confirms the data of a new appointment.
VIEW
<div id="wizard-frame-4" class="wizard-frame" style="display:none;">
<div class="frame-container">
<h3 class="frame-title"><?php echo $this->lang->line('step_four_title'); ?></h3>
<div class="frame-content row">
<div id="appointment-details" class="col-md-6"></div>
<div id="customer-details" class="col-md-6"></div>
</div>
</div>
<div class="command-buttons">
<button type="button" id="button-back-4" class="btn button-back"
data-step_index="4"><i class="icon-backward"></i>
<?php echo $this->lang->line('back'); ?>
</button>
<form id="book-appointment-form" style="display:inline-block" method="post">
<button id="book-appointment-submit" type="button" value="saveAppointment" name="submit1"
class="btn btn-success" onclick = "this.style.visibility='hidden', loading.style.visibility='visible'">
<i class="icon-ok icon-white"></i>
<?php
echo (!$manage_mode) ? $this->lang->line('confirm')
: $this->lang->line('update');
?>
</button>
<input type="hidden" name="csrfToken" />
<input type="hidden" name="post_data" />
</form>
</div>
</div>
JS:
$('#book-appointment-submit').click(function(event) {
var formData = jQuery.parseJSON($('input[name="post_data"]').val());
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'id_users_provider': formData['appointment']['id_users_provider'],
'id_services': formData['appointment']['id_services'],
'start_datetime': formData['appointment']['start_datetime'],
};
if (GlobalVariables.manageMode) {
postData.exclude_appointment_id = GlobalVariables.appointmentData.id;
}
var postUrl = GlobalVariables.baseUrl + '/index.php/appointments/ajax_check_datetime_availability';
$.post(postUrl, postData, function(response) {
////////////////////////////////////////////////////////////////////////
console.log('Check Date/Time Availability Post Response :', response);
////////////////////////////////////////////////////////////////////////
if (response.exceptions) {
response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately '
+ 'the check appointment time availability could not be completed. '
+ 'The following issues occurred:');
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
return false;
}
if (response === true) {
$('#book-appointment-form').submit();
} else {
GeneralFunctions.displayMessageBox('Appointment Hour Taken', 'Unfortunately '
+ 'the selected appointment hour is not available anymore. Please select '
+ 'another hour.');
FrontendBook.getAvailableHours($('#select-date').val());
alert('#select-date');
}
}, 'json');
});
CONTROLLER:
if($this->input->post('submit2'))
{
$post_waiting = json_decode($_POST['post_waiting'], true);
$waitinglist = $post_waiting['appointment'];
$this->load->model('appointments_model');
$this->appointments_model->waitinglist_to_db($waitinglist);
$this->load->view('appointments/waiting_success');//return to book view
} else {
try {
$post_data = json_decode($_POST['post_data'], true);
$appointment = $post_data['appointment'];
$customer = $post_data['customer'];
if ($this->customers_model->exists($customer))
$customer['id'] = $this->customers_model->find_record_id($customer);
$customer_id = $this->customers_model->add($customer);
$appointment['id_users_customer'] = $customer_id;
$appointment['id'] = $this->appointments_model->add($appointment);
$appointment['hash'] = $this->appointments_model->get_value('hash', $appointment['id']);
$provider = $this->providers_model->get_row($appointment['id_users_provider']);
$service = $this->services_model->get_row($appointment['id_services']);
$company_settings = array(
'company_name' => $this->settings_model->get_setting('company_name'),
'company_link' => $this->settings_model->get_setting('company_link'),
'company_email' => $this->settings_model->get_setting('company_email')
);
It returns Customers_Model->exists(NULL) and says that customers email was not provided. This is all wrong and does not happen outside the frame. It appears that I cannot postback when the application is run within the wordpress page and shortcode. So, I believe I need to do an Ajax post instead. What would that look like in this case? Would it require major surgery on the code?
As I worked on this I narrowed down my question little by little and posted the solution here:
AJAX submit and 500 server error

Categories