How do I refresh a certain element within a django template?
Example:
{% if object.some_m2m_field.all %}
<h3>The stuff I want to refresh is below</h3>
<div id="the-div-that-should-be-refreshed">
{% for other_object in object.some_m2m_field.all %}
{{ other_object.title }}
{% endfor %}
</div>
{% endif %}
Lets say some other element in the page triggers a javascript that should refresh the div above. Is there a way to cause django to refresh this specific element within the template?
If not, I'll have to monkey-patch the div using regular JS or jQuery methods and not use the great power of django's template layer. Also, the above code is a simplification of the actual template, I use much of the template's power, so monkey-patching the resulting html will be a nightmare...
You could use an async request to fill the div element.
The async request is answered by Django using the template engine.
In this case, you would have to outsource the template code of the div element into a separate template file.
UPDATED WITH EXAMPLE:
Javascript:
For refreshing the view asynchronously, use JQuery for example:
$.ajax({
url: '{% url myview %}',
success: function(data) {
$('#the-div-that-should-be-refreshed').html(data);
}
});
Async View:
def myview(request):
object = ...
return render_to_response('my_template.html', { 'object': object })
Template:
{% for other_object in object.some_m2m_field.all %}
{{ other_object.title }}
{% endfor %}
You can have a look at eg. this Ajax with Django tutorial. Anyways as mentioned above you can always use django's template engine, no matter if the view is called in a normal or an ajax request! If you have to use ajax with django more frequently it makes sense to have a look at something like dajax, which is an ajax library for django (have a look at the tutorials there).
What i did was to put all the code into a set interval function, in this way I will render a location every 5 seconds
The base
setInterval(() => {
//code to execute
}, 5000);
Applying to my div
setInterval(() => {
console.log("interval")
$.ajax({
url: window.location.pathname,
async: false,
type: 'POST',
data: {
'action': 'graph_ubicacion',
'id': id
},
dataType: 'json',
}).done(function (data) {
//console.log("DEBUG 83 === ", data)
if (!data.hasOwnProperty('error')) {
//Proceso cuando se elije una ubicacion (después de tener una respuesta
dataCharArray = [
['Nombre', 'X', 'Y', 'Tipo'],
];
if (data.hasOwnProperty('todas')) {
data['todas'].forEach(function (elemento) {
dataCharArray[dataCharArray.length] = elemento;
//console.log("DEBUG 91 === ", elemento)
});
}
if (data.hasOwnProperty('target')) {
data['target'].forEach(function (elemento) {
dataCharArray[dataCharArray.length] = elemento;
console.log("DEBUG 102 === ", elemento, "\n")
console.log("DEBUG 102 === ", elemento[0], "\n")
console.log("DEBUG 102 === ", elemento[1], "\n")
console.log("DEBUG 102 === ", elemento[2], "\n")
console.log("DEBUG 102 === ", elemento[3], "\n")
});
}
if(data['todas'].length > 0 && data['target'].length > 0){
google.charts.load('current', {
'packages': ['corechart']
}
);
google.charts.setOnLoadCallback(drawSeriesChart);
}else{
if(data['todas'].length === 0 && data['target'].length === 0){
//MensajeAlerta("No hay Datos para mostrar");
console.log("No hay datos para mostrar")
}else{
if(data['todas'].length === 0){
MensajeAlerta("No hay Balizas para mostrar");
}
if(data['target'].length === 0){
MensajeAlerta("No hay Historial de datos de Pulseras para mostrar.");
}
}
}
return false;
} else {
MensajeError(data['error']);
}
}).fail(function (jqXHR, textStatus, errorThrown) {
MensajeError(textStatus + ': ' + errorThrown);
}).always(function (data) {
})
}, 5000);
Related
I am trying to scan QR code using html,javascript as shown below by nurse_home.html. I am able to scan and see the content of the QR code on the website but I can't POST the QR code output represented by
<output type='POST' id='result' name='result' placeholder='qrCodeMessage'>
in nurse_home.html.
I want to post it to the python function: nurse_qrscan in views_nurse.py so that it can be written into the database
Any help is greatly appreciated!
The following are the relevant codes:
<nurse_home.html>
{% load static %}
{% block mainbody %}
<title>Django Online Barcode Reader</title>
<meta charset="utf-8">
{% csrf_token %}
<script src={% static "js/html5-qrcode.min.js" %}></script>
<style>
.result{
background-color: green;
color:#fff;
padding:20px;
}
.row{
display:flex;
}
</style>
{% csrf_token %}
<div class="row">
<div class="col">
<div style="width:500px;" id="reader"></div>
</div>
<div class="col" style="padding:30px;">
<h4>Scanned Result</h4>
<!--<div id="result" name="result">Result Here</div>-->
<output type="POST" id="result" name="result" placeholder="qrCodeMessage">
{% csrf_token %}
</div>
</div>
<script type="text/javascript">
function onScanSuccess(qrCodeMessage) {
document.getElementById('result').innerHTML = '<span class="result">'+qrCodeMessage+'</span>';
}
function onScanError(errorMessage) {
//handle scan error
}
var html5QrcodeScanner = new Html5QrcodeScanner(
"reader", { fps: 10, qrbox: 250 });
html5QrcodeScanner.render(onScanSuccess, onScanError);
</script>
{% endblock %}
Edited <script> tag
function getCookie(name) {
let cookie = document.cookie.match("(^|;) ?" + name + "=([^;]*)(;|$)");
return cookie ? cookie[2] : null;
}
function onScanSuccess(qrCodeMessage) {
document.getElementById("result").innerHTML = '<span class="result">' + qrCodeMessage + "</span>";
sendQrCode(qrCodeMessage);
}
async function sendQrCode(qrCode) {
const response = await fetch("/nurse_qrscan", {
method: "POST",
headers: {
"X-CSRFToken": getCookie("csrftoken"),
},
body: JSON.stringify({
result: qrCode,
}),
})
.then((response) => response.json())
.then((data) => {
console.log(data)
axios.post(ToDJ("nurse_qrscan")) //**Newly added**
}
);
}
function onScanError(errorMessage) {
//handle scan error
}
var html5QrcodeScanner = new Html5QrcodeScanner("reader", {
fps: 10,
qrbox: 250,
});
html5QrcodeScanner.render(onScanSuccess, onScanError);
<views.py>
def nurse_home(request):
return render(request, 'nurse_home.html')
<views_nurse.py>
#api_view(['GET',"POST"])
# Nurse scans QR
def nurse_qrscan(request):
### Test! nurse: QR
if request.method == 'POST':
print("Hi")
result = request.POST.get("result")
print(result)
# Saving the result to database, nurse_QR
# c = connection.cursor()
# c.execute("INSERT INTO nurse_QR (output) VALUES ('{0}');".format(result))
return Action.success()
<urls.py>
from hospital import view_nurse
from . import views
urlpatterns = [
# Main Page
path('', views.login, name='login'),
path('nurse/', views.nurse_home),
path('nurse_home/', views.nurse_home),
# Nurse
path('nurseLogin', view_nurse.nurseLogin, name='nurseLogin'),
path('nurse_qrscan', view_nurse.nurse_qrscan, name='nurse_qrscan'),
]
Actual database output (image 1)
Expected database output (image 2): 36987-2480
Error obtained from print(result) - Image 3
(Since "Hi" is printed, in "view_nurse.py", it shows that "
if request.method == "POST"
is working.
However, "result" is not printed, showing that
result = request.POST.get("result")
is not working.)
Multiple POSTS in the same QR scan - Image 4
Do this in your <script> tag:
// Create a function to get the CSRF token
function getCookie(name) {
let cookie = document.cookie.match("(^|;) ?" + name + "=([^;]*)(;|$)");
return cookie ? cookie[2] : null;
}
function onScanSuccess(qrCodeMessage) {
document.getElementById("result").innerHTML =
'<span class="result">' + qrCodeMessage + "</span>";
// Call the function here
sendQrCode(qrCodeMessage);
}
async function sendQrCode(qrCode) {
const response = await fetch("/nurse_qrscan", {
method: "POST",
headers: {
"X-CSRFToken": getCookie("csrftoken"),
},
body: JSON.stringify({
result: qrCode,
}),
})
.then((response) => response.json())
.then((data) => {
// Do your thing here.
});
}
function onScanError(errorMessage) {
//handle scan error
}
var html5QrcodeScanner = new Html5QrcodeScanner("reader", {
fps: 10,
qrbox: 250,
});
html5QrcodeScanner.render(onScanSuccess, onScanError);
Let me know which part troubles you for further explanation.
Here is a breakdown.
First, you get the CSRF token from your form with the following:
function getCookie(name) {
let cookie = document.cookie.match("(^|;) ?" + name + "=([^;]*)(;|$)");
return cookie ? cookie[2] : null;
}
Second, after generating the qrcode in the onScanSuccess callback, you invoke sendQrCode function with the qr code as argument:
function onScanSuccess(qrCodeMessage) {
document.getElementById("result").innerHTML =
'<span class="result">' + qrCodeMessage + "</span>";
// Call the function here
sendQrCode(qrCodeMessage);
}
Third, you use Fetch to send a POST request to nurse_qrscan route:
async function sendQrCode(qrCode) {
const response = await fetch("/nurse_qrscan", {
method: "POST",
headers: {
// You pass the CSRF token generated from the function
"X-CSRFToken": getCookie("csrftoken"),
},
// Create an object with `result` as property
// and the `qrCode` as value.
// After that, convert it to JSON
body: JSON.stringify({
result: qrCode,
}),
})
....
It is a POST method because of method: "POST"
Following that, you write functionality to handle the data returned from your Django view:
async function sendQrCode(qrCode) {
...
.then((response) => response.json())
.then((data) => {
// Do your thing here.
});
}
Edit:
Could you elaborate on how the data returned in ".then((data) => { // Do your thing here}" can be handled? I don't quite understand what needs to be written in there?
In your nurse_qrscan view, you are returning something:
# import json at the top of the file
import json
def nurse_qrscan(request):
### Test! nurse: QR
if request.method == 'POST':
# parse the JSON data
data = json.load(request)
result = data.get('result')
print(result)
# Saving the result to database, nurse_QR
# c = connection.cursor()
# c.execute("INSERT INTO nurse_QR (output) VALUES ('{0}');".format(result))
return Action.success()
When it receives the POST request from fetch(), it will return Action.success. I can't tell if its JSON or if you want to do something with the returned value to the frontend. If you want to access the value in Frontend using JavaScript.
Assuming it is JSON, you can do this:
...
.then((response) => response.json())
.then((data) => {
console.log(data) // log the data returned from Django
});
}
In the line .then((response) => response.json()), The value returned from the view(if JSON), it is parsed into native JavaScript.
After the data is parsed, you can log it in the console or append in the DOM depending on your use case:
.then((data) => {
console.log(data) // log the data returned from Django
});
}
Here is the button's code:
{% assign p_annual = all_products[section.settings.paid_product_annual] %}
{% assign p_free = all_products[section.settings.free_product] %}
{% if section.settings.productlink1label != blank %}
<button class="btn"
type="submit"
name="paid-plan"
id="paid-plan-option-annual"
data-variant-id="{{ p_annual.selected_or_first_available_variant.metafields.subscriptions.discount_variant_id }}"
data-variant-interval-value="{{ p_annual.metafields.subscriptions.shipping_interval_frequency }}"
data-variant-interval-unit="{{ p_annual.metafields.subscriptions.shipping_interval_unit_type }}"
data-quickadd-id="{{ p_annual.selected_or_first_available_variant.id }}"
data-quickadd-properties
>
{{ p_annual.selected_or_first_available_variant.price | money_without_trailing_zeros }}{{ section.settings.productlink1label }}
</button>
{% endif %}
The code grabs the item by the ID and makes an AJAX request.
// quick add
_document.on('click', '[data-quickadd-id]', function() {
let _this = $(this);
loadingBarTrigger('start');
itemAdd(
_this.attr('data-quickadd-id'),
_this.attr('data-quickadd-properties'),
(_this.attr('data-quickadd-quantity'))
? _this.attr('data-quickadd-quantity')
: 1,
(!html.is('#cart')) ? true : false,
(html.is('#cart')) ? true : false
);
});
inside of cart function:
onst itemAdd = (variantId, properties, qty, openCart, reloadPage) => {
$.ajax({
type: 'POST',
dataType: 'html',
url: `/cart/add.js`,
data:
{
id: variantId,
quantity: qty,
properties: (properties)
? JSON.parse(properties) : null
},
error: function(data) {
console.error(data);
loadingBarTrigger('done');
},
success: function() {
loadingBarTrigger('move');
$.ajax({
url: '/cart',
dataType: 'html',
error: function(data) {
console.error(data);
loadingBarTrigger('done');
},
success: function(data) {
let minicartContent = $('#minicart-content');
let cartItemsHtml = $(data).find('#cart-content #cart-items').html();
// insert or prepend cart HTML
(minicartContent.find('#cart-items').length)
? minicartContent.find('#cart-items').html(cartItemsHtml)
: minicartContent.prepend(cartItemsHtml);
// remove giftbox content if exists
(minicartContent.find('#cart-giftbox .item-info').length)
? minicartContent.find('#cart-giftbox .item-info').remove()
: '';
loadingBarTrigger('done');
cartTotalUpdate();
// open cart
(openCart && !html.is('#cart'))
? minicartTrigger.trigger('click') : '';
(reloadPage)
? location.reload() : '';
}
});
}
});
}
I know this is possible with the AJAX API update last year. But I'm unsure how to implement it in my store. The data-variant-id only accepts one value if I'm not mistaken. And what's data-variant-id comes first gets precedence. I guess the main thing is that I'm unsure how to send json with the submit button.
Any ideas?
In a classic add product form, you can replace:
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}" disabled> with:
<input type="hidden" name="items[0][quantity]" value="1">
<input type="hidden" name="items[0][id]" value="ID_OF_YOUR_FIRST_PRODUCT_VARIANT">
<input type="hidden" name="items[1][quantity]" value="1">
<input type="hidden" name="items[1][id]" value="ID_OF_YOUR_SECOND_PRODUCT_VARIANT">
If you want to add the products in ajax, you just have to use the "FormData" object in the body of the request:
let addToCartForm = document.querySelector('form[action$="/cart/add"]');
let formData = new FormData(addToCartForm);
fetch(window.Shopify.routes.root + 'cart/add.js', {
method: 'POST',
body: formData
})
.then(response => {
return response.json();
})
.catch((error) => {
console.error('Error:', error);
});
I think you need to check and default Shopify documentation and make changes to the code according to the documentation.
Here into documentation they clearly mentioned how you can add multiple product using AJAX API.
https://shopify.dev/docs/themes/ajax-api/reference/cart
So you can check and update the code and past the multiple variants to items array like this demo code.
jQuery.post('/cart/add.js', {
items: [
{
quantity: quantity,
id: 1st ID
},
{
quantity: quantity,
id: 2nd ID
},
{
quantity: quantity,
id: 3rd ID
}
]
});
i'm struggling to make ajax function that change the boolean value of an object without refreshing the page.
It returns error 500.
Model:
class Donation(models.Model):
is_taken = models.BooleanField(default=False)
HTML:
<div style="width: 50%; float:left" class="steps--container">
{% for d in taken %}
<div style="width: 80%; float: left">
<h4>{{d.quantity}} bags of {% for c in d.categories.all %} {{c}} {% endfor %} by {{d.user.first_name}} {{d.user.last_name}} </h4>
<input type="text" id="donation_id" value={{d.id}} hidden>
</div>
<div style="width: 20%; float:right">
<input type="button" onclick="updateStatus()" value="{{d.id}}" Mark as not taken>
</div>
<br>
{% endfor %}
</div>
JS:
function updateStatus() {
var dId = document.getElementById("donation_id").value;
var dIdInt = parseInt(dId, 10)
$.ajax({
type: "GET",
url: "/ajax/taken_or_not_taken/",
data: {
"donation_id": dIdInt
}
}).done(function(e){
console.log("done")
console.log(dIdInt)
})
.fail(function(e){
console.log('error')
console.log(e)
})
}
View:
def taken_or_not_taken(request):
obj = request.GET.get('donation_id', '')
print(obj)
return JsonResponse(obj)
Url:
url(r'^ajax/taken_or_not_taken/$', views.taken_or_not_taken, name='taken_or_not_taken'),
How can i make it works?
The full stacktrace says :
line 121, in taken_or_not_taken return JsonResponse(obj)
line 555, in __init__'In order to allow non-dict objects to be serialized set the the safe parameter to False.'
JsonResponse() should have a dict in argument and you pass an integer.
You can use the donation_id name:
def taken_or_not_taken(request):
obj = request.GET.get('donation_id', '')
print(obj)
return JsonResponse({'donation_id':obj})
Or use the safe=False parameter : https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.JsonResponse
Yea, i found it out, thanks guys anyway,
But the new problem appeared.
User still needs refresh the page to see the changes.
How to do it without refreshing page? Can i do it in django view?
Like:
def taken_or_not_taken(request):
obj = request.GET.get('donation_id')
data = {
"id": obj
}
donate = Donation.objects.get(id=obj)
if donate.is_taken == True:
donate.is_taken = False
donate.save()
elif donate.is_taken == False:
donate.is_taken = True
donate.save()
return JsonResponse(data)
You can use ajax "POST" method to send the query to the server without refreshing the page.
$.ajax({
type: "POST",
url: "url_of_query",
data: {
// Data you want to update
}
success: function(){
console.log("Success msg");
},
error: function(){
console.log("error");
},
)}
I am a little bit stuck on my Symfony code.
Let me explain,
I have a todo-list table in my database containing :
An ID called : id
A name field called : todo
And 3 others fields that don't matter : "completed", "created_at", "updated_at".
Before going further : here is my codes,
The concerned Controller :
/**
* #Route("/todos/delete/{id}", name="todo.delete", methods={"POST"})
* #param Todo $todo
* #param ObjectManager $manager
* #param Request $request
* #return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function delete(Todo $todo, ObjectManager $manager, Request $request)
{
$manager->remove($todo);
$manager->flush();
if ( $request->isXmlHttpRequest()) {
return $this->redirectToRoute('todo.home', [
'id' => $todo->getId()
]);
}
throw $this->createNotFoundException('The todo couldn\'t be deleted');
}
The view :
{% extends 'base.html.twig' %}
{% block title %}Todos{% endblock %}
{% block content %}
<br>
<form action="{{ path('todo.create') }}" method="post">
<input type="hidden" name="token" value="{{ csrf_token('todo-create') }}"/>
<label for="todo">Todo</label>
<input type="text" id="todo" name="todo" class="form-control input-group-lg" placeholder="Create a new todo">
</form><br>
{% for todo in todos %}
{{ todo.todo }}
Update
x
{% if todo.completed %}
Completed !
{% else %}
Mark as completed
{% endif %}
<hr>
{% endfor %}
{% endblock %}
We focus on :
x
The JavaScript :
$(document).ready(function () {
$('.js-delete-todo').on('click', function (e) {
e.preventDefault();
var url = $(this).attr('href');
delTodo(url);
function delTodo(url) {
$.ajax({
type: "POST",
url: url
}).done(function (data) {
$('#id').remove();
}).fail(function () {
alert('Could not be deleted');
});
}
});
});
Actually,
Everything seems to work : it does a POST ajax request, and delete the row in my table in my database.
The only issue is that I have to hit F5 to see it.
How can I make it work without reloading the page nor hitting the F5 hotkey?
In your symfony code you should return JSON format like here.
Wrap your todo in container like this
{% for todo in todos %}
<div id="todo-{{todo.id}}">
// your todo staff here
</div>
{% endfor %}
Then change your javascript to
function delTodo(url) {
$.ajax({
type: "POST",
url: url
}).done(function (data) {
var id = JSON.parse(data).id;
$('#todo-' + id).remove();
}).fail(function ()
alert('Could not be deleted');
});
}
I'm trying to create a dynamic 2-step form using Jquery where in "step 1", I want to submit the form data without refreshing my page so that I can hide my html division containing my form and show the other representing my step 2 using Jquery.
The problem is that I'm using a collection of forms in my controller action like this:
public function indexAction(Request $request)
{
$user = $this->getUser();
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository('ATPlatformBundle:NoteDeFrais');
$form = $this->get('form.factory')->createBuilder(FormType::class)
->add('ndf', CollectionType::class,array(
'entry_type' => NoteDeFraisType::class,
'label' => false,
'allow_add' => true,
'allow_delete' => true,
))
->getForm();
And I'm getting the forms data submitted from like this:
if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()
&& isset($_POST['next_button'])) {
$notesDeFrais = $form['ndf']->getData();
foreach ($notesDeFrais as $ndf) {
$ndf->setUser($user);
$em->persist($ndf);
}
$em->flush();
}
elseif (isset($_POST['validate_button'])) {
foreach ($listNdf as $ndf) {
$ndf->setSubmitted(true);
}
$em->flush();
}
So what I wanted to know is how to send my data via an ajax request and how to get them from my action. So far I tried to proceed like this but it (logically) doesn't work.
$("div#bloc_validation").css("display", "none");
$("#next_button").click(function(){
$(".form_ndf").each(function(){
$.post("{{ path('platform_homepage') }}",
{ndf: $(this).serialize()}, //My issue is here
function(){
alert('SUCCESS!');
}
);
});
$("div#form_bloc ").css("display", "none");
$("div#bloc_validation").css("display", "block");
});
Do you have any ideas ? Thanks in advance
The most basic approach is this:
add a javascripts block in your twig file with the content as below.
Change appbundle_blog in the first line inside the .ready() function in the name of your form. (Inspect your html to find it).
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(edit_form) }}
{{ form_widget(edit_form) }}
<input type="submit" value="Save Changes" />
{{ form_end(edit_form) }}
{% endblock %}
{% block javascripts %}
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous">
</script>
<script>
$(document).ready( function() {
var form = $('form[name=appbundle_blog]');
form.submit( function(e) {
e.preventDefault();
$.ajax( {
type: "POST",
url: form.attr( 'action' ),
data: form.serialize(),
success: function( response ) {
console.log( response );
}
});
});
});
</script>
{% endblock %}
If the form has been submitted you have to answer to an AJAX request. Therefore you could render another template..
/**
* Displays a form to edit an existing blog entity.
*
* #Route("/{id}/edit", name="blog_edit")
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Blog $blog)
{
$editForm = $this->createForm('AppBundle\Form\BlogType', $blog);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
/* render some new content */
return $this->render('blog/ajax.html.twig', array(
'blog' => $blog,
));
}
return $this->render('blog/edit.html.twig', array(
'blog' => $blog,
'edit_form' => $editForm->createView(),
));
Or answer in JSON:
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* Displays a form to edit an existing blog entity.
*
* #Route("/{id}/edit", name="blog_edit")
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Blog $blog)
{
$editForm = $this->createForm('AppBundle\Form\BlogType', $blog);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
return new JsonResponse(array(
'status' => 'success',
// ...
));
}
return $this->render('blog/edit.html.twig', array(
'blog' => $blog,
'edit_form' => $editForm->createView(),
));
}
If you want you can even test if the request is an AJAX request or not:
if($request->isXmlHttpRequest()) {
// yes it is AJAX
}