Refresh HTML table values in Django template with AJAX - javascript

Essentially, I am trying to do the same thing as the writer of this and this
was trying to do.
Which is to dynamically update the values of an html template in a django template via an ajax call.
Both of them managed to fix their issue, however, I am unable to do so after 1.5 days.
index.html
{% extends 'app/base.html' %}
{%load staticfiles %}
{% block body_block %}
<div class="container" >
{% if elements %}
<table id="_appendHere" class="table table-bordered">
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>User</th>
<th>Date</th>
</tr>
{% for e in elements %}
<tr>
<td>{{e.A}}</td>
<td>{{e.B}}</td>
<td>{{ e.C }}</td>
<td>{{ e.D }}</td>
<td>{{ e.User }}</td>
<td>{{ e.Date }}</td>
</tr>
{% endfor %}
</table>
{% else %}
No data to display! <br/>
{% endif %}
</div>
{% endblock %}
<script>
var append_increment = 0;
setInterval(function() {
$.ajax({
type: "GET",
url: "{% url 'get_more_tables' %}", // URL to your view that serves new info
data: {'append_increment': append_increment}
})
.done(function(response) {
$('#_appendHere').append(response);
append_increment += 10;
});
}, 1000)
</script>
views.py
def index(request):
elements = ElementFile.objects.all().order_by('-upload_date')
context_dict = {'elements':elements}
response = render(request,'app/index.html',context_dict)
return response
def get_more_tables(request):
increment = int(request.GET.get('append_increment'))
increment_to = increment + 10
elements = ElementFile.objects.all().order_by('-upload_date')[increment:increment_to]
return render(request, 'app/get_more_tables.html', {'elements': elements})
get_more_tables.html
{% for e in elements %}
<tr>
<td>{{e.A}}</td>
<td>{{e.B}}</td>
<td>{{ e.C }}</td>
<td>{{ e.D }}</td>
<td>{{ e.User }}</td>
<td>{{ e.Date }}</td>
</tr>
{% endfor %}
urls.py
urlpatterns = [
path('', views.index, name=''),
path('get_more_tables/', views.get_more_tables, name='get_more_tables'),
]
in the javascript part, I tried:
url: "{% url 'get_more_tables' %}", with and without quotes
If I try to access /get_more_tables/
I get the following error:
TypeError at /get_more_tables/
int() argument must be a string, a bytes-like object or a number, not 'NoneType'
So for some reason, I get nothing, the append_increment is the empty dictionary. But why?
I tried altering the code like, but to no avail:
try:
increment = int(request.GET.get('append_increment'))
except:
increment = 0
Expectation: dynamically loading database
Outcome: error or non-dynamic loading (must refresh manually)
Million thanks to everyone who attempts to help with this.

Related

How to call a function from python inside a html loop?

I am new to web coding... I was not able to find a good solution on my own. I need to add a function in my buttons and write the function in "application.py". I can't create a new html and I would prefer not to write a script in the html, if possible. The function should use the "i.stock" of the moment since it is inside a for loop. Any help is appreciated, thanks.
My html code:
{% extends "layout.html" %}
{% block head %}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet">
{% endblock %}
{% block title %}
Your Portfolio
{% endblock %}
{% block main %}
<h2> This is your current Portfolio:</h2>
<table class="table">
<thead class="thead-light">
<tr>
<th scope="col">Symbol</th>
<th scope="col">Name</th>
<th scope="col">Shares</th>
<th scope="col">Current Price</th>
<th scope="col">Total</th>
<th scope="col">Buy</th>
<th scope="col">Sell</th>
</tr>
</thead>
<tbody>
{% for i in portfolio %}
<tr>
<th scope="row">{{ i.stock_symbol }}</th>
<td>{{ i.stock_name }}</td>
<td>{{ i.stock_shares }}</td>
<td>{{ i.stock_price }}</td>
<td>{{ i.total_amount }}</td>
<td><a type="button" class="btn btn-success" onClick="buy()">+</a></td>
<td><a type="button" class="btn btn-danger">-</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<h4> Your currently have {{cash}} available in cash </h4>
<h4> Your Total (stocks + cash) is {{total}}</h4>
{% endblock %}
My python below [the part that matters, the def index is for the table]. The i.stock here does not work (obviously you may say) any suggestions on how to fix that?
Maybe I should create another #? I will need to refresh his portfolio once he buys another stock.
#app.route("/")
#login_required
def index():
"""Show portfolio of stocks"""
...
#Function to buy stocks directly from index
def buy():
cost = float(i.stock["price"])
#Looks in the datababse for the amount of cash the user still has
query = db.execute("SELECT cash FROM users WHERE id = :id", \
id=session["user_id"])
cash = query[0]["cash"]
#See if user has enough money and handle when user does not
if cost > cash:
return apology("You don't have enough money")
#Append information to the history table
db.execute("INSERT INTO history (user_id, stock_symbol, stock_price, stock_amount, total_amount) \
VALUES (:user_id, :stock_symbol, :stock_price, :stock_amount, :total_amount)", \
user_id = session["user_id"], stock_symbol = i.stock["symbol"], stock_price = usd(i.stock["price"]), stock_amount = 1, total_amount = cost)
#Calculates new cash amount and update database
net_cash = int(cash - cost)
db.execute("UPDATE users SET cash = :new_cash WHERE id = :id", \
id = session["user_id"], new_cash = net_cash)
You can't access Python functions in HTML. Instead, you send an AJAX request to the server. To do this, you need to modificate your buy-function:
import json
from flask import request
#app.route('/buy', methods=['POST'])
def buy():
i = json.loads(request.args.get('i'))
Now you can create the actual JavaScript-buy-function that will call the Python-buy-function:
function buy() {
var i = {}; // You need to get the details
var i_json = JSON.stringify(i);
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "/buy", true);
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log("Done.");
}
};
xhttp.send(i_json);
}
Now the only thing you have left to do, is passing all the necessary information (i) to the JS-buy-function.

how to change condition in if template tag using javascript

I am trying to use some value that I get from clicking a button to be loaded in the if statement in my HTML template. but cannot do so.maybe I am doing everything wrong.
I have used var tag and placed my variable inside it but it didn't work when I tried to edit it through javascript code
{% for publication in page.get_children.specific %}
{% if publication.pub_type == <var id="varpubtype">pubtype</var> %}
{% if publication.pub_year == <var id="varpubyear">pubyear</var> %}
<tr>
<td>{{ publication.Authors }}</td>
<td>{{ publication.name }}</td
<td>{{ publication.pub_year }}</td>
<td>{{ publication.pub_journal }}</td>
<td>{{ publication.vol_issue }}</td>
<td>{{ publication.pages }}</td>
</tr>
{% endif %}
{% endif %}
{% endfor %}
here is my script
function toggletable( var pubtypevar)
{
document.getElementById("varpubtype").innerHTML = pubtypevar;
}
function toggleyear( var pubyearvar){
document.getElementById('varpubyear').innerHTML = pubyearvar;
}
when i used var and span tags it showed template error. That
Could not parse the remainder: '
it doesn't seem like that, you have to do the condition on the server not on the client, and the page reload when you click that button,
and then you use condition from server then you implementation on the client

Trying to get previous and next object in template Django

I need to get the previous & next value of the object (col2 from the object) in the same for loop iteration. Below is my index.html code:
<script>
var i = 1;
var j = 0;
</script>
{% for b in obj %}
<tr>
<td>{{ b.col1 }}</td>
<td><span class="wrapped"><span>{{ obj.j.col2 }}</span></span> </td>
<td id='myTable'></td>
<td id='myTable'></td>
<td>{{ b.col5 }}</td>
<td>{{ b.col6 }}</td>
<td>{{ b.col7 }}</td>
</tr>
<script>j=j+1;</script>
{% endfor %}
</table>
views.py:
def display(request):
return render_to_response('index.html', {'obj': my_model.objects.order_by('col2')})
What I tried was that when using: {{ obj.0.col2 }} or {{ obj.1.col2 }}, it displays the value of that cell correctly. However, when using {{ obj.j.col2 }}, it does not display anything. Why is this happening?? Why is it not reading j's value?? When I'm initializing j to 0 outside the loop and am incrementing value of j at the end of the loop as well!!

Pass an array of a twig for a jQuery

I have a block on my twig writing a table from a variable received from controller
{% block foot_informations %}
{% if ads is not empty %}
<div class="panel-foot-information row">
<table id="ads">
<thead>
<tr>
<th>Departure</th>
<th>Destination</th>
</tr>
</thead>
<tbody>
{% for ad in ads %}
<tr class="ad-tr">
<td>{{ ad.departure }}</td>
<td>{{ ad.packageType }}</td>
<td>{{ ad.transportation }}</td>
{# <td>{{ ad.date }}</td> #}
<td>select</td>
<td class="hidden"><input type="hidden" id="idLat" value="{{ ad.departureLatitude }}"/></td>
<td class="hidden"><input type="hidden" id="idLong" value="{{ ad.departureLongitude }}"/></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}
I would like to get this variable month in JQuery to manipulation it and then rewrite my table
to catch it saw something like this: var ads = {{ ads|json_encode() }};
My idea is in a evnto of button to click to change the value of the array and reconstruct the table someone help me?
$('#my_button').click(function () {
alert(ads);
$.each(ads, function(){
alert($(this));
//filter by type package
});
//rewrite table
});
First of all I would suggest that you don't mix two strategies.
is generating views serverside, what you obviously do with the twig templates.
is passing raw data (with AJAX or like your example with the json_encoded array parsed into a JS Object), and then generating the table with JS DOM manipulation.
But that's my opinion about this part.
If you choose for Option 1 you could add/remove classes in your $.each filter-like callback for the table rows you want to hide / show.
And then write something like this in your stylesheet
tr.filtered {
display: none;
}
Alternative: extend your table body like this:
<tbody>
{% for ad in ads %}
<tr data-ad-id="{{ ad.id }}" class="ad-tr">
<td>{{ ad.departure }}</td>
{# all the other td's #}
</tr>
{% endfor %}
</tbody>
And you Clickhandler:
$('#my_button').click(function() {
//alert(ads);
$.each(ads, function(index, ad) {
if (ad.packageType == 'some_package_type') {
$('table#ads tr[data-ad-id=' + ad.id + ']').hide();
}
});
// rewrite table
// Perhaps there is no need for anymore
});
EDIT:
If you have a javascripts block in your base template, you could do this to expose an ads array to the global JS scope (just like you said in the question, about what you have seen):
{% block javascripts %}
{{ parent() }}
<script>
var ads = {{ ads|json_encode() }};
</script>
{% endblock %}

How do I code a count for double nested for loop?

I'm trying to pass just the piece number to my html. This will be used to update the content of a selected tag with javascript. All of my tags are created by a double nested for loop in django. But from what I've tried I've had no success.
Here is the javascript code:
$('td#'+new_data['piece_number']).html(new_data['img']);
Here is the double nested for loop in question:
<table id="table" bgcolor="{{puzzle.color_hash}}">
<tbody>
{% for x in n_rows %}
<tr id='r{{x}}'>
{% for y in n_cols %}
<td id='{{count}}' height='{{puzzle.piece_res_height}}' width='{{puzzle.piece_res_width}}'>
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
I want the total iteration count in {{count}} but from my understanding django doesn't let you have variable manipulation in the renderer
I'm looking for a result such as a row by column table...
1 2 3
4 5 6
7 8 9
Where there are 3 rows and 3 columns. 9 pieces. each with a td id of the piece number
i.e. row 2 column 2 has a td id of 5
You can send two wariables instead one count to html file and change ida of id naming.
<td id='r{{x}}d{{y}}' height='{{puzzle.piece_res_height}}' width='{{puzzle.piece_res_width}}'>
Edit - right solution
Ok, I have two solutions for you.
Both use custom template filters.
File app/templatetags/default_filters.py
from django import template
register = template.Library()
#first way
def mod(value, arg):
return value % arg == 0
#second way
#register.filter(name='multiply')
def multiply(value, arg):
return value*arg
register.filter('mod', mod)
Context send to template
class MainSiteView(TemplateView):
template_name = "main_page.html"
def get_context_data(self, **kwargs):
context = super(MainSiteView, self).get_context_data(**kwargs)
n_rows = n_cols = 2
context['max_nums'] = n_rows * n_cols
context['n_rows'] = [0, 1]
context['n_cols'] = [0, 1]
context['number_of_columns'] = 2
context['range'] = [x for x in range(n_cols * n_rows)]
return context
And template
{% load default_filters %}
<table id="_table" bgcolor="{{puzzle.color_hash}}">
<tbody>
{% for x in range %}
{% if not forloop.counter|mod:number_of_columns %}
<tr id='_r{{x}}'>
{% endif %}
<td id='_{{forloop.counter0}}' height='{{puzzle.piece_res_height}}' width='{{puzzle.piece_res_width}}'>
({{forloop.counter0}})
</td>
{% if forloop.counter|mod:number_of_columns %}
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
<table id="table" bgcolor="{{puzzle.color_hash}}">
<tbody>
{% for x in n_rows %}
<tr id='r{{x}}'>
{% for y in n_cols %}
<td id='{{x|multiply:number_of_columns|add:y}}' height='{{puzzle.piece_res_height}}' width='{{puzzle.piece_res_width}}'>
[{{x|multiply:number_of_columns|add:y}}]
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>

Categories

Resources