How to send Jinja variables to Django View - javascript

I have a view in HTML whereby it displays a list of table with attendees;
<table>
{% for people in Attendees %}
<tr>
<td>{{ people.id }}</td>
<td>{{ people.name }}</td>
<td>
<a id='deleteAttendeeButton' class="btn btn-primary btn-xs">Delete</a>
</td>
</tr>
{% endfor %}
</table>
The table has a delete button for all entries and when clicked, I am using AJAX for a GET request as per below;
$("#deleteAttendeeButton").on("click", function () {
$.ajax({
url: '/modifyAttendee/?id={{ people.id }}',
type: 'GET',
})
});
I want to use AJAX to send the people.ID variable to view so that the view can determine what object to delete in the database. However, the issue is I cannot seem to pass in a jinja variable in AJAX.
Am I missing something in my AJAX statement? If not, what would be an ideal solution?
Note: I do not want to use 'href' in the button because I do not want to reload the page.

Well, it doesn't work like that. The template tags are evaluated at render time, but you need the ID of the element that was clicked. You can use the data element to hold the ID and get it back in the JS.
There are a few other things wrong here too; in particular, HTML element ids need to be unique, but you are using the same one for every link in the loop. You should use a class instead.
<a class='deleteAttendeeButton btn btn-primary btn-xs' data-people_id="{{ people.id }}">Delete</a>
...
$(".deleteAttendeeButton").on("click", function () {
var people_id = $(this).data('people_id');
$.ajax({
url: '/modifyAttendee/?id=' + people_id,
type: 'GET',
})
(Note, unless you have specifically configured it, Django does not use Jinja; this is almost certainly Django template language which is similar but not the same. It doesn't affect your problem, though.)

Related

pass some variable of a row in Vue.js as parameters to vue.js method and send out using axios

I have a web app, used Django as backend, Vue.js for the frontend.
In the cell, that's a button for every row, which is supposed to get the detail info of the row after click.
So I want to pass some variable of a row in Vue.js as parameters to Vue.js method.
But I failed to do that, when I tried to click the button, it always submitted the form, but I have added type="button" already.
<tbody>
<tr v-for="(row, index) in filteredRows" :key="`isbn-${index}`">
<td name="`title_${index}`" v-html="highlightMatches(row.title)">{{ row.title }}</td>
<td v-html="highlightMatches(row.author)">{{ row.author }}</td>
<td><button type="button" v-on:click="greet( $event, {{ row.title }})">Greet</button></td>
<td name="`discipline_code_course_code_${index}`" bgcolor= "white"><div contenteditable></div></td>
</tr>
</tbody>
<script>
const app = new Vue({
el: '#app',
data:() => ({
filter: '',
rows: book_rows
}),
methods: {
greet: function (event, title) {
alert(title); #undefined when debug
this.$http.post(
'/check_code/',
{ title: title }
);
}
},
</script>
How could I pass some variable of a row in Vue.js as parameters to Vue.js method and send out using axios?
You need to use the verbatim tag, to ensure django does not strip those attributes from the template before JS uses them: https://docs.djangoproject.com/en/3.2/ref/templates/builtins/#verbatim
Wrap you JS template (currently within your django served HTML file) with the verbatim tag to ensure the bracketed vars are not parsed by django:
{% verbatim %}
<div>{{ app.jsVars }}</div>
{% endverbatim %}
You can check this by inspecting the source code of the produced HTML page (right click view source) - and your JS template variables should be there.
Quick note:
The code v-on:click="greet( $event, {{ row.title }})" might need inspecting, as if that's your title - you're applying it slightly differently in the row above:
v-html="highlightMatches(row.title)
If it is a backend var, it needs speech-marks:
v-on:click="greet( $event, '{{ row.title }}')"

Django framework, crud in grid row

I’ve been developing an app in djanog 3.0 for my wife. Got a nice modal ajax crud up and running for the grid, but she does not like the modal effect, she just wants to edit inside the row and always have an empty row at the bottom for new entries.
I’ve looked at table2 and jqgrid but have not been able to find something that works like that. I’ve now been playing around with editablegrid.net js grid and I can display data and edit, but not save the edited data. Editablegrid is a good example of what my wife would like to do, without the empty new row, but should be able to hack that in.
Obviously I’ll not be able to make a row a from, so I need to figure out how to make my data serial in something like json. I then also need the CSRF token as part of the json right?
I’m way out of my depth as I develop embedded c for a living and this all is self taught as we go.
Questions are:
What is the best grid for something like this? Is it even possible?
Is django even suited for something like this?
Should I pivot and go with rest api and look at some other tech like react?
EDIT 1:
I tried #Raiyan suggestion like follows:
{% for person in persons %}
<form id="F{{ person.pk}}" method="post" action="{% url 'person-update' person.pk %}" class="js-ajax-update-form" update-table-name="ajax-table">
{% csrf_token %}
<tr>
<td>{{ person.title }}</td>
<td>{{ person.first_name }}</td>
<td>{{ person.last_name }}</td>
<td>{{ person.id_number }}</td>
</tr>
</form>
{% endfor %}
but if I open page and look at html it looks like this:
<form method="post"></form>
<input type="hidden" name="csrfmiddlewaretoken" value="IREdUDr8bplgvDrtmMSSjOua2NL98SXnoeIGdX1mN0nY2hpQTByW0FfJZxvO5kCw">
<tr id="R2">
<td>Mr.</td>
<td>John</td>
<td>Doe</td>
<td>123456789</td>
</tr>
</tbody>
For some reason the form tag gets closed before the table row and input. I've also adapted a simple CRUD books app to try and get the desired behavior with none of the fluf, but there also the form tag closes immediately.
For the CRUD app I changed the fbv view to:
def book_list(request, template_name='books_fbv/book_list.html'):
books = Book.objects.all()
forms = []
for index, book in enumerate(books):
forms.append(BookForm(request.POST or None, instance=book, prefix="form_{}".format(index)))
data = {}
data['object_list'] = forms
if request.method == 'POST':
for form in forms:
if form.is_valid():
action = form.save(commit=False)
action.save()
return render(request, template_name, data)
and html to:
<table>
<thead>
...
</thead>
<tbody>
{% for book in object_list %}
<form method="POST">
{% csrf_token %}
<tr>
<td>{{ book.name }}</td>
<td>{{ book.pages }}</td>
</tr>
</form>
{% endfor %}
</tbody>
</table>
Any idea why form tags close like that?
Django is very well suited for projects like this.
Obviously I’ll not be able to make a row a from
I think you can, unless I misunderstood something. You can render each row as a separate form, using Django templates. The implementation may look like this:
{% for row in rows %}
<form method="post">
<tr>
<td>...</td>
...
</tr>
</form>
{% endfor %}
You are right that you need to handle the CSRF token. Django allows you to insert CSRF token anywhere in the rendered HTML using the {% csrf_token %} in your template. A very simple form would look like this:
<form method="post">{% csrf_token %}... </form>
In your case, each of the row-forms would then look like:
{% for row in rows %}
<form method="post">
{% csrf_token %}
<tr>
<td>...</td>
...
</tr>
</form>
{% endfor %}
Read more about it here:
https://docs.djangoproject.com/en/3.0/ref/csrf/#how-to-use-it
Hope this helps.
I agree with everything that #Raiyan said, but just wanted to give my input on this as well.
she just wants to edit inside the row and always have an empty row at the bottom for new entries.
Sounds like your wife wants something very responsive and dynamic, which for me, it means that the frontend (or client-side) should be more active. Although you can achieve a similar result with Django or other "server render" options, using Rest API and Javascript will give you much more flexibility.
React is an example (as you mentioned), but depending on your project, you don't need to go there. You can still use Django to create your API and simple Javascript (or even jQuery) to call the API. This would allow you to create new rows dynamically, delete data and manipulate the content without reloading the page (which I believe is the smooth effect desired).
Here are some references:
AJAX in jQuery: https://api.jquery.com/jquery.ajax/
Rest API in Django: https://medium.com/#BennettGarner/build-your-first-rest-api-with-django-rest-framework-e394e39a482c

How to generate a unique div id for django objects displayed in template

I am working on a Django project. I have a template which displays all the available posts. Users can like a post. Everything is working fine. But I am facing a problem. Since I am using ajax to change the status of the like button when a user clicks on it, I noticed that all the like buttons of the displayed posts object are affected, when a user clicks on the like button of one of the displayed posts. I want changes to occur just on the like button the user has clicked. Not all the like buttons of the displayed post object
Example of my HTML template looks something of this sort.
{% for post in allpost %} <!--for loop to get all post objects in data base-->
{{post.tittle}}
{{post.content}}
{{post.type}}
<!-- like button for users to be able to like post they fine interesting-->
<a href="" data-href="{% url 'post:api_like' slug=post.slug %}">
<button id="like">like</button></a>
{% endfor %}
So you can see my like button id is not dynamic, which is one of the reasons I am facing this problem. How can I go about generating a dynamic button id for each like button in the for loop post?
Please Help me out
Identifiers in HTML must be unique instead assign a CSS class and then use it to attach event handlers.
Instead of using id attribute, I would recommend to use custom data-* attributes if you want to persists arbitrary data which can be fetched using .data() method.
{% for post in allpost %} <!--for loop to get all post objects in data base-->
<!-- like button for users to be able to like post they fine interesting-->
<button type="button" class="like" data-id="{{post.id}}">like</button>
{% endfor %}
Here is a jQuery Script to attach event handler and get data on click event
$(function (){
$('.like').on('click', function(){
//Fetch Id
var id = $(this).data('id');
});
});

Populate HTML table with AJAX data in Django

I have the following AJAX script running in my Django template:
function create_table() {
$.ajax({
method: "GET",
url: "/api/data/",
success: function(data){
console.log('button clicked')
console.log(data)
//$('#table').html('<div class="test">' + data['Name'] +'</div>');
//$('#table').load('table_to_load.html');
},
error: function(error_data){
console.log("errorrr")
console.log(error_data)
}
})
}
document.getElementById("create_table").onclick = function() {
create_table();
return false;
}
The purpose of this script is to create a HTML table upon button click populated by dictionary data fetched by the AJAX call.
The AJAX call collects the data correctly, however, I don't know how to go about inserting the table.
Should I write the table HTML in pure Javascript/jQuery inside the AJAX call? Or maybe load a pre-prepared HTML (how do I reference its directory inside the call?)?
My preferred method though would be to write the template for the table in Django's template tag language and somehow reference in it the data fetched by AJAX. Something like:
<table>
<tr>
<th>dictionary key</th>
<th>dictionary value</th>
</tr>
{% for key, value in dictionary.items %}
<tr>
<td>{{ key }}</td>
<td>
{{ value }}
</td>
</tr>
{% endfor %}
</table>
But I am not sure if it's possible.
You can do it either way, but you seem like you are trying to do in in 1/2 of both ways.
You can use ajax to make a call and get back some json data, and then use that json object to build the html string and use jquery to insert that html at the correct point in your page - nothing wrong with that way imo, though I personally am not a fan of hand stitching together html statements (mostly because for complicated pages it gets hard to design them and debug them this way, but for small pieces its OK).
An alternative is to have jquery call django view (via a url you have defined), and have that django view make the database call and use a template that is already in your project as a html doc, and then render that template and data just like you would any other django page. That view would return an httpresponse containing html, and then jquery would just insert that html into the page as before.

JQuery - autorefresh part of a page

In my Django project, I have a page that displays all the instances of a particular model. I want to auto-refresh the page every few seconds, but only update the relevant part of the page.
I'll describe each part. First - I have a Django view. In its simplest form, it looks like this
class MyListView(ListView):
lookup_field = 'uuid'
model = Foo
template_name = 'mylist.html'
def get_queryset(self):
return list(Foo.objects.all()) # finds all my objects from DB
def get_context_data(self, **kwargs):
objects = self.get_queryset()
context = super(MyListView, self).get_context_data(**kwargs)
context['foos'] = objects # this gets passed to html page
return context
So it finds all Foo objects from the database and returns it to the html.
The html page displays a table, where each entry is a row. Furthermore, there is a checkbox at the beginning of each row. Like this
<table id="content">
<thead>
<tr>
<th><input type="checkbox" id="chckHead"/></th>
<th>UUID</th>
<th>Attribute1</th>
<th>Attribute2</th>
</tr>
</thead>
<tbody>
{% for item in foos %}
<tr id="{{ item.uuid }}">
<td>
<input type="checkbox" name="checkboxlist" class="chcktbl" />
</td>
<td><code>{{ item.uuid }}</code></td>
<td>{{ item.attribute1 }}</td>
<td>{{ item.attribute2 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
Now, some of the attributes of the Foo model may get updated in the background, so I want to somehow refresh the page periodically with new data.
I did that in javascript, like this
function setup() {
setTimeout("refreshPage();", 5000);
}
function refreshPage() {
window.location = location.href;
}
$(document).ready(setup);
So every 5 seconds, JS would call refreshPage(), and my page gets refreshed. If the database was changed behind the scenes, my page would reflect it.
The problem with the above is that it refreshes the whole page, which includes the checkbox. So if I had already selected a checkbox, the refresh would reset it to its original state ('not checked').
So, what is the correct way to solve this problem?
Just really high level:
The window.location that you're adding is going to reset the whole page. By this time you've already figured that out. What you're looking for is something could be handled by using a page partial or by using a REST endpoint and pushing it back through the template.
Here are the steps you'll want refreshPage to preform instead.
Save off any values that you think are important
Send an ajax request to get either the partial or json
Render that new information to the page
Put back the values from step one over the values rendered in step 3
More likely you're going to want to wait to do the refreshPage if they're currently editing the area (saves you step 1 and 4). That, may be a choice you've already voted against.
I hope that helps, it's a very non-technical answer but I'm not sure I could give you a very specific answer without knowing A LOT more about your project.

Categories

Resources