I have an array of objects which are rendered through for loop in twig template. I want to apply a filter-like mechanism where after selecting a category from a filter, list of elements in twig would update without refreshing a page and contain elements only from chosen category.
Until now I managed to pass chosen category value through ajax to Symfony controller, parse it, encode to JS and send it as a response and fetch it via ajax.
Here's some code:
//variable passed to twig
return $this->render('#Ad/ad_list.html.twig', [
'adList' => $adList,
]);
//An ajax call
$.ajax({
url : $form.attr('action'),
type: "POST",
data : filters,
complete: function(html) {
console.log(html['responseJSON'])
}
});
//creating a response
$response = JsonResponse::fromJsonString($jsonContent);
$response->prepare($request);
$response->send();
{% for ad in adList|slice(0, 9) %}
...
{% endfor %}
Is it possible to update passed variable ($adList) to twig via JS, so it would render elements from response?
Thanks to brombeer and DarkBee help I achieved my goal. I did it by:
Creating new template which holds list of elements,
Rendering this new template in main template and passing there updated value
main template:
<section>
{% include '#Ad/ad_list_container.html.twig' %}
</section>
ad_list_container template:
<div id="ad-list">
{% for ad in adList %}
...
{% endfor %}
</div>
ajax call:
$.ajax({
url : $form.attr('action'),
type: "POST",
data : filters,
success: function(response) {
$('#ad-list').html(response);
}
});
php controller:
return $this->render('#Ad/ad_list_container.html.twig', [
'adList' => $adList
]);
Related
I need to create a form with 5 select fields, each one dependent of the previous one (Schools, Disciplines, Macro-Content, Micro-Content, Teacher)
I'm able to get only one working, passing an Ajax view to the form div:
<form action="" id="orderForm" method="POST" discipline-queries-url="{% url 'ajax-load-discipline' %}>
and
<script src="//code.jquery.com/jquery-3.6.0.js"></script>
<script>
$("#institute").change(function () {
const url = $("#orderForm").attr("discipline-queries-url");
const instituteId = $(this).val();
$.ajax({
url: url,
data: {
'institute_id': instituteId
},
success: function (data) {
$("#discipline").html(data);
}
});
});
</script>
From what I understand I'd need 4 different ajax views, one for each database query, and pass the url attribute through modelform attributes like this:
'discipline': forms.Select(attrs={'id': 'discipline', 'class': 'form-control',
'discipline-queries-url': '{% url "ajax-load-discipline" %}'}),
But the special characters are escaping and returning something like this:
"GET /order/create/%7B%%20url%20%22ajax-load-discipline%22%20%%7D?institute_id=1 HTTP/1.1" 404 13568
So it is passing {% url "ajax-load-discipline" %} to the url...
Any idea of what I can do to pass the correct parameters?
When you set attributes for a widget, it does not get rendered as if it were part of the template, it gets rendered as if it were a variable being rendered in the template, hence instead of "{% url 'ajax-load-discipline' %}" you should be writing the url itself there using reverse_lazy [Django docs]:
from django.urls import reverse_lazy
'discipline': forms.Select(attrs={'id': 'discipline', 'class': 'form-control', 'discipline-queries-url': reverse_lazy('ajax-load-discipline')}),
So I have this variable called "posts" in html and its used in a for loop to create a series of well, posts.
{% for post in posts %}
{% with voteform = voteform, votes = votes, post = post %}
{%include "postlayout.html"%}
{% endwith %}
{% endfor %}
</div>
I then use Ajax to retrieve a new querylist from flask and return another series of posts based on what filters the user selects.
$('input[type=checkbox]:checked').each(function(){
all.push($(this).val());
});
console.log(all)
var moods = {
'filters': all
};
$.ajax({
url : "/update",
type: 'POST',
data: JSON.stringify(moods),
contentType: 'application/json;charset=UTF-8',
success: function(resp){
$('div#response').html('posts <br>')
for (var key in resp.data) {
var val = resp.data[key]
console.log(val)
$('div#response').append(resp.data[key]['songname'] + ' by ' +
resp.data[key]['artist'] + '<br>')
}
console.log(resp.data)
},
error: function(error){
console.log(error)
}
});
}
So I was wondering if there was a way to replace "posts" in my html code with "resp.data" from my json code.
Unfortunately, no.
The Flask template is rendered into HTML server-side before the AJAX request is made and so you cant use the AJAX response in your Flask template.
You'll have to use JavaScript (or/and jQuery) to loop over the response data and insert the required HTML.
I have built a view in views.py that returns a JSON when user press a button. The page updates simple html divs (last_bid, credits, message) without reloading but I have some {% for %} tags that don't refresh although JSON response is updated with extra data.
template.html script
<script>
$('#bid').on('submit', function(event){
event.preventDefault();
$.ajax({
method: 'POST',
url: '{% some url %}',
datatype: 'json',
data: {
some data
},
success: function(data) {
$('#last-bid').html(data.last_bid);
$('#credits').html(data.credits);
$('#message').html(data.message);
$('#registered_players').html(data.registered_players);
}
});
});
template.html
<div id="registered_players">
{% for i in registered_players %}
{{ i.auction_player__user__username }}
{% endfor %}
</div>
JSON
{"registered_players": [{"auction_player__user__username": "admin"}, {"auction_player__user__username": "minos"}], "last_bid": "8.10", "credits": 612, "message": ""}
Instead of targeting the div "registered_players". Either you need to loop through your JSON data and replace every single player Or you need to remove the old players html and add your new HTML.
Please provide your HTML by inspecting the html page for more clear answer.
Thank you all for the help. Managed to solve this by looping through JSON response.
var player_list = "<ul>";
for (var i=0; i< data.registered_players.length; i++){
player_list += "<li>" + data.registered_players[i].auction_player__user__username + "</li>";
}
player_list += "</ul>"
$('#registered_players').html(player_list);
Currently my button functions, but I've placed it inside of a django for loop. I'd like to move the js logic to a separate file, but first I need to give it a better name. Here is a snippet of my code:
{% for post in posts %}
.....
<script type="text/javascript">
function toggleLike{{post.id}}(){
$.ajax({
url: "{% url 'photo_blog-post_like_api' post.id %}",
success: function(data) {
$("#likeCount{{post.id}}").html(data.like_count + ' likes');
$('#imageElement{{post.id}}').html(data.img);
}
});
};
</script>
<a id=imageElement{{post.id}} onclick="toggleLike{{post.id}}()"><img src="/media/nav_buttons/liked.svg" height="17" width="17"></a>
....
<post info here>
....
{% endfor %}
When I remove the {{post.id}} from the function name, and onclick call, the button only functions for the post on the bottom of the page. All of the other buttons toggle the information for that one post. How can I give this function a general name, but still have it interact uniquely with each post?
You shouldn't be doing this as part of the name anyway. The post id is a parameter. The only collocated part is working out how to pass it to the Django URL tag
function toggleLike(post_id){
$.ajax({
url: "{% url 'photo_blog-post_like_api' "00000" %}".replace("00000", post_id)
success: function(data) {
$("#likeCount" + post_id).html(data.like_count + ' likes');
$('#imageElement' + post.id).html(data.img);
}
});
};
</script>
<a id=imageElement{{post.id}} onclick="toggleLike({{post.id}})"><img src="/media/nav_buttons/liked.svg" height="17" width="17">
javascript:
$('.openDiv').click(function () {
var id = $(this).attr('id');
var csrf_token = $("#csrf_token").val();
$.ajax({
data: {
csrfmiddlewaretoken: ('{{csrf_token}}'),
id: id,
},
type: 'POST',
url: '/setting/save-reporter/',
success: function () {
$('#authorisedreporter').load('save_reporter.html');
}
});
});
index.html
<div id="authorisedreporter" {% if not registerform.errors %}style="display:none"{% endif %}>
<form method="post" action="." id="reporter-form">
{% csrf_token %}
<table width="100%">
""""""""
</table></form></div>
save_reporter.html
<form method="post" action="." id="{{ id }}">
{% csrf_token %}
<table width="100%">
"""""""""
</table></form>
I am using ajax with js,after successfull ajax call,the div is replaced by save_reporter.html.But i am getting 404 page not found error in console.If i am not using $('#authorisedreporter').load('save_reporter.html'); ,i am getting the required output in console.While trying to show the output in template i did that and i am getting the error.Need help.
You can't use the jQuery load function to load templates from Django. Templates are not standalone HTML pages: as you already know from writing the other views, you need to write a URL and a view to render the template and return it.
What you should be doing is getting your /setting/save-reporter/ view to return the rendered template, and insert that result in your div via .html():
success: function(response) {
$('#authorisedreporter').html(response);