How do I include a break in a string in HTML? - javascript

To simplify things, I'm writing code using Nunjucks where I am passing a collection of strings to a function, where that function will then display those strings. Something like this:
{% macro Function(strings) %}
{% for item in strings %}
<div>{{ item.string }}</div>
{% endfor %}
{% endmacro %}
{% set example = [
{string: 'Hello,'},
{string: 'it is nice'},
{string: 'to meet you!'}
]%}
{{ Function(strings=example)}}
I want to be able to add a break tag or new line character in some of these strings, but every time I do the new line isn't displayed. It'll end up like this:
input: {string: 'it is\nnice'}
output: it is nice
or this:
input: {string: 'it is<br>nice'}
output: it is<br>nice
What am I doing wrong?

You're close, but with a little more structure and tooling with your macros, and the built in 'safe' filter, you can pull it off...
Using a loop to display your full predefined set:
{# STEP 1 - define your strings the way you want with set...#}
{% set mStrings = [
{stringval: 'Hello,'},
{stringval: 'it is<br> nice'},
{stringval: 'to meet you!'}
]%}
{# STEP 2 - create a macro function to help display/decor the data back into our template #}
{# notice the use of 'safe' to allow your string to not be esacped #}
{% macro collection(gStrings) %}
<ul>
{% for gString in gStrings %}
<li>{{ gString.stringval|safe }}</li>
{% endfor %}
</ul>
{% endmacro %}
{# STEP 3 - finally, from within your template, call your macro function, with the correct parameter, like so!...
{{collection(gStrings=mStrings)}}
#}
Adding custom parameter string data on the fly :
{# With a lighter approach, start our with your macro function...#}
{% macro entry(entryItem) %}
{{ entryItem|safe }}
{% endmacro %}
{# from within your template, call your macro function, with the correct parameter, like so!... #}
{{entry("lets say<br>something")}}
{{entry("lets eat<br>something")}}
...etc...

Related

'first_time_accessed' Shopify liquid variable is always false

I'm trying to use the first_time_accessed liquid variable in my checkout.liquid Shopify template to decide whether or not to push certain data to an array, like so:
config.elements.push({
id: prodId,
price: prodPrice,
quantity: prodQty,
{% if first_time_accessed %}
{% assign last_purchase_date = "January 1, 1970" %}
{% for order in customer.orders %}
{% if (order.order_number != checkout.order.order_number) and (order.created_at > last_purchase_date) %}
{% assign last_purchase_date = order.created_at %}
{% endif %}
{% endfor %}
{% assign raw_new_customer_boundary = 'now' | date: "%s" | minus : 46656000 /* 540 days */ %}
{% assign raw_last_purchase_date = last_purchase_date | date: "%s" | minus: 0 %}
new_customer: {% if raw_new_customer_boundary > raw_last_purchase_date %}true{% else %}false{% endif %},
{% endif %}
});
However, every time I test this code I can see that first_time_accessed is always false. I've also tested this by putting similar code on other pages and it always equates to false. I've tested it in incognito mode with a VPN and same thing.
I'm wondering if anyone has any idea why first_time_accessed is always false? I'm sure it has to do with some misunderstanding on my end about how this variable works, but there's very little info on Shopify's docs about it.

How do i create and use variables in django

New to Django and its templates.
I'm trying to set a variable given a specific situation, and that part I think ill be able to do, the code below isn't the exact conditions its just there as a demo. The part im stuck on is how do i create a variable name, and then use that name variable elsewhere. Such as within a div or within a method or anywhere else within the html file, and withing different <Script> tags to run methods and for really any purpose.
demo scenario :
{% for row in table.rows %}
{% if row == 2 %}
{% var name = row.name %}
{% endif %}
{% endfor %}
{% if name %}
<div>{{name}}</div>
{% endif %}
my actual code Im trying to implement:
<script type="text/javascript">
function map_init_basic(map, options) {
var markerClusters = L.markerClusterGroup({ chunkedLoading: true });
{% for row in table.rows %}
var x = "{{ row.cells.x }}"
var y = {{ row.cells.y }}
var m = L.marker([y, x])
m.bindPopup("{{row.cells.first_name}} {{row.cells.last_name}} <br>{{row.cells.chgd_add}}");
m.on("click" , ()=>{
//console.log(`${first_name} ${last_name}`)
{% var first_name = {{row.cells.first_name}} %}
})
//changed row.cells.chgd_add to row.cells.Chgd_add to make sure its matching the table
markerClusters.addLayer(m);
{% endfor %}
markerClusters.addTo(map);
}
{% if first_name %}
console.log("{{first_name}}");
{% endif %}
</script>
Django templates are intended to render html but you are trying to render javascript. It can work but the way you are trying to do it is not a good practice; very soon you won't be able to maintain your code.
If you want to pass data directly from python/django to javascript, an accceptable way to do so is to put the data in a dictionary, translate it to a json string and have it set to a var in your javascript.
in a view:
data = dumps(some_dictionary)
return render(request, 'main/template.html', {'data': data})
in the template:
<script>
var data = JSON.parse("{{data|escapejs}}");
</script>
https://docs.djangoproject.com/fr/3.1/ref/templates/builtins/#escapejs
Alternative: You can use django to generate a widget with data attributes and have a javascript operating on this widget and do whaterever needs to be done.

Adding python variables to jinja counter

I want to add the python variables from flask in the jinja template
Suppose 'a' is a python variable(a list of int values) brought into the jinja template using render_template function from flask :
{%set count = 0%}
{%for element in a%}
{%set count = count + element%}
{%endfor%}
{{ count }}
The value of 'count' should be updated but it still prints 0 on the screen
Can anyone help me?
In the most recent versions, due to scoping rules, your version doesn't work.
Instead, you could do something like this:
{% set count = namespace(value=0) %}
{% for element in a %}
{% set count.value = count.value + 1 %}
{% endfor %}
{{ count }}

How to set an item to be the first in a for loop in Liquid if a condition is met

I have a for loop in Liquid which loops through customer addresses. What I would like to do is make the address which has been set as the default (customer.default_address) as the first address to appear in the loop. I currently add a default tag to the default address but struggling to make it the first to appear.
I tried using 'sort' but with no luck.
My current code is below.
Any help would be much appreciated.
{% assign sortedAddresses = customer.addresses | sort: 'customer.default_address' %}
{% for address in sortedAddresses %}
<div class="address">
{{ address | format_address }}
{% if address == customer.default_address %}
<div class="default">DEFAULT</div>
{% endif %}
</div>
{% endfor %}
You have default_address as a property of customer and Im guessing customer.addresses is an array of strings. If you were to make customer.addresses an array of objects instead... with string property for address and true/false property for default, then you could do something like:
{% assign default_address = customer.addresses | where: "default", true %}
{% assign address_array = default_address | concat: customer.addresses %}
{% assign customer.addresses = address_array | uniq %}

javascript - dry - nested if statement

I am new to coding, but have been reading about DRY - Don't Repeat Yourself.
I have a JavaScript if/else statement that does not fit the DRY approach, but I am unable to workout how to write the JavaScript if/else statement so that the contents are not repeated.
I am hoping some one smarter than me can show me.
Here is my code:
{% if user.get_profile.subscription_category == '00' %}
$('#id_name_details_prefix_title').addClass('kmw-disabled');
$('#id_name_details_first_name').addClass('kmw-disabled');
$('#id_name_details_middle_name').addClass('kmw-disabled');
$('#id_name_details_last_name').addClass('kmw-disabled');
$('#id_name_details_suffix_title').addClass('kmw-disabled');
{% else %}
{% if user.get_profile.display_virtual_keyboard %}
$('#id_name_details_prefix_title').removeClass('kmw-disabled');
$('#id_name_details_first_name').removeClass('kmw-disabled');
$('#id_name_details_middle_name').removeClass('kmw-disabled');
$('#id_name_details_last_name').removeClass('kmw-disabled');
$('#id_name_details_suffix_title').removeClass('kmw-disabled');
{% else %}
$('#id_name_details_prefix_title').addClass('kmw-disabled');
$('#id_name_details_first_name').addClass('kmw-disabled');
$('#id_name_details_middle_name').addClass('kmw-disabled');
$('#id_name_details_last_name').addClass('kmw-disabled');
$('#id_name_details_suffix_title').addClass('kmw-disabled');
{% endif %}
{% endif %}
The contents of the 1st if are repeated in the else of the 2nd if statement - I am hoping that I only have to write the repeated contents once.
You can put your selectors in an array
var selectors = [#id_name_details_prefix_title', '#id_name_details_first_name' ...];
and then add/remove class
$(selectors.join(',')).addClass('kmw-disabled')
Break it up into functions that isolate what's going on.
{% if something %}
functionThathAddsClass();
{% else %}
{% if something_else %}
functionThatRemovesClass();
{% else %}
functionThathAddsClass();
{% endif %}
{% endif %}
You will run into the problem of creating two global functions in this case, but that's a different issue.
I like to make, what I personally call, CSS Guards.
A CSS Guard is basically just an object that has functions that pokes and prods at the DOM.
var NameDetailsGuard = {
functionThathAddsClass = function () {
$('#id_name_details_prefix_title').addClass('kmw-disabled');
$('#id_name_details_first_name').addClass('kmw-disabled');
},
functionThatRemovesClass = function () {
$('#id_name_details_prefix_title').removeClass('kmw-disabled');
$('#id_name_details_first_name').removeClass('kmw-disabled');
}
};
and you use it like this
NameDetailsGuard.functionThatAddsClass();
An added benefit to this is that if you expand on this concept you can start doing simpler DOM node caching within this object so that instead of querying for the selector everytime you'll retain a reference to it and manipulate that.
You can add some class to needed elements (in HTML markup) and select by that class.
For example, add category-zero and virtual-keyboard classes and use following:
{% if user.get_profile.subscription_category == '00' %}
$('.category-zero').addClass('kmw-disabled');
{% else %}
{% if user.get_profile.display_virtual_keyboard %}
$('.virtual-keyboard').removeClass('kmw-disabled');
{% else %}
$('.virtual-keyboard').addClass('kmw-disabled');
{% endif %}
{% endif %}

Categories

Resources