I have a follow/unfollow button. Currently my Jquery is working on the first submit but when I toggle the button again, the Jquery doesn't change any of the elements.
html
{% for user in followers %}
<div id="flist-{{ user.profile.pk }}">
<article >
<a href="{% url 'user-posts' user %}">
<img src="{{ user.profile.image.url }}"></a>
<div >
{% if user.profile in following %}
<div >
<form method="POST" action="{% url 'remove-follower-js' user.profile.pk %}" id="{{ user.profile.pk }}">
{% csrf_token %}
<button type="submit" style="float:right;" id="unfollow-button-{{ user.profile.pk }}"><span>Following</span></button>
</form>
</div>
{% else %}
<div >
<form method="POST" action="{% url 'add-follower-js' user.profile.pk %}" id="{{ user.profile.pk }}">
{% csrf_token %}
<input type="hidden" name="profile_id" value="{{ user.profile.pk }}">
<button type="submit" style="float:right;" id="follow-button-{{ user.profile.pk }}">Follow</button>
</form>
</div>
{% endif %}
.js file
$( document ).ready(function() {
$('.add-follower-form').on("submit", function(e) {
e.preventDefault();
const profile_id = $(this).attr('id');
console.log(profile_id)
const url = $(this).attr('action');
console.log(url)
$.ajax({
type: 'POST',
url: url,
data: {
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
'profile_id':profile_id,
},
dataType: 'json',
success: function(response) {
console.log('success')
console.log(response)
console.log(profile_id)
console.log(url)
$(`.add-follower-div-${profile_id}`).find('.add-follower-form').attr('action', "/profile/" profile_id "/followers/remove/js");
$(`.add-follower-div-${profile_id}`).find('.add-follower-form').attr('class', "remove-follower-form");
$(`.add-follower-div-${profile_id}`).attr('class', `remove-follower-div-${profile_id}`);
$(`#follow-button-${profile_id}`).attr('class',"btn btn-unfollow unfollow-link");
$(`#follow-button-${profile_id}`).empty();
$(`#follow-button-${profile_id}`).append('<span>Following</span>');
$(`#follow-button-${profile_id}`).attr('id',"unfollow-button-" profile_id);
},
error: function(response) {
console.log('error', response);
}
});
});
$('.remove-follower-form').on("submit", function(e) {
e.preventDefault();
const profile_id = $(this).attr('id');
console.log(profile_id)
const url = $(this).attr('action');
console.log(url)
$.ajax({
type: 'POST',
url: url,
data: {
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
'profile_id':profile_id,
},
dataType: 'json',
success: function(response) {
console.log('success')
console.log(response)
console.log(profile_id)
console.log(url)
$(`.remove-follower-div-${profile_id}`).find('.remove-follower-form').attr('action', "/profile/" profile_id "/followers/add/js");
$(`.remove-follower-div-${profile_id}`).find('.remove-follower-form').attr('class', "add-follower-form");
$(`.remove-follower-div-${profile_id}`).attr('class', `add-follower-div-${profile_id}`);
$(`#unfollow-button-${profile_id}`).attr('class',"btn btn-follow btn-light side-link mr-4");
$(`#unfollow-button-${profile_id}`).find('span').remove();
$(`#unfollow-button-${profile_id}`).text("Follow");
$(`#unfollow-button-${profile_id}`).attr('id',"follow-button-" profile_id);
},
error: function(response) {
console.log('error', response);
}
});
});
});
views.py
#AJAX RESPONSE FOR FOLLOWERS.HTML, FOLLOWING.HTML
def add_follower_js(request, *args, **kwargs):
if request.method == 'POST':
pk = request.POST.get('profile_id')
profile = Profile.objects.get(pk=pk)
profile.followers.add(request.user)
data = {
'success': '1',
}
return JsonResponse(data, safe=False, status=200)
return redirect(request.META.get('HTTP_REFERER', 'redirect_if_referer_not_found'))
def remove_follower_js(request, *args, **kwargs):
if request.method == 'POST':
pk = request.POST.get('profile_id')
profile = Profile.objects.get(pk=pk)
profile.followers.remove(request.user)
data = {
'success': '1',
}
return JsonResponse(data, safe=False, status=200)
return redirect(request.META.get('HTTP_REFERER', 'redirect_if_referer_not_found'))
urls.py
path('profile/<int:pk>/followers/add/js', user_views.add_follower_js, name='add-follower-js'),
path('profile/<int:pk>/followers/remove/js', user_views.remove_follower_js, name='remove-follower-js'),
Example: If the button is currently (showing Following):
<div >
<form method="POST" action="{% url 'remove-follower-js' user.profile.pk %}" id="{{ user.profile.pk }}">
{% csrf_token %}
<button type="submit" style="float:right;" id="unfollow-button-{{ user.profile.pk }}"><span>Following</span></button>
</form>
</div>
I click it, the button submits the form, view returns sucessfully, and button html is changed to (showing Follow):
<div >
<form method="POST" action="{% url 'add-follower-js' user.profile.pk %}" id="{{ user.profile.pk }}">
{% csrf_token %}
<input type="hidden" name="profile_id" value="{{ user.profile.pk }}">
<button type="submit" style="float:right;" id="follow-button-{{ user.profile.pk }}">Follow</button>
</form>
</div>
But when I click it again, the html doesn't change back to showing Following. The url and all the html stays the same.. what am I doing wrong..
CodePudding user response:
I spent a few minutes looking through your code to see what the error might be but honestly I think there's a fundamentally better way of doing this that isn't so repetitive and cumbersome, JS-wise. I would suggest having a single view and url for toggling whether someone is a follower or not. It will make everything so much simpler. See below:
# template - a single form, the if-statement controls the text only
<form method="POST"
action="{% url 'toggle-following' user.profile.pk %}">
{% csrf_token %}
<button type="submit" style="float:right;">
{% if user.profile in following %}
Following
{% else %}
Follow
{% endif %}
</button>
</form>
Then we let the view to do the lifting, note the name change. I also changed the URL but I'm sure you know how to change this. We have a simple if-statement that checks whether someone is already following or not, it sets the action accordingly and determines the response. I have changed the JSON response to a simple HTTP response because you don't need JSON here:
def toggle_follower(request, pk):
if request.method != 'POST':
return redirect(... # truncated
profile = Profile.objects.get(pk=pk)
if request.user not in profile_followers.all():
profile.followers.add(request.user)
return HttpResponse("Following") # JSON response is unnecessary
else:
profile.followers.remove(request.user)
return HttpResponse("Follow")
As we are determining the value on the server and we only have a single form that handles both follow/unfollow functions, your Jquery then becomes far more concise:
$('.follower-form').on("submit", function(e) {
e.preventDefault();
const url = $(this).attr('action');
$.ajax({
type: 'POST',
url: url,
data: {
'csrfmiddlewaretoken': ... // truncated
},
success: function(response) {
// simply set the button text to the response
e.target.innerText = response
},
...
});
});