Is there an alternative for onload on <select>? - javascript

I am using jinja templates to compile a form of multiple select blocks based on a template variable dictionary, like this:
{% for key, value in some_template_variable_dict.items %}
<select id="{{ key }}_selector" name="key">
{% for item in values %}
<option value="{{ item }}">{{ item }}</option>
{% endfor %}
</select>
{% endfor %}
I would like to fire the following wrapper function for selectize on all of the select blocks on loading the document:
function selectizeSingleChoice(selector) {
$('#'+selector).selectize({
sortField: 'text',
maxItems: 1,
create: false,
highlight: true,
openOnFocus: true
});
}
The select block does not have an onload event handler, and I cannot put it in a general $(document).ready(); section either, as the exact list of select blocks and their id-s is dependent on user choice. There is also an option that a slightly different version of the selectize wrapper is needed for some of them (e.g. not only one selected option allowed etc), so I cannot fire it on each and every select item either.
A working solution is to insert a script tag inside the for loop, but I dislike it for being messy.

Since your data is generated dynamically you could mark each select option with a class that specifies it's type like class="type1" and class="type2" so later you can do separate actions on them from the JS side. Or you could use the HTML data-* attribute to differentiate them.

Related

Creating custom data in Shopify to save into the customer object and access on a different page

I am trying to create custom data to save into the customer object, which I could then access on a different page. I have an input like this
<input type="hidden" id="{{ formId }}-score" name=contact[score]>
I created an exam page that uses a script to calculate the score, which is then sending the value to that input. I am trying to save that value into the customer object which I could then access on a different page like this:
{% if customer.score > 11 %} <h1> You Passed </h1> {% endif %}
In Shopify, using tags we can save custom data of the customer. You will need to add tags in the name like this: name="customer[tags]"
You can pass the value as per your need like this: value="score_11"
You can fetch the value like this: customer.tags
You can use tags in your condition.
{% if customer.tags > score_11 %}

What's the best way to perform small client-side JavaScript in Eleventy?

Problem
I'd like to add a small bit of client-side JavaScript to my Eleventy website. I can't seem to access document. using Eleventy which means I can't access elements and listen to them for events. Example of what doesn't work:
const formElement = document.querySelector("form")
The error message I receive from Eleventy:
ReferenceError: document is not defined
Question
How do I work with Eleventy in order to listen to document element changes and make page changes?
Example:
formElement.addEventListener("change", function () {
// Update nearby paragraph element based on form value
});
My real-world scenario: I would like to have a paragraph element display which of the form's input type="radio" has the value checked.
Approach so far
I have a file in /data called fruits.json:
{
"items": [
{
"name": "Apple"
},
{
"name": "Banana"
},
{
"name": "Strawberry"
},
{
"name": "Mango"
},
{
"name": "Peach"
},
{
"name": "Watermelon"
},
{
"name": "Blueberry"
}
]
}
And a HTML file in /_includes/layouts based on my base.html file:
{% extends "layouts/base.html" %}
{% block content %}
<form>
{% for item in fruits.items %}
{# Create a radio button for each, with the first one checked by default #}
<input type="radio" name="screen" id="{{ item.name | slug }}" value="{{ item.name | slug }}" {% if loop.index === 1 %} checked {% endif %}>
<label for="{{ item.name | slug }}">{{ item.name }}</label>
{% endfor %}
{% set selectedFruit = helpers.getSelectedFruit() %}
<p>Currently selected item from above is: {{ selectedFruit }}</p>
</form>
{% endblock %}
Note that thee variable called selectedFruit is assigned to a helper function:
{% set selectedScreen = helpers.getSelectedScreen() %}
That getSelectedScreen() function looks like:
getSelectedScreen() {
const formEl = document.querySelector("form")
console.log(formEl)
}
Aside from not being able to work with .document, I feel like this approach is probably 'against the grain' of Eleventy, static site generators in other ways:
The script is being called mid-document
The script is one-off and away from its context
I wonder if I'm approaching this wrong in the first place, or if I just need to do something to allow .document access.
There are some misconceptions here — the most important distinction for your JavaScript code is whether it's executed at build time or client-side at runtime.
The Eleventy core as well as your .eleventy.js configuration file are written in JavaScript which is executed once during the build step, i.e. when your static site is being generated. This happens in a NodeJS environment, not in a browser, which is why there's no document variable and and no DOM.
If you want to dynamically change something on your site in response to user interaction, you need to write a separate JavaScript file which is copied to the output directory of your static site. Then you can include it in the HTML template for your static sites so it's included during normal page visits after your site is deployed.
First, modify your template to only generate a placeholder element for your JavaScript function to add text to later:
{% extends "layouts/base.html" %}
{% block content %}
<form id="fruits-form">
{% for item in fruits.items %}
{# Create a radio button for each, with the first one checked by default #}
<input type="radio" name="screen" id="{{ item.name | slug }}" value="{{ item.name | slug }}" {% if loop.index === 1 %} checked {% endif %}>
<label for="{{ item.name | slug }}">{{ item.name }}</label>
{% endfor %}
<p id="selected-fruits-output"></p>
</form>
{% endblock %}
Then, create a JavaScript file which reacts to change events on the form:
// fruit-form.js
const fruitForm = document.getElementById('fruits-form');
const formOutput = document.getElementById('selected-fruits-output');
fruitForm.addEventListener('change', e => {
// update the formOutput with the list of selected fruits
});
Now you need to make sure this javascript file is copied to your output directory, using Passthrough file copy:
eleventyConfig.addPassthroughCopy("path/to/fruit-form.js");
Finally, make sure to include the script element in your HTML template (make sure the path is an absolute path to the output as specified above):
{# layouts/base.html #}
<script src="/path/to/fruit-form.js" defer></script>
Now it should work as expected. In general, make sure to understand the difference between build-time and runtime JavaScript, so you can decide which will work best in different situations.

Django: AJAX code needed for dependent dropdowns

Since I'm new to Django and have absolutely no knowledge of JS/AJAX, I'm trying to code in the most simple possible way dependent dropdowns. I managed to get my dropdowns populated with values from my database (data_immo). Now I need to have the second dropdown updated after user selection in the first one.
Here is my home.html file with the two dropdowns (regions and departements):
<select name="regions" id="regions">
{% for item in query_results_dict %}
<option value={{ item.nom_reg }}>{{ item.nom_reg }}</option>
{% endfor %}
</select>
<select name="departements" id="departements">
{% for item in departements %}
<option val="{{ item.insee_dep }}"> {{ item.insee_dep }} </option>
{% endfor %}
</select>
views.py:
def MyView(request):
query_results = data_immo.objects.all()
regions = data_immo.objects.values_list("nom_reg", flat=True).distinct()
departements = data_immo.objects.values_list("insee_dep", flat=True).distinct()
query_results_dict = {
'query_results': query_results,
'regions': regions,
'departements': departements,
}
return render(request,'home.html', query_results_dict)
models.py:
class data_immo(models.Model):
id = models.AutoField(primary_key=True)
insee_dep = models.IntegerField(db_column='INSEE_DEP', blank=True, null=True)
nom_reg = models.TextField(db_column='NOM_REG', blank=True, null=True)
class Meta:
managed = True
db_table = 'immo'
My understanding is that I need to retrieve the selected value from the "regions" dropdown and use an onChange function to trigger an action that will use that variable and inspect the db so only matching depatements are selected. Unfortunately I don't know how to proceed. I know there are a few examples out there, but none of them were really satisfying, and those I tried failed due to my lack of JS/AJAX knowledge.
Let me know if need more details.
EDIT 1: added models.py; also, the website that has been recommended in the comments has values stored in different tables whereas mine are all in the same one. Surely this must have an impact on my code and cannot be replicated per se.

Keep option selected on page refresh

So how my code works i'll give you a gist.
When there are no files in html_files, the default option is "---", but when there exists a file in html_files there are two options now,
1) "---"
2) file. But with default still as "---"
So what i want to do is, when there exists a file in html_files I want the default option change to the current file and not "---". I cant think of a way as to how to do it. Could someone help me?
<span title="list resources who's involved etc">About File:
<select class="experiment_file_selector" id="about_file" name="about_file">
<option value="None" {% if not exp.about_file %}selected="selected"{% endif %}>---</option>
{% for file in html_files %}
<option value="{{ file.id }}" {% if file == exp.about_file %}selected="selected"{% endif %} >{{ file.get_base_name }}</option>
{% endfor %}
</select></span>
I added a JS script as suggested below it does the work on getting the default file on the select input tag when the exp.about_file is present but for it to get displayed on the template it needs to be manually clicked.
To automate the process i tried using .click() which seems to fail somehow.
So basically how its working, of i select the first option from the select list "---" or listFile[0] and then select the second one exp.about_file or listFile[1] manually, it delivers the result some how but its not happening with the JS script.
So could someone suggest me a method to automate the mouse click event for
listFile[0] and listFile[1], somewhat like my JS code so that it works.
Thanks
$(document).ready(function(){
var listFile = document.getElementById('about_file');
if (listFile.length > 1)
{
listFile[1].setAttribute('selected', 'selected');
listFile[0].click();
listFile[1].click();
}
});
It will be easy if you use javascript. Just add attribute selected="selected" when your page loaded.
document.addEventListener('DOMContentLoaded', function(e) {
var listFile = document.getElementById('about_file');
if (listFile.length > 1) {
listFile[1].setAttribute('selected', 'selected');
}
});

Using javascript variable in python(flask/Django) dictionary html

I am trying to use a javascript variable in a python dictionary in html, is this possible? Any help would be great.
e.g if I had a dictionary - current_data
var num_key = "4";
alert( {{ current_data[num_key] }} );
If I do the following it works perfectly,
alert( {{ current_data["4"] }} );
But with the javascript variable, it won't work.
Thanks again.
No, while you can use Jinja to create JavaScript embedded in <script> tags, you cannot use it the other way around. When Flask renders this page it's static. The page does not still have blocks of code inside {{ }} or {% %}, it holds the result of those operations. However, there are other options. You could put the contents of current_data into hidden input with the keys as the id attributes.
View
{% for key in current_data %}
<input id="{{ key }}" type="hidden" value="{{ current_data[key] }}"/>
{% endfor %}
JavaScript
var num_key = "4";
alert(document.getElementById(num_key).value);
One extra piece of advice, it's not good practice to embed JavaScript into your html. You should have a separate .js file containing this and then include it in your html.

Categories

Resources