How to create Ajax refresh for django-simple-captcha - django

I'm using the django-simple-captcha app for my django based website, I am able to integrate the captcha form field into my form, but the problem is, how do I create a button which calls Ajax refresh to refresh the captcha image on click? The documentation for the app is not very clear, and I tried to follow the example given in the documentation but it doesn't work. Please help me on this issue?
EDIT: Here's the link to the django package:
django-simple-captcha

Here's a working implementation in javascript:
$(function() {
// Add refresh button after field (this can be done in the template as well)
$('img.captcha').after(
$('Refresh')
);
// Click-handler for the refresh-link
$('.captcha-refresh').click(function(){
var $form = $(this).parents('form');
var url = location.protocol + "//" + window.location.hostname + ":"
+ location.port + "/captcha/refresh/";
// Make the AJAX-call
$.getJSON(url, {}, function(json) {
$form.find('input[name="captcha_0"]').val(json.key);
$form.find('img.captcha').attr('src', json.image_url);
});
return false;
});
});
Then you just need to add some CSS for the class captcha-refresh, perhaps place an image in the <a> and you're good to go!

The chosen answer is with jQuery not JavaScript.
If using purely JavaScript you should do this instead. This will also refresh the audio not just the image django-simple-captcha uses.
https://django-simple-captcha.readthedocs.io/en/latest/advanced.html#rendering
FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
custom_field.html:
​
{% load i18n %}
{% spaceless %}
<label class="control-label">{{ label }}</label>
<img src="{{ image }}" alt="captcha" class="captcha" />
<br/>
<audio id="audio" controls>
<source id="audioSource" src="{{ audio }}" />
</audio>
{% include "django/forms/widgets/multiwidget.html" %}
{% endspaceless %}
Forms.py:
​
class CustomCaptchaTextInput(CaptchaTextInput):
template_name = 'custom_field.html'
​
class Form(forms.Form):
captcha = CaptchaField(widget=CustomCaptchaTextInput)
​
def __init__(self, *args, **kwargs):
super(Form, self).__init__(*args, **kwargs)
self.fields['captcha'].widget.attrs['placeholder'] = 'Solve the captcha'
self.fields['captcha'].label = "Captcha"
Add this at the end of the body tag:
<script>
const captchas = document.querySelectorAll('img.captcha')
function headers(options) {
options = options || {}
options.headers = options.headers || {}
options.headers['X-Requested-With'] = 'XMLHttpRequest'
return options
}
for (const captcha of captchas) {
const anchor = document.createElement('a')
anchor.href = '#void'
anchor.classList.add('captcha-refresh')
anchor.textContent = 'Refresh'
anchor.addEventListener('click', ({ target }) => {
const url = `${window.location.origin}/captcha/refresh/`
let formEl = target.parentElement
while (formEl && formEl.tagName.toLowerCase() !== 'form') {
formEl = formEl.parentElement
}
fetch(url, headers())
.then(res => res.json())
.then(json => {
formEl.querySelector('input[name="captcha_0"]').value = json.key
captcha.setAttribute('src', json.image_url)
document.getElementById('audioSource').setAttribute('src', json.audio_url)
document.getElementById('audio').load()
})
.catch(console.error)
return false
})
captcha.after(anchor)
}
</script>

Related

Django : Displays "No Value " When trying to fetch checked checkbox without submit using AJAX

i wrote a program using django to retrieve all checked checkbox without submit button by using AJAX , it is not throwing any error , but it displays "NO Value " . Can anyone check and tell me what is the mistake i did .
AJAX :
<script>
$('.form-check-input').change(function(){ // checkbox1 change event
var checked_lists = [];
$(".form-check-input:checked").each(function() {
checked_list.push(this.value);
});
var formdata = new FormData();
$.ajax({
formdata.append('checked_list',checked_list)
formdata.append('csrfmiddlewaretoken',$('input[type=hidden]').val());
$.ajax({
url:"secondtableonDashboard", //replace with you url
method:'POST',
data:formdata,
enctype: 'application/x-www-form-urlencoded',
processData:false,
contentType:false,
success:function(data){
alert("Display return data"+data)
},
error:function(error){
alert(error.error)
}
});
});
});
</script>
Views.py
def secondtableonDashboard(request):
conn = pyodbc.connect('Driver={SQL Server};'
'Server=ABC\SQLEXPRESS;'
'Database=WebstartUI;'
'Trusted_Connection=yes;')
cursor = conn.cursor()
cursor.execute("select * from CustomerServer")
result = cursor.fetchall()
if request.method=='POST':
user_list = request.getlist('checked_list')
print(user_list)
else:
print("No Values")
html :
<td>
<div class="form-check form-switch">
<input class="form-check-input" name="Servers[]" value="{{datas.ServerName}}" type="checkbox" id="flexSwitchCheckDefault">
<label class="form-check-label" for="flexSwitchCheckDefault">
</div>
</td>
So here i use my views.py, same function to keep data in checkbox and to get POST values.
UI:

Add new object to list without refreshing with Django & Ajax

I'm searching for someone who helps me in a Django project with JS, Ajax and jquery.
I'm trying to create something like adding objects on the django-admin page. I used https://www.pluralsight.com/guides/work-with-ajax-django, and almost everything is working fine but...
On my form, I have multiple choice field with authors, when I pressed the button to add a new author, the object is properly saving in DB, but on the form, I can't see a new object. When I reload the page, the new object is on this multiple choice field.
I thought I should refresh the field to see a new object on the list, but I don't know it's the proper way to meet this goal.
[edit]
models.py
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
book_author = models.ManyToManyField(Author,blank=True,)
...
form.py
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = ['name', ]
widgets = {
'name': forms.TextInput(),
}
views.py
I added class SaveAutor
def author_add_view(request):
form = AuthorForm()
return render(request,
"author/custom_create_author.html",
{"form": form})
class SaveAuthor(View):
template_name = "author/custom_create_author.html"
def get(self, request):
author_form = AuthorForm(request)
return render(request,
self.template_name,
{'form': author_form})
def post(self, request):
#assume authorForm has author_name defined
author_form = AuthorForm(data=request.POST)
if author_form.is_valid():
author = Author() #here is class name or form name?
author.name = author_form.cleaned_data['name']
author.save()
return JsonResponse({'author_id': author.id,
'author_name': author.name})
# error response or whatever you want to return
return JsonResponse({'error': 'author form is not valid'})
I had these views registered in urls.py
urls.py
# add an author
path('author/add/', views.author_add_view,
name='author_add'),
# not sure if I should add as_view() at the end
path('author/new-add/', views.SaveAuthor.as_view(),
name='new_author_add'),
When I try check if page with form is displaying properly using the SaveAuthor class based view I get error 'WSGIRequest' object has no attribute 'get', but when I use the author_add_view I got the template.
custom_create_author.html
$("#author-form").submit(function (e) {
// preventing from page reload and default actions
e.preventDefault();
// serialize the data for sending the form data.
var serializedData = $(this).serialize();
// make POST ajax call
$.ajax({
type: 'POST',
url: "{% url '.' %}", //serializer_ajax_mehit_from_vies
data: serializedData,
success: function (response) {
// on successfull creating object
// 1. clear the form.
$("#author-form").trigger('reset');
// 2. focus to nickname input
$("#id_author_name").focus();
},
error: function (response) {
// alert the error if any error occured
alert(response["responseJSON"]["error"]);
}
})
})
{% load static %}
{% load widget_tweaks %}
{% block content %}
<h4>
My author
</h4>
<form id="author-form">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<button class="btn btn-outline-success" type="submit">save</button>
</form>
<br>
{% endblock %}
Here is another page where I'm trying to connect the book with multiple-choice-field author (it's typical form, but I'm enclosing only the button to pop-up the form, where I can add the new author)
add_book.html js code open pop-up windows to create new author
<script type="text/javascript">
$(function () {
$("#create-author").modalForm({
formURL: "{% url 'author_add' %}"
});
})
</script>
<button id="create-author" class="btn btn-primary" type="button" name="button">
<span class="fa fa-plus"/>
</button>
And on this page, I tried to paste your JS code
<script type="text/javascript">
// assume the add author button has an id of add_author_button
$('#create-author').click(function(event){
event.preventDefault();
// assume the text field has an id of author_name
author_name= $('#author_name').val();
create_post(event, author_name);
}
) //<-------- this closing bracket was missing?
function create_post(event, author_name) {
$.ajax({
url: "{% url '.' %}", // the endpoint I'll precise that in comment
type: "POST", // http method
data: {
author_name: author_name,
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val()
},
// handle a successful response - data will be a json object returned from your view method
success: function (data) {
if (data.error === null) {
// assume your author multiple choice select has an id of author_sel
// this will append the new author name to the list and will also
// set the value for this author to be the newly created id so you can
// perform other functions on the author like update and/or delete
$('#author_id').append($('<option/>', {
value: data.author_id,
text: data.author_name,
}));
} else {
// display the error on the page
// and/or write it to the console log
console.log(data.error);
}
},
// handle a non-successful http response
error: function (xhr, errmsg, err) {
// display the error on the page
// and/or write it to the console log
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
}
</script>
One closing bracket was missing, so I added in on the JS script.
I had a problem with the endpoint, when I pass the class-based view SaveAuthor(View) (new_author_add by url name) I got the message: the author form is not valid, but when I used author_add_view (author_add by url name) undefined.
The issue is that while you are using AJAX to submit your new author, the author isn't being added to the author's multiple choice field in the current HTML page. Refreshing the page will retrieve the new value but that also does an entire post/refresh loop. Since you are submitting the post using AJAX, you can return the new author's id and name via a JsonResponse and use jQuery to add it to the author's multiple choice field.
views.py
from MyApp.forms import AuthorForm
from MyApp.models import Author
from django.shortcuts import render
from django.views import View
from django.http.response import JsonResponse
class SaveAuthor(View):
template_name = "author/author.html"
def get(self, request):
author_form = AuthorForm()
return render(request,
self.template_name,
{"form": author_form,
"authors":Author.objects.all()})
def post(self, request):
#assume authorForm has author_name defined
author_form = AuthorForm(data=request.POST)
if author_form.is_valid():
author = Author() #here is class name or form name?
author.name = author_form.cleaned_data['name']
author.save()
return JsonResponse({'author_id': author.id,
'author_name': author.name})
# error response or whatever you want to return
return JsonResponse({'error': 'author form is not valid'})Your AJAX
author.html
<!DOCTYPE html>
{% load static %}
<script src="{% static "jquery-3.4.1.min.js" %}"></script>
{% block content %}
<h4>
My author
</h4>
<select id="author_sel" name="author_sel" size="5" class="selectbox">
{% for author in authors %}
<option value="{{author.id}}">{{author.name|capfirst}}</option>
{% endfor %}
</select>
<form id="author-form">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<input type="button" name="button" class="submit_button" id="add_author_button" value="Save">
</form>
<br>
{% endblock %}
<script type="text/javascript">
// assume the add author button has an id of add_author_button
$('#add_author_button').click(function(event){
event.preventDefault();
// assume the text field has an id of author_name
author_name= $('#id_name').val();
create_post(event, author_name);
}) //<-------- this closing bracket was missing?
function create_post(event, author_name) {
$.ajax({
url: ".", // the endpoint I'll precise that in comment
type: "POST", // http method
data: {
name: author_name,
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val()
},
// handle a successful response - data will be a json object returned from your view method
success: function (data) {
if (data.error === undefined) {
// assume your author multiple choice select has an id of author_sel
// this will append the new author name to the list and will also
// set the value for this author to be the newly created id so you can
// perform other functions on the author like update and/or delete
$('#author_sel').append($('<option/>', {
value: data.author_id,
text: data.author_name,
}));
} else {
// display the error on the page
// and/or write it to the console log
console.log(data.error);
}
},
// handle a non-successful http response
error: function (xhr, errmsg, err) {
// display the error on the page
// and/or write it to the console log
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
}
</script>
urls.py
from django.urls import path
from . import views
app_name = 'myapp'
urlpatterns = [
# add an author
path('add/', views.SaveAuthor.as_view(), name='author_add'),
]
forms.py
from django import forms
from MyApp.models import Author
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = ['name', ]
widgets = {
'name': forms.TextInput(),
}
models.py
from django.db import models
# Create your models here.
class Author(models.Model):
name = models.CharField(max_length=100)
This is now a complete working example.

Django: How to upload a file using ajax

I am using django 1.5, python 2.7 and jquery 1.9. I have a form which has precisely 2 fields i.e. title and document. When I press submit I want the users chosen document to be present in the request.FILES as shown in the view.
When I submit the regular form (without ajax), this works fine, but with ajax I do not get the file field in my request. Any suggestions on how to upload a file using ajax.
HTML:
<form enctype="multipart/form-data" action="{% url 'upload_document' %}" method="post" id="uploadForm">
{% csrf_token %}
<ul>
<li>
<div>Title</div>
<input id="title" type="text" maxlength="200"/>
<div class="error"></div>
</li>
<li>
<div>Upload File</div>
<input id="document" type="file" size="15" />
<div class="error"></div>
</li>
</ul>
<input type="submit" value="submit"/></p>
</form>
FORMS.PY:
class UploadForm( forms.Form ):
document = forms.FileField()
title = forms.CharField(max_length = 200)
def clean(self):
cleaned_data = super(UploadForm, self).clean()
return cleaned_data
def save(self, *args, **kwargs):
title = self.cleaned_data['title']
doc = self.cleaned_data['document']
document = Document(title = title, document = doc)
document.save()
return document
SCRIPT:
<script type="text/javascript">
$("#uploadForm").submit(function(event){
event.preventDefault();
$.ajax({
url : "{% url 'upload_document' %}",
type: "POST",
data : {csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
title: document.getElementById('title').value,
//document: document: document.getElementById('document'),
},
dataType : "json",
success: function( response ){
if(response == "True"){
// success
}
else {
//append errors
}
}
});
});
</script>
VIEWs.PY
def upload_document(request):
print request.POST
print request.FILES
if request.is_ajax():
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES, user = request.user)
if form.is_valid():
form.save()
return HttpResponse(simplejson.dumps('True'), mimetype = 'application/json' )
else:
errors = form.errors
return HttpResponse(simplejson.dumps(errors), mimetype = 'application/json' )
The answer to that question is not that simple. First of all if you intend to support old browsers then indeed it gets nasty. You have to deal with hidden iframes and some JavaScript tricks. I do advice using some well-known scripts for that like jQuery-File-Upload.
But the world is evolving and new technologies arise including HTML5. There's a new File API which is available in most modern browsers ( IE10+, FireFox3.6+, Chrome13+, see: http://caniuse.com/fileapi ) which can be used for that. First you need some HTML:
<input type="file" id="file-select" />
Then you can bind to (for example) change event:
$('#file-select').change( handleFileSelect );
and finally the handler itself:
var data = {};
function createReaderHandler(name) {
return function(ev) {
data[name] = ev.target.result;
};
}
function handleFileSelect(ev) {
var files = ev.target.files; // FileList object
// Loop through the FileList
for (var i = 0; i < files.length; i++) {
var file = files[i],
name = file.name || file.fileName,
reader = new FileReader();
reader.onload = createReaderHandler(name);
reader.readAsText(file);
}
}
Once the data is loaded into JavaScript memory (note that the operation is asynchronous) you can send it via AJAX like any other data. There are more options: depending on your file you can read it as a binary data using .readAsBinaryString and so on. Google is your friend. :)
Also I think there already are good scripts for uploading files with a fallback to old methods. This one can be interesting (haven't tried it):
http://www.plupload.com/
I think the issue is in the submit button, change it into normal button
ie, <button type='button' id='submit'>submit</button>(by default all buttons in form are submit)
and the ajax as
$('#submit').on('click',function(){
frm = $(this).parents('form')
$.ajax({
type: frm.attr('method'),
dataType:'json',
url: frm.attr('action'),
data: frm.serialize(),
async: false,
success: function (data) {
console.log('success')
},
error: function(data) {
console.log("Something went wrong!");
}
})
All others will be same
Just try it will work

django jeditable not working

PLease i need your help, i'm trying to use jeditable to edit a field on a table inside {% for in %}.
editable DIV:
<td><div class="edit" id="{{ c.id }}">{{ c.name|safe }}</div></td>
jeditable code:
<script>
$(document).ready(function(){
$('.edit').editable('/categoryedit/{{ c.id }}/', {
style: 'display: inline'
});
});
</script>
Url:
url(r'^categoryedit/(?P<id>\d+)/$', 'pos.views.CategoryEdit'),
View:
def CategoryEdit(request, category_id):
id = request.POST.get('category_id', '')
value = request.POST.get('value', '')
categoria = Category.objects.get(pk=id)
categoria.name = value
categoria.save()
return HttpResponse(escape(value))
Solution : The problem was that the editable DIV was inside a {% for %} bucle and in that case is needed to use .each en the Javascript like this...
$('.edit').each(function(){
$('.edit').editable('/categoryedit', {
});
});
and is not necessary to pass the parameters in the url ("/category/1") instead is better to get the parameters using ...
c_id = request.POST.get('id')
the View must be like this:
def CategoryEdit(request):
if request.is_ajax():
if request.method == 'POST':
txt = request.POST.get('value')
c_id = request.POST.get('id')
categoria = Category.objects.get(pk=c_id)
categoria.name = txt
categoria.save()
return HttpResponse(txt)
You probably need to add CSRF data to your javascript. I just ran into this and posted it here:
Django and JEditable: CSRF error
One way to see for sure is to use firebug and look at the ajax response coming back from Django. (If the CSRF info is missing, the Jeditable AJAX call throws a 403 Forbidden error.)

jquery ajax / django - present form in a bootstrap modal and re-show if validation was not successful

my use case is:
a) Present a form loaded via ajax in a bootstrap modal, the fancy overlay effect stuff.. . I followed these instructions.
This works fine. (see code below)
b) Submit this form back to my Django app, try to validate it, and if it does not validate, re-show the form with the errors in the fancy bootstrap modal.
I can reload the form via ajax, but I m not able to represent it again in the modal.
Note: I did not include the view since it does nothing special. Only instantiating and validating the form.
Quite a lot to read below, so just continue if you think the use case sounds interesting...
My taskList.html looks like this:
<table id="listItemTable" class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
<tr>
<td>Task 1</td>
<td><a class="editItem" href="/update/item/1/">edit</a></td>
</tr>
</tbody>
</table>
<div class="modal hide" id="itemFormModal"></div>
<div id="modalExtraJsPlaceholder"></div>
.js for loading the form + showing the bootstrap modal + binding form to a .jquery submit call:
$(document).ready(function() {
modalConnect();
});
<script type="text/javascript">
//connects the modal load for each <a> with class editItem
//Functionality 1
//loads an item edit form from the server and replaces the itemFormModal with the form
//presents the modal with $("#itemFormModal").modal('show');
//Functionality 2
//loads some extra js "modalExtraJsHtml"
//calls the function "submitItemModalFormBind" which has been loaded via "modalExtraJsHtml"
function modalConnect(){
$(".editItem").click(function(ev) { // for each edit item <a>
ev.preventDefault(); // prevent navigation
url = ($(this)[0].href); //get the href from <a>
$.get(url, function(results){
var itemForm = $("#ajax_form_modal_result", results);
var modalExtraJs = $("#modalExtraJs", results);
//get the html content
var modalExtraJsHtml = modalExtraJs.html();
//update the dom with the received results
$('#itemFormModal').html(itemForm);
$('#modalExtraJsPlaceholder').html(modalExtraJsHtml);
$("#itemFormModal").modal('show');
submitItemModalFormBind(); //bind loaded form to ajax call
}, "html");
return false; // prevent the click propagation
})
}
</script>
The itemForm returned from the view looks like this:
<form id="#ajax_form_modal_result" class="well" method="post" action="/update/item/{{ item.id }}">
<div id="ajax_form_modal_result_div">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3>Edit Item</h3>
</div>
<div class="modal-body">
{% csrf_token %}
{{form.as_p}}
</div>
<div class="modal-footer">
<input class="btn btn-primary" type="submit" value="Save" />
<input name="cancel" class="btn" type="submit" value="Cancel"/>
</div>
</div>
</form>
Loading and showing the modal works fine.
But now comes the second part which does not work as expected. The issue is the following. If the form does not validates, the view returns the form. The returned form should be shown again in the bootstrap modal. But the result is that ONLY the form is presented in the browser, everything else is lost. No css, no table, only the form. Quite ugly.. Thus I did not achieve to update the ajax_form_modal_result_div. Can anyone help me out here what I m doing wrong..!?
The view returns also the js function 'submitItemModalFormBind' which prevents the form default behavior and sends the form via ajax.
<div id="modalExtraJs">
//ajax bind for update item form visualized via modal
function submitItemModalFormBind(){
var url = "{% url updateItem item.pk %}";
$('#ajax_form_modal_result').submit(function(){
$.ajax({
type: "POST",
url: "{% url updateTask item.pk %}",
data: $(this).serialize(),
success:function(response){
var div = $("ajax_form_modal_result_div", response);
$('#ajax_form_modal_result_div').html(div);
},
error: function (request, status, error) {
console.log("failure");
console.log(request.responseText);
}
});
});
return false;
}
</div>
Found a working approach (based upon this solution - and enhanced it with handling of invalid forms) and will post it for anybody who also want to use the stunning beautiful bootstrap modals with django. Major issue with the code above was that I did not correctly disabled the default behavior of the submit button and the approach for loading additional js was not a good idea. So I changed my strategy.
On documentReady or ajaxStop event bind the click event of the hyperlinks to the modalConnect function. Note that you only need the ajaxStop function if you have some kind of ajax which updates the content of your table (which I have):
<script type="text/javascript">
$(document).ready(function() {
modalConnect();
});
</script>
<script type="text/javascript">
$( document ).ajaxStop( function() {
modalConnect();
});
</script>
The modalConnect function which loads the form which we want to present in the modal and a formUpdateURLDiv:
<script type="text/javascript">
function modalConnect()
{
//unbind the click event. If not done we will end up with multiple click event bindings, since binding is done after each ajax call.
$(".editItem").unbind('click');
//bind the click event
$(".editItem").click(function(ev) { // for each edit item <a>
ev.preventDefault(); // prevent navigation
var url = this.href; //get the href from the <a> element
$.get(url, function(results){
//get the form
var itemForm = $("#ajax_form_modal_result", results);
//get the update URL
var formUpdateURLDiv = $("#formUpdateURL", results);
//get the inner html of the div
var formUpdateURL = formUpdateURLDiv.html();
//update the dom with the received form
$('#itemFormModal').html(itemForm);
//show the bootstrap modal
$("#itemFormModal").modal('show');
$(document).ready(function () {
//bind the form to an ajax call. ajax call will be set to the received update url
submitItemModalFormBind(formUpdateURL);
});
}, "html");
return false; // prevent the click propagation
})
}
</script>
the formUpdateURL includes a server generated (see included view below) url to which the loaded form has to make its form submission call. We use this url to "init" the submitItemModalFormBind function:
<script type="text/javascript">
function submitItemModalFormBind(url){
//bind the form. prevent default behavior and submit form via ajax instead
$('#ajax_form_modal_result').submit(function(ev){
$.ajax({
type: "POST",
url: url,
data: $(this).serialize(),
success:function(response, textStatus, jqXHR){
var form = $("#ajax_form_modal_result_div", response);
//form is returned if it is not valid. update modal with returned form
//change this "if" to check for a specific return code which should be set in the view
if (form.html()) {
console.log('Form was invalid and was returned');
//update modal div
$('#ajax_form_modal_result_div').html(form);
$("#itemFormModal").modal('show');
}
//form is not returned if form submission succeeded
else{
//update the entire document with the response received since we received a entire success page and we want to reload the entire page
document.open();
document.write(response);
document.close();
//sort by modified date descending
//var notificationDiv = $("#notification", response);
//$('#notification').html(notificationDiv.html());
console.log('Form was valid and was not returned');
$("#itemFormModal").modal('hide');
}
},
error: function (request, status, error) {
var div = $("ajax_form_modal_result_div", request.responseText);
$('#ajax_form_modal_result_div').html(div);
//implement proper error handling
console.log("failure");
console.log(request.responseText);
}
});
return false;
});
}
</script>
..and to see what is going on at the server see below the view which handles the logic:
class UpdateTaskModalView(LoginRequiredMixin, View):
template = 'list_management/crud/item/update_via_modal.html'
def get_logic(self, request, task_id, **kwargs):
task = get_object_or_404(Task.objects, pk=task_id)
task_form = TaskForm(instance=task)
context = {
'model_form': task_form,
'item': task,
}
return context
def post_logic(self, request, task_id, **kwargs):
task = get_object_or_404(Task.objects, pk=task_id)
task_form = TaskForm(request.POST, instance=task)
if task_form.is_valid():
task = task_form.save(commit=False)
task.modified_by = request.user
task.save()
messages.add_message(request, messages.INFO, 'Item "%s" successfully updated' % (task.name))
return ('redirect', HttpResponseRedirect(reverse('show_list_after_item_update', kwargs={'list_id':task.list.pk, 'item_id':task.pk})))
context = {
'model_form' : task_form,
'list': task.list,
'item': task,
}
return ('context', context)
def get(self, request, task_id, **kwargs):
context = self.get_logic(request, task_id, **kwargs)
return render_to_response(
self.template,
context,
context_instance = RequestContext(request),
)
def post(self, request, task_id, **kwargs):
post_logic_return = self.post_logic(request, task_id, **kwargs)
if post_logic_return[0] == 'redirect':
return post_logic_return[1]
if post_logic_return[0] == 'context':
context = post_logic_return[1]
return render_to_response(
self.template,
context,
context_instance = RequestContext(request),
)
..the form template is already included in my question: ajax_form_modal_result_div, you only have to provide also the formUpdateURL. I did it via the template, which seems quite odd now that I write this post. could be easily provided via the view context.
Voila - Django Forms with Bootstrap Modals! Spice up your UI!
I hope this helps somebody to solve a similar problem.
I wrote this simple AJAX that did the trick for me, hope it helps:
$(document).on('submit', 'div.modal-body form', function(e) {
var form_el = $(this);
e.preventDefault();
$.ajax({
type: $(this).attr('method'),
url: $(this).attr('action'),
data: $(this).serialize(),
success: function (xhr, ajaxOptions, thrownError) {
if ( $(xhr).find('.errorlist').length > 0 ) {
form_el.parents('.modal-body').html(xhr);
} else {
form_el.parents('.modal-body').html('<h4>Formulario enviado correctamente</h4>');
}
},
error: function (xhr, ajaxOptions, thrownError) {
form_el.parents('.modal-body').html(xhr);
}
});
});
Oh btw, you will also need something like this in order to load your form into the modal:
$('.modal-class').on('click',function(){
let dataURL = $(this).attr('data-href');
$('.modal-body').load(dataURL,function(){
$('#modal_crear').modal({show:true});
});
});