How to add dynamic information in the header script? - javascript

I have a Django website that retrieves scores of various items. I would like to make the score appear when a user clicks on a link. The problem is, how do I create this functionality when all of my Jquery code is located in the head?
For example, I have the following code in my head:
$(document).ready(function() {
var $addedElem = $('<p>New Element</p>');
$('.display').one('click', function() {
$addedElem.hide().appendTo("#container").fadeIn("slow");
});
});
Where it defines addedElem, I would like it to add the "score" that the view gives to me. So, I would normally be doing this:
{{ score }}, but how would I add this to addedElem if I do not have access to it? I am using Django's templating system, so I only have access in the innermost body elements and not the head.

Base template have access to context of its inherited templates, {{ score }} will work. You should of course handle the situation when there is no score provided.
If you want this code only for a particular page, you can define {% block head_ext %}{% endblock %} in base template and override it in child template. It's ok to call $(document).ready() more than once.

Related

Reading all products' tags in a FOR loop with a Shopify theme app extension. Can it be done?

I am working on a Shopify app that uses a theme app extension to alter how the price is displayed based on the tags associated with that product. The following code achieves this effect on product pages by inserting these lines of liquid in the price . The if statement looks for a match on the product tags and displays either my code when there is a match or the straight price when there is not.
var x = document.querySelectorAll(".product-single__price");
var i;
for (i=0; i < x.length; i++) {
x[i].innerHTML = `
{%- if product.tags contains 'mytags' -%}
{% comment %} mycode {% endcomment %}
{%- else -%}
{{ product.price | money | strip_html }}
{%- endif -%}
`;
}
 
However, I cannot get this to work on collection pages. I'm assuming this is because the theme app extension's injection is occurring after the loop that displays the product grid and the product tags are no longer readable. Even if I assign the last product on the collection page with the tag to match, it doesn't display my code.
Is there a work around where I can pull the tags for each product and inject this code to each in the grid/list?
You should render all products in a collection into a Javascript data structure, because as you well know, Liquid renders first, creating a giant string of HTML. Inside this HTML Shopify is injecting your Liquid too in your Theme App Extension. So far so good?
Once the Liquid has been totally rendered, that is, the entire collection up to the limits of pagination are in the DOM would any Javascript execute. So it is at this point that you could iterate the DOM for rendered products, and use it. So you could do your querySelector on product prices, and do your logic based on the data you previously saved.
If you expect to be able to change prices on the fly in the Liquid phase, your logic has to be moved from JS to Liquid itself. In other words, when rendering a single product in the collection template, you alter the price then and there, based on logic you have at your disposal, like a tag or metafield.

Access elements inside a Layout View

I am currently working on a website which uses MVC model.
I have a Layout page and 4 pages(home,contactus,aboutus,ourwork) which use this Layout. I am having this situation where I want to use the html element defined in layout page in one of the page(ex. home).
use in the sense modify certain property of that element(using javascript).
example:
lets say there is a button defined in layout page and i want to change the display property of the button when some action happens in home page
Yes, it is possible! You have to create a global Javascript file and add that into the layout body and select the element you want, e.g.:
If the element id is readm, put the script into that file:
var readm= $("#readm");
Include the script file src into the layout body, e.g.:
If the filename is accesselement.js:
<script src="accesselement.js">
Use the variable name in your view in which that element is required.
That's it.

How may I access to a twig variable with innerHTML using Javascript?

I'm currently trying to to get an innerHTML from a twig variable using javascript. But I cannot access to it.
I created a calendar which is an array. And I pass it through my controller so I can use it with twig in my template.
Then I named a div where I render some cells from this array.
Using javascript I get the id from my div and use innerHTML method.
After that, I simply add a alertbox to check if my innerHTML is showed.
myPage.html.twig:
{% for day in calendrier %}
....
<div id="myId">{{day[2]}}</div>
...
{% endfor %}
javascript.js:
document.getElementById('myId').addEventListener('click', fn);
function fn(){ alert(this.innerHTML); };
I cannot access to this value.
I expected to get the day from this div. Let's say for example '14' or any number the user click on the calendar.
How may I process to reach {{ day[2] }} ?
Thank you for your replies.

AJAX on Load command for a Liquid code

I wanted to add a onClick function when I click on the link.
Basically, whenever I click on "Click" it should add the liquid code in the div.
What it is doing is, adding a liquid code yes, but just the code and not the content it should be adding with the liquid code. Here is my code:
Index
Click me!
<div id="result"></div>
<script src="http://code.jquery.com/jquery-latest.min.js"
type="text/javascript"></script>
<script>
$("#myLink").on("click", function(){
$("#result").load("liquidcode.html");
});
</script>
liquidcode.html
{% include 'cod-checker' %}
What I get after clicking on "Click Me" is this {% include 'cod-checker' %}
Liquid is rendered server-side so you will not be able to render liquid after the page loads using jquery. You can circumvent this issue by inserting whatever code resides in 'liquidcode.html' from the very beginning, but hiding it by adding a class to the div with display set to none. You can then remove that class when the user clicks on "Click".
Answering here to expand my comment, since there was a request for actual code from the question author.
My comment, which is the basis of the anser:
I would suggest making an AJAX request on click then, to an endpoint
from your server. Make that endpoint provide a parsed html version of
your liquidcode.liquid (just assuming the filename here).
On client side, jQuery-aided AJAX looks like this:
$("#myLink").on("click", function() {
$("#result").load("myAwesomeServerEndpoint", function() {
console.log('BOOM, server-parsed HTML was successfully loaded inside #result');
});
});
As for server side, I really have no clue what framework you are using. (Ruby on Rails?)
In an MVC fashion, you need to register a route called "myAwesomeServerEndpoint".
Assign a Controller to that route, say "myAwesomeServerController".
This Controller is not supposed to do much, it should just render your liquicode.liquid template.
Pseudocode for your controller (since I dont know Ruby on Rails):
return HtmlResponse(render("liquicode.liquid"));
Make sure that the response is sent as HTML and that the route is exposed to AJAX requests, and that should be it.
Again, this is not a solution but just a rough concenpt

How to prevent caching of my Javascript in django template?

this is my javascript function :
<script>
function text() {
var i = new Array();
{% for content in table %}
i[{{content.id}}]= document.getElementById('checkbox{{content.id}}').checked;
{% endfor %}
return i;
}
</script>
as you can see I have some django template code in It. how to prevent caching of my script ?
I see this but It didn't solve my problem !
I'm not sure I've understood properly, but as far as I can tell this has nothing to do with caching: it is a matter of understanding when templates are rendered vs when scripts are executed.
This script is contained in a template. That template is rendered on the server side. Therefore, the script will be generated - and sent to the browser - with the values of content as they were at that point.
If you have an Ajax function which later updates something in the HTML page, this script will not care at all, because you have done nothing to update it - again, the values in the script were hard-coded when the template was sent to the browser.
You probably don't want to do it this way at all. Instead, you should find or define a parent element that contains all the checkboxes - a div or table row, for example - and then dynamically iterate through all descendants of that element to find the value of any checkboxes. You can then call this script from your Ajax function to update the values when the content changes.

Categories