I am very confused as to how to write the code in javascript/jquery to allow for the proper submission of my form. I currently have a function to handle an on-click event, which loads the proper form. However, the form fails to submit successfully. I am using the .submit() function, but I think I am missing something here. I believe the URL I would have to place in that function would be the one being dynamically loaded in the onclick function. Is there a reasonable way to transfer this information? Or am I mistaken?
I have already confirmed that the correct URL is loaded and that the form behaves as intended if the URL is accessed manually. This issue seems to be unique to loading the URL
from select_my_book.html (the url to be loaded)
<form action="" method="POST" id="submitForm">
{% csrf_token %}
<!-- Code to render form elements -->
<input type="submit" value = "Buy" id="submit">
</form>
from get_my_book.html (the current url with the tabs/jumbotron)
{% for course in userprofile.courses.all%}
<div class="minicoursenav">
<a class='course_link' data='{{ course.pk }}' href='#' type="submit">
{{ course.name }}
</a>
</div>
{% endfor %}
from activate.js
function selectConditionURL(criterion, condition){
var url = "/books/select_my_book/"
return(url+ condition + "/" + criterion + "/")
}
function selectCourseURL(criterion){
var url = "/books/select_my_book/best_price/";
return (url + criterion + "/");
}
$('.course_link').click(function(e) {
e.preventDefault();
var course_pk = $(this).attr('data');
/*alert( course_pk );*/
var url = selectCourseURL(course_pk);
/*alert( url );*/
$("#best_price").load(url);
$("#very_good").load(selectConditionURL(course_pk, "very_good_condition"));
$("#good").load(selectConditionURL(course_pk, "good_condition"));
$("#fine").load(selectConditionURL(course_pk, "fine_condition"));
return false;
})
$(document).ready(function() {
$("#submitForm").submit(function(e) {
e.preventDefault();
$.ajax({
type: "POST",
/* NOT SURE WHAT SHOULD GO HERE */
success: function(response) {
console.log(response)
}
});
return false;
})
})
Related
I need to get database objects on the HTML only when the the SUBMIT is clicked and not on page load. I currently have an AJAX script running on the same form where it returns the text entered in textbox onto the HTML when submit is clicked. I want this feature to stay as well as add a new feature of retrieval of data. Below are some of the code snippets I am using:
views.py
#csrf_exempt
def chat(request):
resps = Responses.objects.all()
context = {'resps' : resps}
return render(request, "chat.html", context)
urls.py
path('chat/', views.chat, name='chat'),
chat.html
<form id="testForm" name="test-form" class="test-form" action="" method="POST">{% csrf_token %}
<input id="texting" name="texting" type="text" class="test-text" placeholder="Test here"/>
<div class="footer">
<input type="submit" value="SEND">
</form>
</div>
{% for r in resps %}
<div>
<p>{{r.response}}</p>
</div>
{% endfor %}
................................................
<script type="text/javascript">
$(document).on('submit','#testForm', function(e){
e.preventDefault();
$.ajax({
type : 'POST',
url : '/chat/',
data :{
text : $('#texting').val(),
csrfmiddlewaretoken: $('input[text=csrfmiddlewaretoken]').val()
},
success : function(){
// alert("Done!");
document.getElementById("userSpeaks").innerHTML = document.getElementById('texting').value;
}
});
});
</script>
Any help would be appreciated. I just need a way out to print the model objects on each click of the submit button and not automatically on page load. Thanks in advance.
Please change the line
csrfmiddlewaretoken: $('input[text=csrfmiddlewaretoken]').val()
to
csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val()
So you will have to send your querylist as a json object if you want it to be sent through ajax
from django.http import JsonResponse
from django.core.serializers import serialize
#csrf_exempt
def chat(request):
data = {
'resps': serialize("json", Responses.objects.all())
}
return JsonResponse(data)
and you success will look something like this
success : function(data){
// alert("Done!");
resps = JSON.parse(data.resps);
var htmldata=""
for(var x in resps){
htmldata+="<p>"+resps[x].fields.xyz+"</p>"
}
$("#userSpeaks").html(htmldata);
}
I'm working on a Like button. It's working fine. After Like button completes it's functionality I'm trying to update the button text (Like to Liked) without refreshing the page, but problem is that It's updating the every single Like button on the webpage (until I refresh the page) not just the one I clicked on . . .
Here's that success function in AJAX call,
$('.like-click').click(function(e){
e.preventDefault();
var this_ = $(this);
var quesURL = this_.attr('like-href');
$.ajax({
url: quesURL,
method: 'GET',
data: {},
success: function (data) {
var like_text = $(data).find('.like-click').html();
$('.like-click').html(like_text);
}
})
});
Here's the HTML code,
{% for data in datas %}
...
<a class="like-click" like-href="...">{% if user in Likes %}Liked{% else %}Like{% endif %}</a>
...
{% endfor %}
How can I update the button I clicked, not all of them ?
You have saved your clicked element in var this_, so you have to just update that element text only via replacing $('.like-click').html(like_text); to $(this_).html(like_text);
So it will not update each button text.
that's happened because you firing all button with having 'like-click' class
$('.like-click').click(function(e){
e.preventDefault();
var this_ = $(this);
var quesURL = this_.attr('like-href');
$.ajax({
url: quesURL,
method: 'GET',
data: {},
success: function (data) {
if(this_.html()=='like'){
this_.html('liked');
}else{
this_.html('like');
}
}
})
});
Why you use AJAX for this? You are not pulling "Like" or "Liked" from database. Do it with simple handler:
$(function(){
$('button').click(
function(){
$(".button div").toggle();
}
)
});
<button type="button" class="button like-click">
<div>Like</div>
<div style="display: none">Liked</div>
</button>
And note, that selecting button / a element by class="like-click" is probably not what you need (it would affect all elements by that class), so better asing them ids that are unique and comes from your {% for data in datas %} loop
UPDATE:
Because you dont have a dislike, it could be done in same manner as in my above example:
<button type="button" class="button" id="btn">
<div class="like">Like</div>
<div style="display: none" class="like">Liked</div>
<div class="count" id="current"> 1 </div>
<div style="display: none" class="count" id="clicked"> </div>
</button>
$('#btn').click(function() {
$('#btn #clicked').html(parseInt($('#current').text()) + 1);
$('#btn .like').toggle();
$('#btn .count').toggle();
})
i'm quite new using django and i've been stuck in this problem for several days.
I have a form.Form in a bootstrap modal on my template with only 1 field (email_field) and basically i need to submit that form via ajax, check if that email address is registered in the database, then send an invitation to that email and close the modal. if the email is not registered show the form errors without closing the modal. I've tried with different examples but can find the solution either because the examples don't handle errors or the form is not inside a modal or not using class based views
.
I'm having 2 issues with my code:
Not sure what to return in my view if the form is valid or invalid and how to handle errors in my js code to show them on the modal.(return tha form to render the errors or a JSON response??).
After the first success submission is made the form cannot be used again.(The size of the submit button changes and if you click it return a error : CSRF token missing or incorrect)
Form.py
class CollaboratorForm(forms.Form):
email_address = forms.EmailField(required=True,widget=forms.TextInput(attrs={'class': 'form-control focus-text-box', 'type': 'email',
'placeholder': 'Enter email'}))
def clean_email_address(self):
email = self.cleaned_data['email_address']
if not User.objects.filter(email=email):
raise forms.ValidationError('This user is not registered')
return email
def sendEmail(self, datas):
message = "Hello, " + datas['user_name']+" "+ datas['email_from'] + " invited you to collaborate in an existing project. Follow this link if you are interested " + datas['invitation_link']
msg = EmailMessage('Invitation from ' + datas['user_name'],
message, to=[datas['email_to']])
msg.send()
Template.html (project_detail.html)
<script src="{% static '/experiments/js/invite_collaborator.js' %}"></script>
<div class="bootstrap-modal modal fade in" id="collaboratorModal" style="display: none;">
<div class="modal-body">
<form action="{% url 'experiments:invite-collaborator' project_id=project.id %}" method="post" id=collaborator-form >
{% csrf_token %}
<div class="form-group">
{% if collaborator_form.errors %}
<ol>
{% for error in collaborator_form.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
<label class="control-label">Invite someone by email</label>
<div class="input-group mt10">
{{ collaborator_form }}
<span class="input-group-btn">
<input name="collaborator-commit" onClick="invite({{project.id}});" class="btn btn-primary" data-disable-with="Send Invitation" id="invite-button" type="submit">
</span>
</div>
</div>
</form>
</div>
</div>
Url.py
urlpatterns = [
url(r'^(?P<project_id>[0-9]+)/invite_collaborator$', views.InviteCollaborator.as_view(), name='invite-collaborator'),
]
View.py
class ProjectDetail(DetailView):
model = Project
template_name = 'experiments/project_detail.html'
pk_url_kwarg = 'project_id'
def get_context_data(self, **kwargs):
context = super(ProjectDetail, self).get_context_data()
project = get_object_or_404(Project,pk=self.kwargs["project_id"])
context["project"] = project
context["collaborator_form"] = CollaboratorForm()
return context
class InviteCollaborator(FormView):
form_class = CollaboratorForm
template_name = 'experiments/project_detail.html'
def post(self, request, *args, **kwargs):
collaborator_form = CollaboratorForm(data=request.POST)
project_id = request.POST['project_id']
current_project = Project.objects.get(id=project_id)
datas={}
if collaborator_form.is_valid():
cleaned_data = collaborator_form.cleaned_data
email_address = cleaned_data.get('email_address')
user = User.objects.get(pk=request.user.id)
invitation_link = "http://exp.innovationhackinglab.com/projects/"+ str(current_project.id) + "/join/" + current_project.invitation_key
datas['user_name'] = user.first_name + ' ' + user.last_name
datas['email_from'] = user.email
datas['email_to'] = email_address
datas['invitation_link'] = invitation_link
collaborator_form.sendEmail(datas)
data = simplejson.dumps("Success")
return HttpResponse(data, content_type='application/json')
else:
return super(InviteCollaborator, self).form_invalid(collaborator_form)
invite_collaborator.js
function invite(project_id) {
$('#collaborator-form').submit(function(e) {
e.preventDefault();
$.ajax({
data: $(this).serialize()+'&'+$.param({ 'project_id': project_id }),
type: $(this).attr('method'),
url: $(this).attr('action'),
});
$('#collaboratorModal').modal('toggle');
$('#collaboratorModal').on('hidden.bs.modal', function () {
$(this).find("input,textarea,select").val('').end();
});
});
};
I've read about using success: & error: on the js file but don't know how to use it without the appropriate "return" in the view
You need to have two ajax methods, one to get the form (as raw html) and one to post the form. You will have a corresponding get and post method in your view too.
get function of your view class:
def get(self, request, *args, **kwargs):
form = CollaboratorForm()
return render(request,'template.html',{'form':form})
def post(self, request, *args, **kwargs):
form = CollaboratorForm(request.POST)
if form.is_valid():
//save form
//return whatever you want to show on successful form submission
else:
//return bound form as html with errors
return render(request,'template.html',{'form':form})
js functions
have two seperate ajax function one for get (showing form) one for post(submitting form)
If you want to use templates on server's side, with FormView and ajax, I would suggest splitting templates into two parts - wrapper and form, load only wrapper via TemplateView, then fetch form with ajax. That allows you to send form with ajax and put responses (like form with errors) in wrapper.
Change your HTML template - take modal body's to another file, ex.:
project_detail.html
<script src="{% static '/experiments/js/invite_collaborator.js' %}"></script>
<div class="bootstrap-modal modal fade in" id="collaboratorModal" style="display: none;">
<div class="modal-body" id="collaboratorModalContent">
</div>
</div>
project_detail_content.html
<form action="{% url 'experiments:invite-collaborator' project_id=project.id %}" method="post" id=collaborator-form >
{% csrf_token %}
<div class="form-group">
{% if collaborator_form.errors %}
<ol>
{% for error in collaborator_form.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
<label class="control-label">Invite someone by email</label>
<div class="input-group mt10">
{{ collaborator_form }}
<span class="input-group-btn">
<input name="collaborator-commit" onClick="invite({{project.id}});" class="btn btn-primary" data-disable-with="Send Invitation" id="invite-button" type="submit">
</span>
</div>
</div>
</form>
FormView should handle GET and POST - first one to get the form in project_detail_content.html into modal, second for sending email. Fortunately, FormView can do all that for us! (I don't know from where you get that project variable though)
View.py
class InviteCollaborator(FormView):
form_class = CollaboratorForm
template_name = 'experiments/project_detail_content.html'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
project_id = self.request.POST['project_id']
current_project = Project.objects.get(id=project_id)
datas={}
cleaned_data = form.cleaned_data
email_address = cleaned_data.get('email_address')
user = User.objects.get(pk=request.user.id)
invitation_link = "http://exp.innovationhackinglab.com/projects/"+ str(current_project.id) + "/join/" + current_project.invitation_key
datas['user_name'] = user.first_name + ' ' + user.last_name
datas['email_from'] = user.email
datas['email_to'] = email_address
datas['invitation_link'] = invitation_link
form.sendEmail(datas)
data = simplejson.dumps("Success")
return HttpResponse(data, content_type='application/json')
Note few things - we use FormView, so for GET request it will return content of project_detail_content.html with CollaboratorForm, and on POST, same template with form and errors if form is invalid, or JSON with Success message otherwise.
What happened to project_detail.html? We will use TemplateView to create thw wrapper:
Url.py
urlpatterns = [
url(r'^invite_collaborator$', TemplateView.as_view(template_name="project_detail.html")),
url(r'^(?P<project_id>[0-9]+)/invite_collaborator/form$', views.InviteCollaborator.as_view(), name='invite-collaborator'),
]
Finally, JS
invite_collaborator.js
// In JS you need to make sure you fetch form from /project_id/invite_collaborator/form each time you show modal
$(document).ready(function(e) {
$('#collaboratorModalContent').load('invite_collaborator');
});
// Then, on submit we simply send data and handle response with success and error.
// With our current View, invalid form will generate successful response with form and error, so we need to check
function invite(project_id) {
$('#collaborator-form').submit(function(e) {
e.preventDefault();
$.ajax({
type: $(this).attr('method'),
url: $(this).attr('action'),
data: $(this).serialize()+'&'+$.param({ 'project_id': project_id }),
success: function ( response, status, xhr, dataType ) {
if( dataType === 'json' ){
//Make sure response is 'Success' and close modal
$('#collaboratorModal').modal('toggle');
$('#collaboratorModal').on('hidden.bs.modal', function () {
$(this).find("input,textarea,select").val('').end();
});
});
};
}
else {
// It's not JSON, it must be HttpResposne with forms and errors, so it goes into modal's body
$('#collaboratorModalContent').html(response)
}
}
});
I still don't know where and how you get/set you project variable, so maybe TemplateView is bad choice...
I am currently trying to learn django. I decided to create a small app. currently I am making a form to create VoteType and Voting candidates on one page. I created a page where u can add as many candidate fields as you want, but when I click the button nothing happenes and even if I don't click the button some data is saved. I was watching this django guide on youtube. This guy is making one simple form. He added method = POST and action = '' to ... and in views he used (request.POST or None). I tried to do the similar, but as my form is a bit more complicated I got really confused.
so this is my views.py code:
def create(request):
voteTypeForm = VoteTypeForm(request.POST or None)
voteForm = VoteForm(request.POST or None)
instance = voteTypeForm.save(commit=False)
instance.pub_date = timezone.now()
instance.save()
instance2 = voteForm.save(commit=False)
instance2.save()
#print instance.pub_date
context = RequestContext(request,{
'voteTypeForm': voteTypeForm,
'voteForm': voteForm,
})
return render(request, 'Vote/create.html', context)
and this is my create.html django template:
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'Vote/style.css' %}" />
<fieldset id="fieldset">
<form method = 'POST' action = ''>{%csrf_token %}
<p>{{ voteTypeForm }}</p>
</form>
<div id="placeholder">
</div>
<p>
<button type="button" name="Submit" onclick="Add();">+</button>
</p>
<input type = 'submit' value="create"/>
</fieldset>
<script type='text/javascript'>
{# document.write(code);#}
var _counter = 0;
var template = document.createTextNode('')
function appendStringAsNodes(element, html) {
var frag = document.createDocumentFragment(),
tmp = document.createElement('body'), child;
tmp.innerHTML = html;
// Append elements in a loop to a DocumentFragment, so that the browser does
// not re-render the document for each node
while (child = tmp.firstChild) {
frag.appendChild(child);
}
element.appendChild(frag); // Now, append all elements at once
frag = tmp = null;
}
function Add() {
var code = '<div id="template">' +
'<p>' +
'<fieldset id="fieldsets">' +
'<legend id="legends">Candidate No ['+ String(_counter+1) +']</legend>' +
' <form method = "POST" action = "">'+
'<input type="hidden" name="csrfmiddlewaretoken" value="{{csrf_token }}" />' +
'<p><label for="id_name">Name:</label> <input id="id_name" maxlength="50" name="name" type="text" /></p>'+
'<p><label for="id_image">Image:</label> <input id="id_image" name="image" type="file" /></p>'+
'</form>' +
' </fieldset>' +
'</p>' +
'</div>';
_counter++;
appendStringAsNodes(document.getElementById("placeholder"),code);
document.getElementById("someInput").value = _counter;
}
</script>
how do I fix this code so that my program only saves instances when I push the create button?
You still need to check that the action is a POST, and that the forms are valid, and you must redirect after a successful submission.
def create(request):
voteTypeForm = VoteTypeForm(request.POST or None)
voteForm = VoteForm(request.POST or None)
if request.method == 'POST':
# check validity separately to avoid short-cutting
vote_type_valid = voteTypeForm.is_valid()
vote_form_valid = voteForm.is_valid()
if vote_type_valid and vote_form_valid:
instance = voteTypeForm.save(commit=False)
instance.pub_date = timezone.now()
instance.save()
instance2 = voteForm.save(commit=False)
instance2.save()
return redirect('<view-you-redirect-to-on-success'>
context = RequestContext(request,{
'voteTypeForm': voteTypeForm,
'voteForm': voteForm,
})
return render(request, 'Vote/create.html', context)
The easiest way to do it is by making ajax request when you push the submit button.
Considering you have a form 'voteForm', try loading this form using django's inbuilt template as: {{voteForm.as_p}}
This will create your form for, which you have already done.
Now when you press submit button, make an ajax request with your form data in it.
The ajax request will take your data to the form and reverts back with a response which you can use to further do the processing.
A quick example for ajax request would be:
function youfunctionname()
$.ajax({
type: "POST",
url: url,
data: $("#yourformname").serialize(), // serializes the form's elements.
success: function(data)
{
alert(data);
}
});
}
I have a simple html page which renders with a number of nearly identical forms for the user to submit. Upon submit, the view is intended to add a row to the database, recreate the list of forms with slightly updated data, and send it back to the browser ('/route/complete/' maps to add_completed_route_view in urls.py).
This works perfectly the first time. Once the page has been redrawn with the new list of forms, however, the next submit will fail the request.is_ajax() test I have in the view. That causes it to skip to request.REQUEST['next'] and subsequently to home_view.
I've commented it out below, but I've also tried appending c['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' to the view but it hasn't helped.
I'm looking for help in ensuring that the headers continue to have the appropriate XMLHttpRequest param while the user submits through AJAX. Code is below, and help is much appreciated.
script.js
<script>
$(document).ready(function() {
$(".doneForm").submit(function() {
var route_id = $(this).find('input[name=route_id]').val()
var next = $(this).find('input[name=next]').val()
var reqData = {route_id:route_id,next:next}
$.ajax({
type: "post",
url: "/route/complete/",
data: reqData,
success: function(data) {
$("#routeTable").html(data);
}
});
return false;
});
});
</script>
and
template.html
<div id="routeTable">
{% for route in route_list %}
<div id="routeDone">
<form class="doneForm" action="/route/complete/" method="post">
<input type="hidden" name="route_id" value="{{ route.route_id }}" />
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
<input type="submit" value="Done" class="doneButton" />
</form>
</div>
{% endfor %}
</div>
and
views.py
def add_completed_route_view(request):
if request.method == 'POST' and request.user.is_authenticated():
add_completed_route(request)
if request.is_ajax():
wall_slug = get_wall_slug_from_route_id(request.REQUEST['route_id'])
c = get_context_for_wall_page(request, wall_slug)
# c['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
return render_to_response('m/js_route_table.html', c, context_instance=RequestContext(request))
else:
return HttpResponseRedirect(request.REQUEST['next'])
else:
return HttpResponseRedirect(reverse('home_view'))
The problem is that once the Ajax is completed, it replaces the original form with a new one - and this one no longer has the javascript event handler attached, so the next time the form submits via the normal POST method.
Luckily, jQuery has a couple of methods that handle this for you - live and delegate. So instead of $(".doneForm").submit(function() ..., do this:
$(".doneForm").live("submit", function() {...