Implement jQuery in a slider that uses dynamic data - javascript

I am trying to add a slider with dynamic data to my django project using jQuery and ajax to do it, I received help to make the previous and next button which gives the ability to swipe through profiles, but I am now focusing on the previous one, in the process I realized that there is a NoReverseMatch error in the code and I don't know how to fix them because I am very new at jQuery and ajax.
views.py
def matesmain(request):
contents = Mates.objects.all()
context = {
'contents': contents,
'form_mates': MatesForm(),
}
print("nice3")
return render(request, 'mates.html', context)
def previous(request):
id= request.GET.get("id", None)
if id != 1:
previous_id= id-1
prev_user= Mates.objects.filter(user= previous_id)
data={
"username": prev_user.user,
"req_bio": prev_user.req_bio,
"req_image": prev_user.req_image,
}
return JsonResponse(data)
models.py
class Mates(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='usermates')
users_requests = models.ManyToManyField(User, related_name="users_requests")
req_bio = models.CharField(max_length=400)
req_image = models.ImageField(upload_to='requestmates_pics', null=True, blank=True, default=False)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to='profile_pics', null=True, blank=True, default='default.png')
bio = models.CharField(max_length=400, default=1, null=True)
connection = models.CharField(max_length = 100, blank=True)
follower = models.IntegerField(default=0)
following = models.IntegerField(default=0)
urls.py
urlpatterns = [
path('mates', views.mates, name='mates'),
path('mates-main', views.matesmain, name='mates-main'),
path('previous', views.previous, name='previous'),
]
html
<div class="mates-grid-1-1-content">
<div class="mates-grid-2-content">
<button type="button" onclick="previous({{user.id}})" id="prev-button">prev</button>
</div>
<div class="mates-grid-1-content">
<div class="mates-item-content">
<img class="mate-pic" src="{{ user.profile.profile_pic.url }}" >
</div>
<div class="mates-item-content">
{{ content.user }}
</div>
<div class="mates-item-content">
<div class="responses">
<div class="response-item-img">
<img class="mates-image" src="{{ content.req_image.url }}" width="400px">
</div>
<div class="response-item-bio">
<p>{{ content.req_bio }}</p>
</div>
<div class="response-item-button">
<button type="submit">Submit</button>
</div>
</div>
</div>
</div>
<div class="mates-grid-3-content">
<button type="button" onclick="next({{user.id}})" id="next-button">next</button>
</div>
</div>
script
function previous(id){
$.ajax({
url: '{% url 'previous' %}',
type: "get",
data: {
'id': id,
},
dataType: 'json',
success: function (data) {
$(".mates-item-content").empty();
$(".mates-item-content").append("<img class="mate-pic" src="{{ user.profile.profile_pic.url }}" >");
$(".mates-item-content").empty();
$(".mates-item-content").append("{{ content.user }}");
$(".mates-item-content").empty();
$(".mates-item-content").append("<img class="mates-image" src="{{ content.req_image.url }}" width="400px">");
$(".mates-item-content").empty();
$(".mates-item-content").append("<p>{{ content.req_bio }}</p>");
},
error: function (data) {
alert('nope');
}
});
};
}

You're getting a NoReverseMatch exception because you're not using the {% url &} tag properly inside the $.ajax() function. Since you have that JavaScript code within the HTML itself, then you can replace what you have with the following:
url: "{% url 'previous' %}"
Also, in the success property's callback function, you're not using the data you're getting from the view how it is supposed to be used. Note that you won't be able to get that data using the Django template language inside this callback, but you need to use JavaScript to access that data. For example:
success: function(data){
console.log(data.req_bio);
}
That is because when the HTML gets rendered by Django, the information that you might want to use inside the callback function (e. g.: {{ req.bio }}), will not be there yet.
Nevertheless, there's a way to keep using the Django template language when handling an AJAX response, using the context data returned by the view. Please, refer to this answer for further information.

Related

Send items from forloop populated data in django template through ajax to django view

I have been trying to create a click and populate div with ajax in my django e-commerce application. The project works in such a way that when a customer clicks on a category in men's page it populates another div
gender.html
{%for cate in cat%}
<a href="javascript:getcat()" id="catgend" cats-data="{{cate.catname}}" gen-data="{{gens.gender}}" data-sort-url="{% url 'Home:sortcat' cpk=cate.pk %}" >{{cate.catname}}</a>
{% endfor %}
<div id="products">
<div class="progress">
<img src="{% static 'img/load.gif'%}">
</div>
</div>
This sends the data to my django view through the ajax function called getcat but the data sent through is that of the first item in the loop in-respective of the loop item clicked on. below is my ajax function:
getcat()
function getcat() {
$(".progress").show()
var cat = $("#catgend").attr("cats-data");
var gender = $("#catgend").attr("gen-data");
var url = $("#catgend").attr("data-sort-url");
$.ajax({
url: url,
data: {
'cat': cat,
'gender': gender,
},
success: function (data) {
$("#products").html(data);
}
});
$(".progress").hide()
}
enter code here
From my research i discovered its because they have same ID. How do i solve the issue of dynamically changing the id over the same loop. Thanks
Replace the id attribute with a class attribute since you shouldn't have more than a single element with the same id. Also, we can change cats-data and gen-data to valid data-* attributes.
{% for cate in cat %}
<a href="#" class="catgend" data-cats="{{cate.catname}}" data-gen="{{gens.gender}}" data-sort-url="{% url 'Home:sortcat' cpk=cate.pk %}" >{{cate.catname}}</a>
{% endfor %}
Bind a click event to anchors using the new class name.
$('.catgend').on('click', function (e) {
$('.progress').show()
var data = $(this).data()
$.ajax({
url: data.sortUrl,
data: {
'cat': data.cats,
'gender': data.gen,
},
success: function (data) {
$('#products').html(data);
}
});
$('.progress').hide()
});
Utilise the data attributes to accumulate data values in a simple way.

Django jquery AJAX form submission in view and display results

There are a lot of different posts about all parts of this, I just can't quite figure out how it all fits together.
I have name that is displayed with an update button next to it. When the update button is clicked it shows a form to update the name. In the form is a save changes button. When the changes are saved, it should reload the name at the top, and should the update button be clicked again, the form should show the new name info.
urls.py
path('profile/<int:pk>/', views.customer_profile, name='profile'),
path('update-profile/<int:pk>/', views.update_profile, name='update-profile'),
views.py
def customer_profile(request, pk):
name = get_object_or_404(CEName, id=pk)
name_form = NameForm(instance=name)
return render(
request,
'customer/customer_profile.html',
{'name':name, 'NameForm': name_form}
)
def update_profile(request, pk):
if request.POST:
name_form = NameForm(request.POST)
if name_form.is_valid():
name_form.save()
name = get_object_or_404(CEName, id=pk)
context = {'name':name, 'NameForm': name_form}
html = render_to_string('customer/customer_profile.html', context)
return HttpResponse(html, content_type="application/json")
template.html
<div id="name" class="container d-flex justify-content-between pt-1">
{{ name }}
<button id="update_button" class="bold btn btn-main btn-sm button-main">UPDATE</button>
</div>
<div id="div_NameForm" class="container" style="display: none;">
<hr size="3px">
<form id="NameForm" method="POST" data-url-name="{% url 'customer:update-profile' name.id %}">
{% csrf_token %}
{{ NameForm.as_p }}
<br>
<button type="submit" id="save_changes" class="btn btn-main button-main btn-block">Save Changes</button>
</form>
</div>
<script src="{% static 'ce_profiles/ce_profiles_jquery.js' %}"></script>
jquery.js
$('#save_changes').click(function() {
var NameForm = $('#NameForm');
$.ajax({
type: 'post',
url: NameForm.attr('data-url-name'),
data: NameForm.serialize(),
dataType: 'json',
success: function(data, textStatus, jqXHR) {
$('#name').html(data);
}
});
});
The code for the update button toggle is not displayed.
In your jQuery, to start with.
- First, you could (some may say should) have put a submit event handler on the on the form instead of a click event for button.
- Second, you are doing an AJAX call so you should prevent form submission using .preventDefault() on the submit event that was trigged when the button was pressed. This will prevent the page from reloading.
- Third, in your ajax success callback you should use text() instead of html() since name I imagine is text and not html, however that's just an assumption.
$('#NameForm').on('submit', function(evt) {
evt.preventDefault();
var NameForm = $('#NameForm');
$.ajax({
...
success: function(response) {
$(#name).text(response); // or response.name or whatever
}
});
})

How to refresh a part of the DOM HTML when querying a foreign django view

Hello Awesome People!
So many questions on StackOverflow are about "How to refresh dom via jquery (from the same view/url)" It's not what I'm looking for.
With a website that large of its parts are running with ajax, I wonder how to refresh a part of the HTML DOM when querying a foreign django view.
Let me be clearer with some examples:
I have that view that sends all_users to template
def usersList(request):
all_users = User.objects.all()
return render(request,'administration/users-list.html',{'all_users':all_users})
In the template I loop through all_users... The 2nd <span> reflects the activation state of the user
{% for u in all_users %}
<span>{{forloop.counter}}.- {{u.name}} <span>
<span id='user_{{u.id}}_state'>
<button data-id='{{u.id}}' type='button' class='css-btn btn-circle'>
{% if u.is_activate %} Active{% else %}Inactive{% endif %}
</button>
<span>
{% endfor %}
With jquery, I send a request to a specific view responsible only to activate or deactivate the account of the user. We can activate/deactivate user in many parts of the website, that's why I do so in a different view.
Here's the view:
def deactivateUser(request):
user = request.user
if user.has_perm('is_admin') and request.is_ajax() and request.method == 'POST':
id_user = request.POST.get('id')
targeted_user = get_object_or_deny(User,id=id_user)
# get_object_or_deny is my own function
it will get the object or raise PermissionDenied otherwise
if targeted_user.is_activate:
targeted_user.is_activate = False
state = 'deactivated'
else:
targeted_user.is_activate = True
state = 'activated'
targeted_user.date_update_activation = NOW() # own function
targeted_user.save()
return JsonResponse({'done':True,'msg':'User successfully %s' %s state})
# Here we return a JsonResponse
raise PermissionDenied
So now, how can I refresh the Dom with following jquery stuff to get the current state of each user
$(document).on('click','.btn-circle',function(){
var id = $(this).data("id");
$.ajax({
url:'/u/de-activate/?ref={{ request.path }}',
type:'post',
data:{
csrfmiddlewaretoken:"{{ csrf_token }}",
id:id,
},
success:function(response){
$("#user_"+id+"_state").replaceWith($("#user_"+id+"_state",response));
if(response.created) alert(response.msg);
},
error:function(){
alert("An error has occured, try again later");
}
});
});
Note that all_users is required to loop through. deactivateUser() return a Json response, even though it doesn't returned it, it will not matter.
You can send http response, not json.
First, just move your html that want to change. in this situation,
{% for u in all_users %}
<div id="user-part">
<span>{{forloop.counter}}.- {{u.name}} <span>
<span id='user_{{u.id}}_state'>
<button data-id='{{u.id}}' type='button' class='css-btn btn-circle'>
{% if u.is_activate %} Active{% else %}Inactive{% endif %}
</button>
<span>
</div>
{% endfor %}
Then save it i.e. user_part.html
Second, make your view return HttpResponse with that html, and context. You can use either HttpResponse or render_to_response. I recommend render_to_response.
context = {
'all_users': all_users,
}
return render_to_response(
'path_to/user_part.html',
context=context,
)
Third, you just change script for replacing your html.
success: function(response){
$('#user-part').html(response);
prevent();
}

HTML refreshing on click

I'm using the sample found here http://stackoverflow.com/questions/27218680/how-can-i-reload-just-one-div-on-click and I think I'm missing something in my example or maybe the value is not passing as I'm using MPTT instead of a standard menu.
This is how I'm loading my menu found in my base.html -
{% recursetree nodes %}
{{ node.name }}
{% endrecursetree %}
Here is the javascript I've included -
<script>
$(document).on('click','.node',function(e) {
id = $(this).attr("id");
$.ajax({
type: "GET",
url: '/gui/details/' + id,
success: function (result) {
$('.details').html(result);
},
});
});
</script>
I'm then trying to use this id to reload the template here -
<div class="details">
{% include 'gui/details.html' %}
</div>
Here is the view for generating the details -
def display_details(request, list_id):
qs_details = Details.objects.filter(owner=request.user, list=list_id)
return render(request, 'gui/details.html', {'qs_details': qs_details,})
Currently when I click anything on my list it doesn't do anything.

Django model formsets and Ajax

I am trying to submit my zipped formsets using Ajax. The code works perfectly when the request is not ajax. But whenever I am trying to implement Ajax, I am getting a ValidationError: [u'ManagementForm data is missing or has been tampered with']
My views:
def App(request):
lectures = Lecture.objects.all()
TopicFormSet = modelformset_factory(Topic, extra=0)
SummaryFormSet = modelformset_factory(Summary, extra=0)
tquery = Topic.objects.all()
squery = Summary.objects.all()
#saving formsets:
if request.method == 'POST' and request.is_ajax():
t_formset = TopicFormSet(request.POST)
s_formset = SummaryFormSet(request.POST) #formset instances
if t_formset.is_valid() and s_formset.is_valid():
t_formset.save() and s_formset.save()
zipped = zip(t_formset.forms, s_formset.forms) #saving them with new data
else:
return HttpResponse("not valid formsets, dude") # for testing purposes
else: #request=GET
t_formset = TopicFormSet(queryset = tquery)
s_formset = SummaryFormSet(queryset = squery)
zipped = zip(t_formset.forms, s_formset.forms)
return render (request, "app.html", {"lectures" : lectures, "zipped" : zipped, "t_formset" : t_formset, "s_formset" : s_formset})
And my Javascript code:
$(document).ready(function(){
$(".mygt").click(function(){ // it's a button
serializedData = $("#id_form-0-name").serialize(); // I didn't know how to "catch" all forms in formset so I am only serializing the first one
$.ajax({
url: "/app/",
type: "post",
data: serializedData,
csrfmiddlewaretoken:'{{ csrf_token }}',
success: alert(serializedData)
})
event.preventDefault();
});
});
P.S. I have also included csrf cookie in from this article: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax and {% csrf_token %} is present near the forms.
Edit: my html:
<form action = "http://127.0.0.1:8000/app/" method = "POST">
{% csrf_token %}
<!-- t_formset.management_form -->
{{ t_formset.management_form }}
<!-- t_formset.management_form -->
{{ s_formset.management_form }}
<!-- formsets -->
{% for topic, summary in zipped %}
<div id="topic">{{ topic }}</div>
<br>
<input type="submit" value="Submit" class="mygt" />
<br>
<div id="summary">{{ summary }}</div>
<br>
<input type="submit" value="Submit" class="mygt" />
{% endfor %}
The problem was that I did not know how to serialize all formset and I was only serializing the first field (for testing purposes). I was not aware of the fact that Django sends all formset and not just one field like I thought. So I replaced the
serializedData = $("#id_form-0-name").serialize();
with:
serializedData = $("form").serialize();
And the code works!
Did you include {{t_formset.management_form}} and {{s_formset.management_form}} in your template as described here?I had the same problem and i got the same answer here

Categories

Resources