I'm using Django and Python 3.
I have this in my HTML code:
{% for category in categories() %}
<li class="c-menu__item fs-xsmall">
<a href="#" id="next-category">
{{ category}}
</a>
</li>
<input type="hidden" value="{{ category.code }}" id="category-id">
{% endfor %}
<div class="col-xs-4" id="sub_categories">
</div>
That lists few categories.
And I have this in my script:
$( document ).on( 'click', '#next-category', function(e){
e.preventDefault();
$.ajax({
url : 'product_category/addAjax',
type : 'POST',
data : {
category: $( '#category-id').val(),
},
})
.fail(function( jqXHR, textStatus, errorThrown ){
console.log('FAIL');
})
.done(function(data){
console.log('DONE');
$('#sub_categories').prop('innerHTML',data["sub_categories"]);
});
return false;
});
When I print: $( '#category-id').val(), I always get the same value. It doesn't matter if I choose the first category listed or the last one, I will always get the same value. I have no idea what's wrong.
Gocht comment is the correct answer.
Since you want to iterate over tags they should have different id's !!!
The simple work around is to use a class and evaluate correct id:
{% for category in categories() %}
<li class="c-menu__item fs-xsmall">
<a href="#" class="next-category" value="{{ forloop.counter }}" >
{{ category}}
</a>
</li>
<input type="hidden" value="{{ category.code }}" id="category-id-{{ forloop.counter }}">
{% endfor %}
<div class="col-xs-4" id="sub_categories">
</div>
script :
$( document ).on( 'click', '.next-category', function(e){
e.preventDefault();
var id = $(this).attr("value");
var input_id = "#category-id-" + id;
$.ajax({
url : 'product_category/addAjax',
type : 'POST',
data : {
category: $(input_id).val(),
},
})
.fail(function( jqXHR, textStatus, errorThrown ){
console.log('FAIL');
})
.done(function(data){
console.log('DONE');
$('#sub_categories').prop('innerHTML',data["sub_categories"]);
});
return false;
});
Related
I have a lot of forms on the page and when one of them is submitted I want to send request via ajax to the view and have an id of the article and other info. So I need to check if form that has been clicked is the same as event.target. I did something like this but don't know if it is correct(first console.log works but second not):
<div id = "list">
{% for article in news %}
<h1>{{ article.title }}</h1>
<p>{{ article.published }}</p>
<img src = "{{ article.url }}">
<p>
<button>Upvote</button>
<button>Downvote</button>
</p>
<div id="span">
{% with article.upvotes.count as total_upvotes and article.downvotes.count as total_downvotes %}
<span upvote-id = "{{ article.id }}">{{ total_upvotes }}</span><span> upvote{{ total_votes|pluralize}}</span>
<span downvote-id = "{{ article.id }}">{{ total_downvotes }}</span><span> downvote{{ total_votes|pluralize}}</span>
{% endwith %}
</div>
<form method = 'post' action = '{% url "news:news_list" %}' form-id = '{{ article.id }}' class="form">
{{ form.as_p }}
{% csrf_token %}
<input type = "submit" value = "post">
</form>
{% endfor %}
</div>
{% endblock %}
{% block domready %}
const
list = document.getElementById('list'),
items = document.getElementsByClassName('vote');
forms = document.getElementsByClassName('form');
list.addEventListener('click', voteFunc);
list.addEventListener('submit', commentFunc);
function commentFunc(event){
event.preventDefault();
const clickedForm = event.target;
console.log('event triggered');
for (let form in forms){
if (form == clickedForm){
console.log('form is event.target')
$.ajax({
url: '{% url "news:news_list" %}',
type: 'POST',
data: {'id':$(event.target).attr('form-id'), 'title':$(this).elemets['title_field'].text(), 'body':$(this).elemets['body_field'].text()},
dataType: 'json'
})
}
}
}
Hope to hear advice how to implement it better and what event.target contains
You can write event handler for form submit event .So, whenever submit button(post) is clicked this event will get called then use .serialize() method to get all inputs inside your form and also attach form-id using &name=value and then you can pass same to backend.
Demo Code :
//when form will get submit
$("form.form").submit(function(e) {
//serialize will get all inputs as name=value separted wth `& `
console.log("data to send --> " + $(this).serialize() + "&id=" + $(this).attr('form-id'))
$.ajax({
type: "POST",
url: '{% url "news:news_list" %}',
data: $(this).serialize() + "&id=" + $(this).attr('form-id'), //send same
dataType: 'json'
});
e.preventDefault();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="list">
<a href="{{ article.resource }}">
<h1>A1</h1>
</a>
<p>abcd..</p>
<img src="{{ article.url }}">
<p>
<button>Upvote</button>
<button>Downvote</button>
</p>
<div id="span">
<span upvote-id="1">23</span><span> 54</span>
<span downvote-id="1">2</span><span> 56</span>
</div>
<form method='post' action='{% url "news:news_list" %}' form-id='1' class="form">
<p><label>somehting:</label>
<input type="text" name="something"></p>
<input type="submit" value="post">
</form>
<a href="{{ article.resource }}">
<h1>A</h1>
</a>
<p>abcd..</p>
<img src="{{ article.url }}">
<p>
<button>Upvote</button>
<button>Downvote</button>
</p>
<div id="span">
<span upvote-id="2">23</span><span> 54</span>
<span downvote-id="2">2</span><span> 56</span>
</div>
<form method='post' action='{% url "news:news_list" %}' form-id='2' class="form">
<p><label>somehting:</label>
<input type="text" name="something"></p>
<input type="submit" value="post">
</form>
</div>
i am working on a project using Django. There are lists of users posts in homepage and each post has a comment form. I was able to implement comment properly on views, but the issue now is when I submit a comment it display empty string instead of the comment, the comment display in chrome console. How do i display comment on each post by user when a form is submitted. I attached an image to my questioin to clarify my question.
home.html
<div id="newfeeds-form">
{% include 'ajax_newfeeds_comments.html' %}
</div>
ajax_newfeeds_comments.html
<!-- New Feeds comment Text -->
{% for post in all_images %}
<div class="container newfeeds-comment" id="display-comment">
{% for comment in post.comments_set %}
<div class="row">
<div class="col-1 col-md-1 col-lg-1">
{% if comment.user.profile.profile_pic %}
<img src="{{ comment.user.profile.profile_pic.url }}" class="d-flex rounded-circle" alt="image" height="28" width="28">
{% endif %}
</div>
<div class="col-10 col-md-10 col-lg-10 p-2 ml-1" id="user-commentpost">
<span class="comment-post truncate">
<span class="name text-lowercase">{{ comment.user }}</span>
{{ comment.comment_post }}</span>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
<span class="md-form">
<form enctype="multipart/form-data" class="feeds-form form-inline md-form form-sm" method="POST" action="{% url 'site:home' %}" id="newfeeds-form{{ post.id }}">
{% csrf_token %}
<input type="hidden" value={{post.id}} name="post_comment">
<img src="{{ request.user.profile.profile_pic.url }}" class="rounded-circle avatar-img" height="28" width="28">
<textarea name="comment_post" class="textinput textInput animated fadeIn" placeholder="Add a comment..." required="" id="id_comment_post{{ post.id }}" onkeyup=""></textarea>
<button type="submit" class="submit" id="submit1-{{post.id}}"><i class="fas fa-paper-plane"></i></button>
</form
</span>
Views:
def home_view(request):
#All posts in new feed
all_images = Post.objects.filter(
Q(poster_profile=request.user, active=True)|
Q(poster_profile__from_user__to_user=request.user, active=True)|
Q(poster_profile__to_user__from_user=request.user, active=True)|
Q(poster_profile__profile__friends__user=request.user, active=True)).distinct().exclude(
Q(hide_post=request.user, active=True)|
Q(poster_profile__profile__blocked_users__user=request.user, active=True))
#Comment form homepage
if request.method == 'POST':
post_id = request.POST.get("post_comment")
post_obj = Post.objects.get(pk=post_id)
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.user = request.user
comment.commented_image = post_obj
comment.save()
# messages.info(request,'You submitted a comment')
#return redirect('/')
else:
form = CommentForm()
context = {
'form': form,
'all_images': all_images,
}
if request.is_ajax():
html = render_to_string('ajax_newfeeds_comments.html', context, request=request)
return JsonResponse({'form': html})
return render(request,'home.html', context)
Ajax:
<script type="text/javascript">
//HomeFeeds Comment
$(document).ready(function() {
$('.feeds-form').on('submit', onSubmitFeedsForm);
$('.feeds-form .textinput').on({
'keyup': onKeyUpTextInput,
'change': onKeyUpTextInput
});
function onKeyUpTextInput(event) {
var textInput = $(event.target);
textInput.parent().find('.submit').attr('disabled', textInput.val() == '');
}
function onSubmitFeedsForm(event) {
event.preventDefault();
console.log($(this).serialize());
var form = $(event.target);
var textInput = form.find('.textinput');
var hiddenField = form.find('input[name="post_comment"]');
$.ajax({
type: 'POST',
url: "{% url 'site:home' %}",
data: form.serialize(),
dataType: 'json',
beforeSend: function() {
form.find('.submit').attr('disabled', true);
},
success: function(response) {
$('#newfeeds-form' + hiddenField.val()).html(response.form);
textInput.val('');
var numberOfCommentsElement = $('#number-of-comments');
numberOfCommentsElement.text(parseInt(numberOfCommentsElement.text()) + 1);
},
error: function(rs, e) {
console.log(rs.resopnseText);
},
complete: function() {
textInput.trigger('change');
}
});
}
});
</script>
You don't need ajax actually, you can simply:
let value = $('myInput').val();
$('myCommentContainer').prepend(`
Format the comment as you want ${value}
`)
$('myInput').val('') // To empty the value
now call the ajax normally:
$({
type: 'POST',
url: "{% url 'site:home' %}",
data: form.serialize(),
dataType: 'json',
beforeSend: function() {
form.find('.submit').attr('disabled', true);
},
success: function(response) {}
})
Done, leave the success empty
appending it within the ajax success will make it slower anyway!
I have a button (is anchor tag with class vote) which should be clicked to vote for an article via ajax request. After that I want to update the votes count in my blade view (its a laravel application). The div with the class points should be updated but I dont know how to bind points on click to the ajax call?
I want to bind the .point to ajax call like I did it with $button to then update the div with the class points.
<a data-id="{{ $article->id }}" class="btn vote {{ Auth::check() && Auth::user()->votedFor($article) ? 'btn-success' : '' }}"></a>
Main code:
<div data-id="{{ $article->id }}" class="points">{{ $article->votes->count() }}</div>
$(document).on('click','.vote',function(){
var $counter = $(this).next();
var $button = $(this);
var id = $button.data('id');
var token = $('meta[name="csrf-token"]').attr('content');
$.ajax({
type:'POST',
url:"{!! URL::to('article/vote/') !!}/" + id,
dataType: 'JSON',
data: {
"_method": 'POST',
"_token": token,
"id": id,
},
success:function(data){
$counter.html(data.count);
var color = data.voted ? '#bbb' : '#38c172';
$button.css('background-color', color);
console.log('success');
console.log(data);
},
error:function(xhr){
if (xhr.status == 401) {
window.location.href = "{!! URL::to('login') !!}";
} else if (xhr.status == 403) {
window.location.href = "{!! URL::to('email/verify') !!}";
}
},
});
});
So you want your .points to be updated and not the a button you clicked.
First, make sure your a and .points are children of the same div element and there like:
<div>
<a data-id="{{ $article->id }}" class="btn vote {{ Auth::check() && Auth::user()->votedFor($article) ? 'btn-success' : '' }}">
button
</a>
<div data-id="{{ $article->id }}" class="points">
{{ $article->votes->count() }}
</div>
</div>
...
<div>
<a data-id="{{ $article->id }}" class="btn vote {{ Auth::check() && Auth::user()->votedFor($article) ? 'btn-success' : '' }}">
button
</a>
<div data-id="{{ $article->id }}" class="points">
{{ $article->votes->count() }}
</div>
</div>
Then in your JavaScript define the counter element like
var $counter = $(this).parent().find('points');
and update your success: method to apply CSS class and put data count:
$counter.html(data.count);
var color = data.voted ? '#bbb' : '#38c172';
$counter.css('background-color', color);
Let me know if it makes sense and you can finish the implementation.
I am building a page in a Django project which has multiple comments each of which can be liked/unliked with a button next to the text. So the page has multiple like/unlike buttons.
The buttons display fine when the page is loaded, and I can use Ajax to send data to Django and update my database which works fine, and I can return data back to the Ajax success function.
What I can't work out is - how can I update the status of the actual button which was clicked. I am able to update the status of all of the buttons together on the page as per the code below (pointless I know!), but can't see how I reference the clicked button. I've tried passing and then returning the button id which I can display in an alert, but not sure if this is what I should be using or where I go from here?
HTML Template
{% for comments in comments_page %}
<p>
<b>{{ comments.created_at }} ({{ comments.user_type }})</b>
{% if comments.comment_liked is False %}
<button class="comment btn btn-primary btn-xs"
id={{ forloop.counter0 }}
data-surveyid="{{ comments.id }}"
data-commentliked="True"
type="button">
<span class="glyphicon glyphicon-star-empty"></span>
</button>
{% else %}
<button class="comment btn btn-success btn-xs"
id={{ forloop.counter0 }}
data-surveyid="{{ comments.id }}"
data-commentliked="False"
type="button">
<span class="glyphicon glyphicon-star"></span>
</button>
{% endif %}
</p>
<p>{{ comments.comments }}</p>
<br>
{% endfor %}
Javascript / Ajax
{% block javascript %}
<script type="text/javascript">
$(function() {
$('.comment').click(function() {
var surveyid, commentliked, buttonid;
surveyid = $(this).attr('data-surveyid');
commentliked = $(this).attr('data-commentliked');
buttonid = $(this).attr('id');
$.ajax({
url: '/evaluations/validate_username/',
data: {
'surveyid': surveyid,
'commentliked': commentliked,
'buttonid': buttonid
},
dataType: 'json',
type: 'get',
success: function (data) {
alert(data.buttonid);
$(".comment").removeClass('comment btn btn-primary btn-xs').addClass('comment btn btn-success btn-xs');
}
});
});
});
</script>
{% endblock %}
Just target the clicked button in your success function:
{% block javascript %}
<script type="text/javascript">
$(function() {
$('.comment').click(function() {
// the button instance that was clicked
var clickedBtn = $(this);
var surveyid, commentliked, buttonid;
// also, you can use data-* to get the data attributes
// surveyid = clickedBtn.attr('data-surveyid');
// commentliked = clickedBtn.attr('data-commentliked');
surveyid = clickedBtn.data('surveyid');
commentliked = clickedBtn.data('commentliked');
buttonid = clickedBtn.attr('id');
$.ajax({
url: '/evaluations/validate_username/',
data: {
'surveyid': surveyid,
'commentliked': commentliked,
'buttonid': buttonid
},
dataType: 'json',
type: 'get',
success: function (data) {
alert(data.buttonid);
clickedBtn.removeClass('comment btn btn-primary btn-xs')
.addClass('comment btn btn-success btn-xs');
}
});
});
});
</script>
{% endblock %}
Not very good with anything javascript, jquery. I am trying to return results from solr and run it through the typehead and have a dropdown list in a google or bing type fashion. Iv'e been kinda messing around with it but I'm deadlocked. I created a drop down list but it doesn't look nice. Heres my code
views.py
def search_title(request):
posts = SearchQuerySet().models(Post).autocomplete(content_auto=request.GET.get('search_text', ''))
context = {
"posts": posts
}
# context.update(csrf(request))
return render(request, "posts/ajax_search.html", {"posts": posts})
posts/urls.py
urlpatterns = [
url(r'^$', post_list, name='list'),
......
url(r'^search_f/$', search_title),
....
]
ajax_search.html
{% if posts.count > 0 %}
{% for post in posts %}
<div>{{ post.title }}</div>
{% endfor %}
{% else %}
<li class="list-group-item"> None to show</li>
{% endif %}
snippet of nav.html
<form method="GET" action="{% url 'posts:search-page' %}" class="navbar-form navbar-right" role="search">
<div>
<div class="input-group">
<input type="text" class="form-control" autocomplete="off" name="q" id="search" placeholder="search" value="{{ request.GET.q }}">
<span class="input-group-btn">
<button type="submit" class="btn btn-default">search</button>
</span>
</div><!-- /input-group -->
<div class="list-group" id="search-results" style="margin: 5px 0 0 0; width: 172px">
</div>
</div><!-- /.col-lg-6 -->
</form>
ajax.js
$(function(){
$('#search').keyup(function() {
$.ajax({
type: "GET",
url: "/posts/search_f/",
data: {
'search_text': $('#search').val(),
'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken]").val()
},
success: searchSuccess,
dataType: 'html'
});
});
});
function searchSuccess(data, textStatus, jqXHR)
{
$('#search-results').html(data);
}
$('#search-results').typeahead({
name: 'user-search',
remote: '/posts/search_f/%QUERY' // you can change anything but %QUERY
});
I also need it to to be done so I won't get an error like this
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience.
I recently spent hours trying to resolve this on google chrome only to have it resolove itself
EDIT
I did some research and even though it didn't work I feel like I'm on the right track
$(function() {
$("#search").typeahead({
source:function(query,process) {
$.ajax({
url:'posts/search_f',
type:'GET',
data: {
'search_text': $('#search').val(),
'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken]").val()
},
//dataType: 'JSON',
async: true,
success: function(data) {
console.log(data)
}
})
}
})
});