Large set of data, DataTables render time awful - ajax

I have a view that displays a set of data of about 3000+ records (multiple objects combined into a QuerySet. The result is rendered into a table using DataTables but the render time is terrible - 15 seconds at least.
I dug deeper into DataTables and found deferRender API option together with AJAX thing. As I never used it before I'd like to ask for guidance on how to approach in my particular case. Below are views.py and template with DataTables.
views.py:
def index(request):
clients = Client.objects.all().prefetch_related('loan_set', 'loan_set__case_set')
return render(request, 'app/index.html',
{'clients': clients})
index.html:
<table id="case_list" class="display">
<thead>
<tr>
<td>Imię i nazwisko</td>
<td>Edycja</td>
</tr>
</thead>
<tbody>
{% for c in clients %}
<tr>
<td>{{ c.firstName }} {{ c.lastName }}</td>
{% if c.editLock %}
<td><i class="fas fa-lock fa-lg" style="color:Red" title="W edycji przez: {{ c.lockedBy }}"></i> {{ c.lockedBy }}</td>
{% else %}
<form method="post">
{% csrf_token %}
<td><i class="fas fa-pen-square fa-2x" style="color:green"></i></td>
</form>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
<script type="text/javascript">
$(document).ready(function(){
$('#case_list').DataTable( {
deferRender: true
}
);
});
</script>

Look at the documentation for datatables.
$('#case_list').DataTable( {
"processing": true,
"serverSide": true,
"ajax": "{yourdata_url}"
} );
In your view, you have to send the data in json format. Note that you need to do the search etc with your logic in the view.
I would also look into django-datatable-view package.

Related

Multiple root nodes in Alpine.js

Building a data table with the latest Alpine.js (v3.7.0).
Ran into a problem when trying to implement child rows (i.e an additional togglable row under the main/parent row).
Simplified version:
<tbody>
<template x-for="row in currentPageData" :key="row.id">
<tr>
<td>foo</td>
<td>bar</td>
<td>baz</td>
</tr>
<tr>
<td colspan="3">
Some additional content
</td>
</tr>
</template>
</tbody>
While I'm not getting any errors in the console, the second node (tr) is not rendered. I assume that's because Alpine requires a single root element. Is there any way around it, as wrapping with div is invalid HTML and a tbody wrapper breaks the layout?
Thanks to Alpine templates being rendered server-side I ended up with the following workaround:
When table has child rows I remove the root tbody and wrap each tr pair with a tbody of its own.
EDIT (23-9-22):
As per #NoobnSad's request code in twig:
{% if not options.enableChildRows %}
<tbody>
{% endif %}
<template x-for="row in currentPageData" :key="row.id">
{% if options.enableChildRows %}
<tbody>
{% endif %}
<tr>
{% if options.enableChildRows %}
{% include datatable.componentPath('childRowToggler') %}
{% endif %}
{% include datatable.componentPath('tableCells') %}
</tr>
{% if options.enableChildRows %}
{% include datatable.componentPath('childRow') with {tableHandle:datatable.handle} %}
</tbody>
{% endif %}
</template>
<template x-if="recordsCount===0">
{% include datatable.componentPath('notFound') %}
</template>
{% if not options.enableChildRows %}
</tbody>
{% endif %}

Laravel vue js conditional rendering inside v-for

I'm having a trouble on how can I implement conditional rendering inside v-for in laravel vue js
based on the documentation of vue js v-for and v-if together is not recommended. It would be great if anybody could help me out, thank you so much in advance!.
This is what flow looks like I know the format is incorrect
<tr v-for="user in users" :key="user.id" :value="user.id">
<td>
<v-if =user.gender="Male" >
<span>Male - {{ user.gender }}</span>
<v-else>
<span>FeMale - {{ user.gender }}</span>
</td>
</tr>
script
<script>
export default {
data() {
return {
users: [],
}
},
created() {
this.getUsers();
},
mounted() {
},
methods: {
getUsers() {
axios.get(BASE_URL + "/users/listUsers").then(response => {
this.users = response.data;
});
},
},
}
</script>
Your v-if syntax is completely incorrect. Let's fix it first.
<tr v-for="user in users" :key="user.id" :value="user.id">
<td>
<span v-if="user.gender=='Male'">Male - {{ user.gender }}</span>
<span v-else>FeMale - {{ user.gender }}</span>
</td>
</tr>
If <span> isn't necessary I would use this:
<tr v-for="user in users" :key="user.id" :value="user.id">
<td v-if="user.gender=='Male'">Male - {{ user.gender }}</td>
<td v-else>FeMale - {{ user.gender }</td>
</tr>
Actually, there is a better way:
<tr v-for="user in users" :key="user.id" :value="user.id">
<td>{{ user.gender=="Male" ? "Male" : "FeMale" }} - {{ user.gender }}</td>
</tr>
v-for and v-if can't be used in the same tag. This is not the case in your code. When you need v-for and v-if together, you should use a computed property, and return the array/object that is filtered based on the condition, then inject it into v-for.
Let's say you need something like this:
<tr v-for="user in users" :key="user.id" v-if="user.id > 10">...</tr>
In this case, we use computed property:
computed: {
filteredUsers() {
return this.users.filter(user => user.id > 10);
}
}
and in the template:
<tr v-for="user in filteredUsers" :key="user.id">...</tr>
I think there is a misunderstanding. You should not use v-if and v-for on the same element the way you used it is fine. You can see an example here.
If you don't want to have v-if at all since you aren't rendering completely different elements you could use ternary operation in mustaches:
<tr v-for="user in users" :key="user.id" :value="user.id">
<td>
<span>{{ user.gender === 'Male' ? `Male - ${user.gender}` : `Female - ${user.gender}` }}</span>
</td>
</tr>

how to change the number of total rows in datatable

I'm developing an application with Symfony 3 in which I'm using datatables.
to avoid getting all rows of database, I'm using doctrine's paginator. so i want the datatable will get 100 elements first, then when I click in next button it will charge the next 100 elements.
My problem is that when setting datatable with first 100 elements, I can't click on next button. ( because it's showing the 100 elements so there are no other elements for it). I want to tell it that I have more than 100 elements. so how can I do it.
My table :
<table class="table table-striped table-bordered dt-responsive nowrap" cellspacing="0" width="100%"
id="table_city">
<thead>
<tr>
<th>Code</th>
<th>Name</th>
<th>Region</th>
<th>Country</th>
<th class="no-sort">Actions</th>
</tr>
</thead>
<tbody>
{% for core_city in core_cities %}
<tr>
<td>{{ core_city.code }}</td>
<td>{{ core_city }}</td>
<td>{{ core_city.CoreRegion }}</td>
<td>{{ core_city.CoreRegion.coreCountry }}</td>
<td class="datatable_td_buttons">
<a class="m-portlet__nav-link btn m-btn m-btn--icon m-btn--icon-only m-btn--pill"
title="Show" href="{{ path('core_city_show', { 'id': core_city.id }) }}">
<i class="la la-search"></i>
</a>
<a href="{{ path('core_city_edit', { 'id': core_city.id }) }}"
class="m-portlet__nav-link btn m-btn--icon m-btn--icon-only m-btn--pill" title="Edit">
<i class="la la-edit"></i>
</a>
<a href="{{ path('core_zip_code_import_by_city', { 'id': core_city.id } ) }}"
class="m-portlet__nav-link btn m-btn--icon m-btn--icon-only m-btn--pill"
title="Import Zip Code">
<i class="la la-upload"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
I found solution :
$('#example').dataTable( {
"infoCallback": function( settings, start, end, max, total, pre ) {
return start +" to "+ end;
}
} );

update my database and discard an element from table

i want to delete an item from database and remove it from table
Entity product
i want to select all the products and after a click on button x i want it to update name and remove it from table
Any help ??
my twig :
<script>
$("document").ready(function () {
$(".btn-group-vertical").click(function () {
$.ajax({
type:'get',
url:'http://localhost/symfony/nouveau%20dossier/web/app_dev.php/'+$(this).val(),
beforeSend: function () {
},
success: function(data){
var x = $("produit").val(data.approuver);
console.log(x);
$("tt").find('td').fadeOut(1000,function(){
$("tt").remove();
});
}
});
});
});
</script>
{% endblock script %}
{% block body %}
<section class="content">
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header">
<h3 class="box-title">Produit en attente</h3>
</div>
<!-- /.box-header -->
<div class="box-body">
<table id="example2" class="table table-bordered table-hover">
<thead>
<tr>
<th>Produit de</th>
<th>Libelle Produit</th>
<th>Quantite stock</th>
<th>etat</th>
</tr>
</thead>
<tbody>
{% for product in products %}
<tr class="tt">
<td align="center">{{ product.seller }}</td>
<td align="center">{{ product.libelle }}</td>
<td align="center">{{ product.quantiteStock }}</td>
<td><button
type="button"
class="btn btn-group-vertical btn-danger btn-xs"
id=1>Decliner</button>
<button type="button"
class="btn btn-group-vertical btn-sucess btn-xs"
id=2>Approuver</button>
</td>
</tr>
{% endfor %}
<tfoot>
<tr>
<th>Produit de</th>
<th>Libelle Produit</th>
<th>Quantite stock</th>
<th>etat</th>
</tr>
</tfoot>
</table>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
</div>
<!-- ./wrapper -->
my controller :
public function approuverAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$produit = $em->getRepository('ProductBundle:Product')
->findOneBy(array('id'=>$id));
$produit->setApprouver('Approuver');
$respones = new JsonResponse();
return $em->merge($produit);
$em->flush();
}
Any help please
I want to delete an item from database and remove it from table Entity
product
To remove a product:
$em->remove($produit);
$em->flush();

Twig and pagerfanta get the fieldname and the fieldname.value

I'm trying to get the fieldname of a pagerfanta results.
Twig template
{% for post in posts %}
{{ dump(post) }}
{% endfor %}
The dump result is:
Users {#764 ▼
-iduser: 11
-username: "xzvdsfg"
-password: "SHHHHHH"
-lastlogin: DateTime {#691 ▶}
-roles: []
}
i want to get the name of each entry without known it to place in a table like this
<table>
<thead>
<th>{{ fieldname }}</th>
</thead>
<tbody>
<td>{{ fieldname.value }}</td>
</tbody>
</table>
and get this result
<table>
<thead>
<th>username</th>
</thead>
<tbody>
<td>xzvdsfg</td>
</tbody>
</table>
I'm new at Twig templates
Thanks!!!!
You could cast the object to array and iterate over then. You have to create your own twig filter to casting your object to array.
{% for key, value in post|cast_to_array %}
{% endfor %}

Resources