Form data not being sent to the server - javascript

I have a form that pops up in a modal when the user clicks a button in the search results of a query. This form has three input fields and a few other fields that are being appended to it once the submit button is being clicked using ajax. As this is apart of a Django app, I am catching the values in the view on the server-side. I'm successfully able to get the data from the input fields of the form, but I'm not able to get the data from the appended fields.
I'm fairly new to using ajax so its likely that I'm doing something wrong but it seems like the data should be getting sent to the server. What could be the problem?
Here is the code for the ajax call and the modal form:
<script type="text/javascript">
$("#mform").submit(function(){
var c = getCookie('csrftoken');
//var data1 = $().attr("");
var extraData = [];
extraData['venue'] = $("#invite").data("venue");
extraData['artist'] = $("#invite").data("artist");
extraData['f_date'] = $("#invite").data("formatted_date");
extraData['uf_date'] = $("#invite").data("date");
extraData['ticket_url'] = $("#invite").data("ticket_url");
extraData['city'] = $("#invite").data("city");
extraData['region'] = $("#invite").data("region");
extraData['artist'] = $("#invite").data("artist");
var PostData = {csrfmiddlewaretoken: c, additionalValues:extraData}
$ajax({
//context:this,
type : 'POST',
dataType: 'json',
url: '/artistsearch/',
data: JSON.stringify(PostData),
success: function(response){}
});
});
EDIT:
HTML containing data to be sent
<ul class= 'list-group'>
{% for ticket in data %}
<li class = 'list-group-item' >
Title: {{ticket.title}}
Location: {{ticket.formatted_location}}
Venue: {{ticket.venue.name}}
Date: {{ticket.formatted_datetime}}
tickets status: {{ticket.ticket_status}}<br>
<a href = {{ticket.ticket_url}}> ticket url</a>
{% if user.is_authenticated %}
<button id = 'invite' type='button' class= 'btn btn-info btn-lg' data-toggle = 'modal' data-target='#myModal' data-artist = {{ticket.artists.name}} data-venue={{ticket.venue.name}} data-date = {{ticket.datetime}} data-formatted_date = {{ticket.formatted_datetime}} data-city= {{ticket.venue.city}} data-region = {{ticket.venue.region}} data-ticket_url={{ticket.ticket_url}} > Invite a friend </button>
<button id = 'save' type = 'button' class = 'btn btn-primary-outline'> Save Concert </button>
{% endif %}
</li>
{% endfor %}
</ul>

You have missed the # selector for id invite of button it should be like $("#invite"). Use attribute like data-artist instead of just artist and get it like $("#invite").data("artist) or $("#invite").attr("data-artist).
And then post it like ....
var postData = {
csrfmiddlewaretoken: c,
additionalValues: extraData
}
Then post data like
$.ajax({
type: 'post',
url: 'URL here',
data:JSON.stringify(PostData),
// .......
// Other code here
)};

Related

I want to add product in cart without refreshing page with AJAX and Django

Nothing will ne happened when I submit product in the the cart. I want to use AJAX without refreshing page.
When I submit the console message will be displayed.
I'm trying to use AJAX first.
Trying to add product in the cart without refreshing page.
I need help please :)
Views Django
def add_cart(request, product_id):
cart = Cart(request)
product = get_object_or_404(Product, id=product_id)
form = CartProductForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
cart.add(product=product,
quantity=cd['quantity'],
update_quantity=cd['update_qt']
)
return JsonResponse({'status': 'success'})
Form
from django import forms
from django.core.validators import MinValueValidator, MaxValueValidator
class CartProductForm(forms.Form):
quantity = forms.IntegerField(initial=1)
update_qt = forms.BooleanField(required=False, initial=False, widget=forms.HiddenInput)
HTML Code
<form action="{% url "..." %}" method="post" data-id="{{ ... }}" class="form-order" id="form">
{{ cart_product_form }}
{% csrf_token %}
<a data-id="{{ ... }}" class="buy-product"><button>BUY</button></a>
</form>
JS Code
$(".buy-product").on('click', function(e){
e.preventDefault();
var product_id = $(this).attr('data-id')
var quantity = 1
console.log(product_id)
console.log(quantity)
data = {
'product_id': product_id,
'quantity': quantity
}
var point='/cart/add/'+product_id+'/'
$.ajax({
headers:{
'Content-Type':'application/json',
'X-CSRFToken':csrftoken,
},
url: point,
type: 'POST',
data: data,
success: function(data){
console.log('success')
console.log(csrftoken)
}
})
})
You need to add csrftoken in data: {csrfmiddlewaretoken':csrftoken}. Also I don't see when you initialize your variables, but I think is just example. Check this answer for more: link
You can prevent form from refreshig the page and then do whatever you need with your JS code:
<form action="{% url "..." %}" method="post" data-id="{{ ... }}" class="form-order" id="form" onsubmit="myFunction(event)">
...
</form>
<script>
function myFunction(event){
event.preventDefault();
}
</script>

Building a like post in flask using ajax and jquery fails

I am building a simple flask blog and there I am trying to implement like functionality using ajax and jquery. It works without ajax but the page reloads. So I need to use the ajax but when I am using ajax then I got my site redirected to the JSON file which is not expected. Please Help me with this. The code is
<div class="likers" id = 'result{{ slide.id }}'>
{% if current_user.has_liked_slide(slide) %}
<a class="unlike" id="unlike_{{slide.id}}" href="{{ url_for('like_action', slide_id=slide.id, action='unlike') }}">unlike</a>
{% else %}
<a class="like" id="like_{{slide.id}}" href="{{ url_for('like_action', slide_id=slide.id, action='like') }}">like</a>
{% endif %}
<div id = 'like-count'>
{{ slide.likes | count }}
</div>
</div>
#app.route('/like/<int:slide_id>/<action>', methods = ['GET', 'POST'])
#login_required
def like_action(slide_id, action):
slide = Slide.query.filter_by(id=slide_id).first_or_404()
if action == 'like':
current_user.like_slide(slide)
db.session.commit()
return jsonify({'slide_id': slide_id, 'action': action})
if action == 'unlike':
current_user.unlike_slide(slide)
db.session.commit()
return jsonify({'slide_id': slide_id, 'action': action})
$(document).ready(function(event) {
$('.like, .unlike').click(function(){
var id = this.id;
var split_id = id.split('_');
var text = split_id[0];
var slide_id = split_id[1];
$.ajax({
url: '/like/<int:slide_id>/<action>',
type: 'post',
data : {slide_id:slide_id, action:text},
dataType:'html',
success: function(data){
$("like_" + slide_id).html(data);
$('unlikes_' + slide_id).html(data);
}
});
});
});

How to serialize correctly? Ajax updates all instances of a django upvote button in a object forloop when pressed

OK so I have an index page with items that can be up or downvoted.
The issue is that when I upvote/downvote one item, all items on the page are upvoted/downvoted and the appearance of all buttons on the page all change instead of just the one object that was upvoted/downvoted.
Can anyone help me serialize each for loop object correctly?
my index page:
{% for post in posts %}
<span id="post_{{forloop.counter}}" data-value="{{post.id}}"></span>
<button class="vote_action" value="upvote_button"> + </i></button>
<span id="votes_{{forloop.counter}}">{{post.points}}</span>
<button class="vote_action" value="downvote_button"> - </button>
{% endfor %}
...
<script type="text/javascript">
// JQUERY - AJAX SCRIPT FOR voting
$(document).ready(function(){
{% for post in posts %}
$('.vote_action').click(function(e) {
var postid = document.getElementById('post_{{forloop.counter}}').getAttribute('data-value');
var button = $(this).attr("value");
e.preventDefault();
$.ajax({
type: 'POST',
url: '{% url "vote" %}',
data: {
postid: postid,
csrfmiddlewaretoken: '{{ csrf_token }}',
action: 'postvote',
button: button,
},
success: function(json){
if (json.length < 1 || json == undefined) {
//empty
}
document.getElementById("votes_{{forloop.counter}}").innerHTML = json['result']
//change button looks
$("#uvb_{{forloop.counter}}").addClass("disabled");
$("#dvb_{{forloop.counter}}").addClass("disabled");
},
error: function(xhr, errmsg, err) {}
})
})
{% endfor %}
})
</script>
My views function:
#login_required
def post_vote(request):
if request.POST.get('action') == 'postvote':
# get information from request about what item id it is
id = int(request.POST.get('postid'))
# And also which button was pressed
button = request.POST.get('button')
post = Posts.objects.get(id=id)
if button == 'downvote_button':
if not post.voters.filter(id=request.user.id).exists():
post.voters.add(request.user)
post.votes +=1
post.points -=2
post.save()
elif button == 'upvote_button':
if not post.voters.filter(id=request.user.id).exists():
post.voters.add(request.user)
post.votes +=1
post.points +=2
post.save()
# return result
post.refresh_from_db()
result = post.points
return JsonResponse({'result':result})
pass
Instead of using for-loop for script you can simply use closest() and find() method of jquery to achieve same .Here are some change you need to make in your django code :
{% for post in posts %}
<div> //<!--add this div-->
<span id="post_{{forloop.counter}}" data-value="{{post.id}}"></span>
<button class="vote_action" value="upvote_button"> + </i></button>
//<!--add class here-->
<span id="votes_{{forloop.counter}}" class="votes_points">{{post.points}}</span>
<button class="vote_action" value="downvote_button"> - </button>
</div>
{% endfor %}
Then , in your jquery code whenever your button is clicked use closest() method to get the closest div then using this find the span where class="votes_points" and get its id and use split method to get the {{forloop.counter}} value.Using this we can easily get postid value also . So,your jquery code will look like below :
$('.vote_action').click(function(e) {
//get closest div
var selector = $(this).closest('div');
var button = $(this).attr("value");
//find class get id and split to get counter
var counter =selector.find('.votes_points').attr('id').split('_')
//get span data-value
var postid = selector.find("span[id=post_"+counter[1]+"]").attr('data-value');
console.log("postID-->"+postid+"Button-->"+button+"counter[1]-->"+counter[1])
e.preventDefault();
//your ajax
$.ajax({
type: 'POST',
url: '{% url "vote" %}',
data: {
postid: postid,
csrfmiddlewaretoken: '{{ csrf_token }}',
action: 'postvote',
button: button
},
success: function(json) {
if (json.length < 1 || json == undefined) {
//empty
}
//add response to votes_point
selector.find('.votes_points').text(json['result'])
//change button looks
$("#uvb_"+counter[1]).addClass("disabled");
$("#dvb_"+counter[1]).addClass("disabled");
},
error: function(xhr, errmsg, err) {}
})
})
Demo Code(with demo datas) :
$('.vote_action').click(function(e) {
//get closest div
var selector = $(this).closest('div');
var button = $(this).attr("value");
//find class get id and split to get counter
var counter =selector.find('.votes_points').attr('id').split('_')
//get span data-value
var postid = selector.find("span[id=post_"+counter[1]+"]").attr('data-value');
console.log("postID-->"+postid+" || Button-->"+button+" || counter[1]-->"+counter[1])
e.preventDefault();
//your ajax
$.ajax({
type: 'POST',
url: '{% url "vote" %}',
data: {
postid: postid,
csrfmiddlewaretoken: '{{ csrf_token }}',
action: 'postvote',
button: button
},
success: function(json) {
if (json.length < 1 || json == undefined) {
//empty
}
//add response to votes_point
selector.find('.votes_points').text(json['result'])
//change button looks
$("#uvb_"+counter[1]).addClass("disabled");
$("#dvb_"+counter[1]).addClass("disabled");
},
error: function(xhr, errmsg, err) {}
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<span id="post_1" data-value="1"></span>
<button class="vote_action" value="upvote_button"> +</button>
<span id="votes_1" class="votes_points">15</span>
<button class="vote_action" value="downvote_button"> - </button>
</div>
<div>
<span id="post_2" data-value="2"></span>
<button class="vote_action" value="upvote_button"> +</button>
<span id="votes_2" class="votes_points">52</span>
<button class="vote_action" value="downvote_button"> - </button>
</div>
<div>
<span id="post_3" data-value="3"></span>
<button class="vote_action" value="upvote_button"> +</button>
<span id="votes_3" class="votes_points">52</span>
<button class="vote_action" value="downvote_button"> - </button>
</div>
After the support given by #swati, I was able to get this working correctly as demonstrated below for anyone else having trouble with a similar issue.
All credit goes to #swati
HTML portion of the page:
{% for post in posts %}
<div class="eachpost"> //<!--add this div-->
<span id="post_{{forloop.counter}}" data-value="{{post.id}}"></span>
<button class="vote_action" value="upvote_button" id="uvb_{{forloop.counter}}"> + </i></button>
//<!--add class here-->
<span id="votes_{{forloop.counter}}" class="votes_points">{{post.points}}</span>
<button class="vote_action" value="downvote_button" id="dvb_{{forloop.counter}}"> - </button>
</div>
{% endfor %}
The JS/AJAX Section of the page
$('.vote_action').click(function(e) {
//get closest div
var selector = $(this).closest('div.eachpost');
var button = $(this).attr("value");
//find class get id and split to get counter
var counter =selector.find('.votes_points').attr('id').split('_')
//get span data-value
var postid = selector.find("span[id=post_"+counter[1]+"]").attr('data-value');
console.log("postID-->"+postid+"Button-->"+button+"counter[1]-->"+counter[1])
e.preventDefault();
//your ajax
$.ajax({
type: 'POST',
url: '{% url "vote" %}',
data: {
postid: postid,
csrfmiddlewaretoken: '{{ csrf_token }}',
action: 'postvote',
button: button
},
success: function(json) {
if (json.length < 1 || json == undefined) {
//empty
}
//add response to votes_point
$("#votes_"+counter[1]).text(json['result']);
//change button looks
$("#uvb_"+counter[1]).addClass("disabled");
$("#dvb_"+counter[1]).addClass("disabled");
},
error: function(xhr, errmsg, err) {}
})
})

My AJAX is working and I want to know why

In my app I made a favorite list that a user can populate using AJAX.
Is it working perfectly but I am not sure if I did it the right way and I would like to know how to do it the proper way. Or maybe somehow I did it right.
My html:
<div class='sub_button'>
<form class="add_btn" method='post'>{% csrf_token %}
<button class='added btn' value= '{{product.id }} {{ sub_product.id }}' ><i class=' fas fa-save'></i></button>
</div>
My AJAX:
$(".row").on('click', ".added", function(event) {
let addedBtn = $(this);
console.log(addedBtn)
event.preventDefault();
var product = $(this).val();
var url = '/finder/add/';
$.ajax({
url: url,
type: "POST",
data:{
'product': product,
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val()
},
datatype:'json',
success: function(data) {
if (data['success'])
addedBtn.hide();
}
});
});
My views.py
def add(request):
data = {'success': False}
if request.method=='POST':
product = request.POST.get('product')
user = request.user
splitted = product.split(' ')
sub_product = Product.objects.get(pk=(splitted[1]))
original_product = Product.objects.get(pk=(splitted[0]))
p = SavedProduct(username= user, sub_product=sub_product, original_product = original_product)
p.save()
data['success'] = True
return JsonResponse(data)
What is bugging me is the way I passed '{{product.id }} {{ sub_product.id }}'. Because I've made it after some tinkering.
There is a better way to do this.
ie, if you have only one product.id and sub_product.id in this page instance. Then in a script tag at the end of the HTML template for this page you add the following:
<script>
var product_id = {{ product.id }}
var sub_product_id = {{ sub_product.id }}
</script>
Then you can link the external JS file in which you have AJAX to this HTML template with another script tag.
Now your product_id and sub_product_id will be available in your external JS script file in which you have the AJAX code.
So that way, you don't have to pass it through the value attribute of the button tag and things look more clean.

How to display the name that matches the ID without refreshing/submitting the form in Django?

I am trying to display a User's name on top of a box where they enter their Employee # in a form, without having to refresh the page.
For example, they enter their # and then after they click/tab onto the next field, it renders their name on top, which comes from the database, so the user knows they've entered the correct info. This name is stored in a separate model, so I try to retrieve it using the "id/number".
I am not too familiar with AJAX but after reading a few similar questions it seems like an AJAX request would be the most appropriate way to achieve this. I tried to make a function get_employee_name that returns the name of the person based on the way I saw another ajax request worked, but I'm not sure how to implement this so it displays after the # is entered.
My page currently loads, but there is never a call to the function/url that searches for the name to display it on the page (because there isn't one). I'm not sure where I might be missing the part that connects these two areas of the code or how to connect these, as I am not too familiar with html and Django, most of this has been trial and error.
models.py
class EmployeeWorkAreaLog(TimeStampedModel, SoftDeleteModel, models.Model):
employee_number = models.ForeignKey(Salesman, on_delete=models.SET_NULL, help_text="Employee #", null=True, blank=False)
work_area = models.ForeignKey(WorkArea, on_delete=models.SET_NULL, null=True, blank=False)
station_number = models.ForeignKey(StationNumber, on_delete=models.SET_NULL, null=True, blank=True)
This is the model where the name is stored
alldata/models.py
class Salesman(models.Model):
slsmn_name = models.CharField(max_length=25)
id = models.IntegerField(db_column='number', primary_key=True)
I was reading I can add to the "attrs" in the widget an 'onchange' part, but I am not too familiar with how to approach this and tying it to the ajax request from forms and not the html.
forms.py
class WarehouseForm(AppsModelForm):
class Meta:
model = EmployeeWorkAreaLog
widgets = {
'employee_number': ForeignKeyRawIdWidget(EmployeeWorkAreaLog._meta.get_field('employee_number').remote_field, site, attrs={'id':'employee_number_field'}),
}
fields = ('employee_number', 'work_area', 'station_number')
views.py
def enter_exit_area(request):
form = WarehouseForm(request.POST or None)
if form.is_valid():
# Submission stuff/rules
return render(request, "operations/enter_exit_area.html", {
'form': form,
})
def get_employee_name(request):
employee_number = request.GET.get('employee_number')
try:
employee = Salesman.objects.get(id=employee_number)
except Salesman.DoesNotExist:
return JsonResponse({'error': 'Employee not found'}, status=404)
employee_name = employee.slsmn_name
return JsonResponse({'employee_name': employee_name})
urls.py
urlpatterns = [
url(r'enter-exit-area/$', EnterExitArea.as_view(), name='enter_exit_area'),
path('get-employee-name/', views.get_employee_name, name='get_employee_name'),
]
The ajax request I tried to create is at the end of this html. I modified a similar request I found, but it does not actually display anything on the screen, not sure if I'm missing an area where the request is actually never being called, as I am not too familiar with how these types of requests work.
enter_exit_area.html
{% extends "base.html" %}
{% block main %}
<form id="warehouseForm" action="" method="POST" novalidate >
{% csrf_token %}
<div>
<div>
<!-- Here is where I would want the name to render after the user enters their number and tabs out -->
{{ form.employee_number.help_text }}
{{ form.employee_number }}
</div>
<div>
{{ form.work_area.help_text }}
{{ form.work_area }}
</div>
</div>
<div>
<div>
<button type="submit" name="enter_area" value="Enter">Enter Area</button>
</div>
</div>
</form>
<script>
$("#id_employee_number").change(function () {
var employee_number = $(this).val();
var url = $("#warehouseForm").data("employee-name");
$.ajax({
url: url,
type:'GET',
data: {
'id': employee_number
},
success: function (data) {
var employee_name = data['employee_name'];
$('#employee_name').text(employee_name);
},
error : function (data) {
var error_message = data['error'];
$('#employee_name').text(error_message);
}
});
});
</script>
{% endblock main %}
How can I call the function from the HTML? Could I do it in such a way that when the user enters 6 numbers it checks? (All employee numbers are 6 digits)
The url has to be the endpoint url which you defined in your url.py file
<script>
$("#id_employee_number").change(function (e) {
e.preventDefault();
var employee_number = $(this).val();
var url = $("#warehouseForm").data("employee-name");
$.ajax({
url: "/get_employee_name", // Here
type:'GET',
data: {
'id': employee_number
},
success: function (data) {
var employee_name = data['employee_name'];
$('#employee_name').text(employee_name);
},
error : function (data) {
var error_message = data['error'];
$('#employee_name').text(error_message);
}
});
});
</script>
You can append to your GET request a url parameter like: /get-employee-name/<your employee number here>
I recommend taking a look at URL Dispatcher to create url parameters within your django url definitions
I also recommend using underscores NOT dashes in your url definitions.
So a pseudo working config would be
urls.py
urlpatterns = [
url(r'enter-exit-area/$', EnterExitArea.as_view(), name='enter_exit_area'),
path('get_employee_name/<int:employeeNum>', views.get_employee_name, name='get_employee_name'),
]
views.py
def get_employee_name(request, employeeNum): #You get the employeeNum variable from urls.py
try:
employee = Salesman.objects.get(id=employee_number)
except Salesman.DoesNotExist:
return JsonResponse({'error': 'Employee not found'}, status=404)
employee_name = employee.slsmn_name
return JsonResponse({'employee_name': employee_name})
script
<script>
$("#id_employee_number").change(function () {
var employee_number = $(this).val();
var employeeNum = $("#warehouseForm").data("employee-name");
$.ajax({
url: `/get_employee_name/${employeeNum}`,
type:'GET',
success: function (data) {
var employee_name = data['employee_name'];
$('#employee_name').text(employee_name);
},
error : function (data) {
var error_message = data['error'];
$('#employee_name').text(error_message);
}
});
});
</script>

Categories