How to get twig variable after ajax call - javascript

I use nodejs to do a personal project (and learn nodejs).
For the view I use twig.
In my index.html.twig I have a block which load a twig template. This is a list that displays all rows of my database.
<div id="table">
{% include 'liste.html.twig' %}
</div>
In this template I have a variable called "segment"
{% for key, s in segment|slice(0, 10) %}
...
{% endfor %}
I did a pagination system to displays only 10 rows => it work
let up = document.getElementById('up');
let pageA = 1
var segments = {{ segment|json_encode()|raw }}
up.addEventListener('click', function(){
let tbody = document.getElementById("tbody")
tbody.innerHTML = ""
pageA++;
for(let i=(pageA-1)*10;i<pageA*10;i++){
let dist = segments[i]['distance']/1000
tbody.innerHTML += "<tr><td>"+segments[i]['name']+"</td><td>"+segments[i]['nbSegment']+"</td><td>"+dist.toFixed(2)+"km</td><td>"+segments[i]['total_elevation_gain']+"m</td><td>"+segments[i]['average_grade']+"%</td><tr>"
}
addRowHandlers();
})
I have also a field to do a specific research. To do that I used ajax and reload only this block => It work also. My table displays 10 first results of my research
app.get('/search', urlencodedParser, function(req, res) {
req.query.page = 1
getSegmentsByNameDb(escapeHtml(req.query.name)).then(value => {
res.render('liste.html.twig', {segment:value})
})
});
My problem is that I can't get the new twig variable "segment" after the research and so my pagination doesn't work.
When I do a console.log(segment) it displays all the rows of the DB and not only the rows of the research.
Why the twig variable segment is not reset when my template liste.html.twig is reload ?

Related

How to display django queryset values in templates using javascript

I am trying to display list of names from a django queryset using , Here is my code
def vfunc(request):
context={}
bats = Bat.objects.all().order_by('-id')
context['bats'] = bats
[each.batname for each in bats] # Gives all the batnames.
return render(request, 'bat.html', context)
I want to display batnames on template
$(function() {
//This works when I hardcode the values
var batData = [{
"bat":"batname1", //hardcoded & displayed in 1st row
}, {
"bat":"batname2", //hardcoded & displayed in 2nd row
}];
$("#CleanDatasNames").dxDataGrid({
dataSource: batData,
...
...
}
I am tried something like var batData = [{"bat":"{{bats|join:', ' }}"] but it is displaying obj1,obj2 in same row,I also tried to loop through but failed , any help will appreciated.
This way you can work with js:
$(function() {
//This works when I hardcode the values
var batData = [
{% for bat in bats %}
{
"bat":"{{bat}}",
}
{% if forloop.counter != bats|length %} // dynamically checking for last element
,
{% endif %}
{% endfor %}
];
$("#CleanDatasNames").dxDataGrid({
dataSource: batData,
...
...
}

How to create Flask-Stripe Checkout and Charge for the multiple items

I am building an integration with Stripe by following the examples in its documentation, but I can't understand the part of creating a Charge for more than one product.
I was looking all over Stripe's docs and was searching for any articles / forums about the similar issue but was unable to find anything. I'd be very grateful to either some links to the articles on this matter or any tips to help me to understand how to solve it.
Here's a server side code:
```python
#app.route("/checkout", methods=["GET", "POST"])
def checkout():
if request.method == "POST":
# Process a JSON string with a checkout information:
# { item_id: item_quantity, ... }
# Build the SQL query based on it
items = {}
shopping_cart = request.form["cart_checkout"]
shopping_cart = shopping_cart.lstrip("{")
shopping_cart = shopping_cart.rstrip("}")
shopping_cart = shopping_cart.split(",")
sqlQuery = "SELECT * FROM Items WHERE item_id IN ("
for KeyValPair in shopping_cart:
Key = KeyValPair.split(":")[0]
Key = Key.strip('"')
sqlQuery = sqlQuery + Key + ","
Value = KeyValPair.split(":")[1]
items[Key] = Value
sqlQuery = sqlQuery.rstrip(",")
sqlQuery = sqlQuery + ") ORDER BY item_id ASC"
cart_items = sql_select(sqlQuery)
# Add a column about the quantity of items
for item in cart_items:
item["quantity"] = items[item["item_id"]]
# Build a Stripe checkout list
line_items_list = []
for item in cart_items:
line_item = {}
line_item["name"] = item["item_name"]
line_item["description"] = item["item_description"]
line_item["amount"] = item["price"]
line_item["currency"] = "usd"
line_item["quantity"] = item["quantity"]
line_items_list.append(dict(line_item))
stripe_session = stripe.checkout.Session.create(
submit_type="pay",
payment_method_types=["card"],
line_items=line_items_list,
success_url='https://example.com/success',
cancel_url='https://example.com/cancel',
)
return render_template("checkout.html",
stripe_id=stripe_session.id,
stripe_pk=stripe_keys["PUBLIC_KEY"])
return redirect("/")
```
And here's a part of HTML template:
```html
<form action="/checkout" method="post" id="form_checkout" onsubmit="return cart_info()"
...
<input type="hidden" name="cart_checkout" id="checkout_info" value="{{ cart_checkout }}">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ stripe_pk }}"
data-name="Company Name"
data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
data-description="A description of the product or service being purchased"
data-amount="999"
data-shipping-address="true"
data-zip-code="true"
data-allow-remember-me="true"
data-panel-label="Pay"
data-label="Checkout"
data-locale="auto">
</script>
</form>
```
If I do a simple example of Charge from Stripe docs, like this:
```python
#app.route('/charge', methods=['POST'])
def charge():
# Amount in cents
amount = 500
customer = stripe.Customer.create(
email='customer#example.com',
source=request.form['stripeToken']
)
charge = stripe.Charge.create(
customer=customer.id,
amount=amount,
currency='usd',
description='Flask Charge'
)
return render_template('charge.html', amount=amount)
```
Then I can create without any issues a successful test Charge, it displays with the success label in my Stripe's dashboard. If I use stripe.checkout.Session.create, Stripe dashboard properly creates an incomplete record about my Checkout session with the selected list of items, but I've no idea how to proceed from there to finalise the Charge for them.
As often happens, when I start asking questions, I eventually find the answers on my own, lol. I've had a "checkout.html" template but it didn't work, and no errors were displaying, so I assumed that I was missing some more code required for it all to work.
As it happened, all I was missing, was "" in a line of code. Here's a working Checkout session with the addition of a bit of JavaScript:
{% extends "layout.html" %}
{% block title %}Checkout{% endblock %}
{% block head %}
<script src="https://js.stripe.com/v3/"></script>
{% endblock %}
{% block main %}
<!-- Main content -->
<div class="wrapper main-content">
{% with messages = get_flashed_messages(with_categories=true) %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endwith %}
<h2 class="section-header">Checkout</h2>
<p id="result_msg"></p>
<button onclick="checkout()">Checkout</button>
</div>
<script type="text/javascript">
function checkout() {
var stripe = Stripe("{{ stripe_pk }}");
stripe.redirectToCheckout({
// Make the id field from the Checkout Session creation API response
// available to this file, so you can provide it as parameter here
// instead of the {{CHECKOUT_SESSION_ID}} placeholder.
sessionId: "{{CHECKOUT_SESSION_ID}}"
}).then(function (result) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer
// using `result.error.message`.
document.getElementById("result_msg").innerHTML = result.error.message;
});
}
</script>
{% endblock %}

Updating a twig var inside a function

I'm trying to work with twig and javascript. I'm just trying to define a var and update the value inside a click function. Unfortunatelly, the var seems to be updated, but the new value is not updated when the scope of the function ends, so the console log writes 1 the first time and 2 each time I enter in the click function.
Which is the better way to do this?? Thanks in advance
{% set actual_index = 0 %}
{% set num_elements = 3 %}
addNewEvents();
{% set actual_index = actual_index + 1 %}
console.log({{ actual_index }})
$("#load").click(function () {
addNewEvents();
{% set actual_index = actual_index + 1 %}
console.log({{ actual_index }})
});
How to do it cleanly? Separate twig from your javascript. They were not intended to be used together (even though it can work).
You have multiple different ways to retrieve the information for your js. Either use twig and store the information in a hidden input, or get the information with an AJAX call.
for example:
var actual_index = -1;
var num_elements = 0;
$.getJSON('ur_here', function(data){
actual_index = data.actual_index;
num_elements = data.num_elements;
});
But it seems to go further than that, you understand that twig generates HTML server side and sends it to the client? This happens only once.
That means your variable you set only exists server side right? That means that when you do {{ actual_index }} it just generates a number client side and not a variable.
{% set actual_index = 0 %}
{% set num_elements = 3 %}
The two above variables exist server side right before twig generates your HTML and sends it to client.
Here is what your js should look like without twig:
var actual_index = 0;
var num_elements = 3;
addNewEvents();
actual_index = actual_index + 1;
console.log(actual_index)
$("#load").click(function () {
addNewEvents();
actual_index = actual_index + 1;
console.log(actual_index);
});
EDIT:
Answering your comment.
"{{ asset( path('event_values', { 'programmerid': programmerid, 'actual_index': actual_index, 'num_elements':num_elements } ))|raw }}
If the above generates an URL then you're on the right path (otherwise check this post How Generating URLs from a template correctly in Symfony2/Twig ).
Now, the first parameter of the getJSON is an URL, and the second parameter is the callback.
Remember that your {{ asset... }} should generate an URL that can be called on the client side.
So after your twig generates your HTML the URL should look something like this:
$.getJSON('http//:localhost/path/to/your/ajaxHandler.php', function(data){
//this is called when you return data from your ajaxHandler.php
//do something with data
});
This way, when you click ajaxHanlder.php is called and you can send back the information back in json ( echo json_encode(You array here); )

Django: Referencing Views List in Java Script?

So I'm working with Django on a website that I am playing around with, and have been trying to research how I could get the following list in my views.py and be able to reference it in my javascript? I'm working on creating an ajax call and the tutorials I am coming accross are a bit confusing.
#lines 6 - 8 of my code.
def catalog_home(request):
item_list = item.objects.order_by('name') #item is the model name
note: the item model containts a name, description, overview and icon column.
Is it possible for me to use the list above (item_list) and be able to write a javascript function that does something similar to this? :
$(document).ready(function() {
$("#showmorebutton").click(function() {
$("table").append("<tr></tr>");
for (var i = 0; i < 3; i++) {
var itemdescription = item.description;
var itemName = item.name;
var icon = item.icon;
$("table tr:last").append(generateCard(itemName,
itemdescription,
icon));
}
function generateCard(itemNameC, itemdescriptionC, iconC) {
var card = "<td class='tablecells'><a class='tabletext' href='#'><span class='fa "
+ iconC
+ " concepticons'></span><h2 class='header'>"
+ itemNameC
+ "</h2><p>"
+ itemdescripionC
+ "<span class='fa fa-chevron-circle-right'></span></p></a></td>";
return card;
}
I don't mean to crowd source the answer to this, I just would appreciate any feedback/advice for me to handle this task, as I am fairly new to coding.
You should absolutely be able to do this. The trick is to understand Django templates. You showed part of the view but you will need to render to a template. Inside the template, you can just do something like
HTML code for page goes here (if you're mixing js and html)
<script>
var items = [{% for d in data %}
{% if forloop.last %}
{{ d }}
{% else %}
{{ d }},
{% endif %}
{% endfor %}];
// code that uses items
</script>
Note there's a little bit of work required to make sure you have the right # of commas [taken from this SO answer and your code should handle the case where the array is empty.
Alternatively, you could do an ajax call from static javascript to your django server using something like django rest framework to get the list of items as a json object.

New forms - embedding a collection of forms - Symfony2

I'm doing the same as explained here: http://symfony.com/doc/current/cookbook/form/form_collections.html
But in my case I want to add new "tags" not manually with clicking on a link, but automatically. I give to my template an array with items and for each of this items I want to add a new form - the number of items should be equal to the number of forms.
If it's possible, I'd prefer a solution like this:
{% for i in items %}
{{ i.name }} {{ form_widget(form.tags[loop.index0].name) }}
{% endfor %}
But how to automatically create objects in the controller, too? It tells me that there is no obeject with index=1, and yes - there isn't, but isn't there a way to create them automatically and not need to create for example 10 empty objects of the same kind in my controller? :(
Another thing I was thinking was something like this:
{% for i in items %}
<ul class="orders" data-prototype="{{ form_widget(form.orders.vars.prototype)|e }}">
{{ i.name }} and here should be a field from the form, for example tag.name
</ul>
{% endfor %}
I suggest that the js given in the cookbook should be changed to do this, but I'm not good in js and my tries didn't do the job.
I tried putting this in the loop:
<script>
addTagForm(collectionHolder);
</script>
and this in a .js file:
var collectionHolder = $('ul.orders');
jQuery(document).ready(function() {
collectionHolder.data('index', collectionHolder.find(':input').length);
function addTagForm(collectionHolder) {
var prototype = collectionHolder.data('prototype');
var index = collectionHolder.data('index');
var newForm = prototype.replace(/__name__/g, index);
collectionHolder.data('index', index + 1);
var $newFormLi = $('<li></li>').append(newForm);
}
});
Assuming that your main class has addTag($tag) method, you can add different 'new' tags to it.
In class Task
public function addTag($tag){
$this->tags[]=$tag;
return $this;
}
In your Controller (assuming 10 tags here)
$task=new Task();
for($i=0;i<10;i++){
$task->addTag(new Tag());
}
$form->setData($task);
In your view
{% for tag in form.tags %}
<ul class="orders">
<li>{{ form_widget(tag.name) }}</li>
</ul>
{% endfor %}
If you don't need the manually click, you can remove the JavaScript part.

Categories

Resources