jQuery not recognized in extended html python flask - javascript

Not sure what is going on here. It seems that jQuery is not "extended" from a base.html file to an external one.
I have:
#base.html
<!doctype html>
<html class="no-js" lang="en">
<head>
...
... # css imports
</head>
<body>
# some fixed stuff
{% block body %}
# some stuff specific to base.html
{% endblock %}
# js imports at the end of the body
<script src="static/js/jquery-3.1.0.min.js"></script>
... # various other js
</body>
</html>
Then I have another html file:
#test.html
{% extends "base.html" %}
{% block body %}
# some stuff
<script type="text/javascript">
$(document).ready( function () {
alert("foo")
} );
</script>
{% endblock %}
Now, I don't get any alert. However, if I use plain javascript it works as expected.
I noticed that if I import again jQuery in test.html, jQuery works fine. But what's the point of extending then?
There must be something that I'm missing. By the way, this seems to happen only with jQuery, all other javascript libraries seem to be extended fine.

It's really very simple. When the following code runs, it needs to run using jQuery.
<script type="text/javascript">
$(document).ready( function () {
alert("foo")
} );
</script>
However, your jQuery is being loaded AFTER these commands, whereas, it needs to be placed BEFORE that.
It's like you're drinking water from a glass before you're putting water in it. You need to put the water in the glass first and then drink it. I don't know if this example makes it easy or not.

Add this line.I hope this will work.
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-3.1.0.min.js')
}}"></script>

At the moment $(document).ready( function () { executes, $ hasn't been aliased to jQuery, which has yet to load.

Related

JavaScript only runs when both the code is inside the HTML and is called externally with <script src=...>

My JavaScript code only runs when the code is both inside the HTML file and called externally via
<script type="text/javascript" src="{{ url_for('static', filename='index.js') }}"></script>
<script>
var scroller = document.querySelector("#scroller");
...
</script>
I am using Flask and Jinja, with a file structure of:
/app
/static
index.js
/templates
base.html
myfile.html
routes.py
__init__.py
...
The code inside index.js is the exact same code between the <script> tags inside the HTML.
In terms of jinja and using block tags, base.html:
<body>
{% block content %}
<!-- typical HTML stuff here -->
{% endblock %}
<!-- some Bootstrap tags -->
<script ... ></script>
{% block script %}{% endblock %}
</body>
myfile.html:
<body>
...
{% block script %}
<script type="text/javascript" src="{{ url_for('static', filename='index.js') }}"></script>
{% endblock %}
<script>
...
</script>
The code itself works, and it worked not too long ago without this issue; I don't know what I changed to cause this, nor can I even imagine what could cause this. If there is more code that is required, I can easily share it.
Is there something I not understanding?
To note: I have had a similar issue trying to including external JavaScript code inside my HTML; at one point it wouldn't work, then it did, now it behaves the way I have described.
To further note: I have another .html file with its own external .js file that works fine.
Mr.#JakeJackson, Script in externl file never requires the same content to be available inside your inline code.
May be you are trying to process some elements and your script got executed before those elements are mounted to the document object.
A lazy solution to that problem is moving the external file linking tag to the bottom your HTML.Body.
OR
You can use defer attribute to your script element https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
OR
If you have some libraries like jQuery included in your page, You can use the document.ready implementations in that
OR
you can implement your own document.ready like below
function myReady() {
return new Promise(function(resolve) {
function checkState() {
if (document.readyState !== 'loading') {
resolve();
}
}
document.addEventListener('readystatechange', checkState);
checkState();
});
};
myReady().then(function() {
// Put your app custom code here
});

Scrollify function not being found even when script is imported

So I'm trying to use Scrollify, which is a jQuery plugin for scroll snapping. I have jQuery imported no problem, but no matter how I import the plugin itself, I get the error:
Uncaught TypeError: $.scrollify is not a function
I have the plugin script loading after jQuery itself loads, and the configuration code after both of those load, even to the point where I put the plugin's script tag and configuration code at the very end of the page before </body>.
I've tried hosting the plugin script locally, and I tried using a CDN. Both gave the same issue.
I've had these sort of issues with other scripts and they always were due to the loading order, but I'm stumped here. Any help?
So I am building a custom Theme in OctoberCMS, and I was hopping to use scrollify before running into the same error. After a lot of struggling, switching JQuery versions and moving functions around, I noticed my issue was related to using Laravel Mix/Webpack to import the scrollify code. I had it required at the top of my main.js file, but the code itself was loaded after.
My solution was using some October twig functions to load the code after JQuery manually.
// These get loaded first
<script src="{{ [
'assets/js/app.js', // My JQuery gets loaded here
'assets/js/vue.js' // Other JS for the website
]|theme }}"></script>
// Scripts in here injected into page by the {% scripts %} tag after, having the
// scrollify.js in the array above or outside the {% put scripts %} tag would always throw
// $.scrollify is not a function error
{% put scripts %}
<script src="{{ 'assets/js/scrollify.js'|theme }}"></script>
<script>
$(document).ready(function () {
$.scrollify({
section: ".example-section",
});
});
</script>
{% endput %}
{% scripts %}
The {% scripts %} tag inserts JavaScript file references to scripts
injected by the application.
https://octobercms.com/docs/markup/tag-scripts
As the above answers mentioned, Scrollify needs to be loaded after the page and Jquery loads, but if you are using Webpack or equivalent I would suggest checking the compiled scripts in your browser and making sure they are ordered correctly.
Try putting your script at the bottom of your code.
...
<script>
$(function(){
$.scrollify({
...
});
});
</script>
</body>
Try to use it this way
jQuery(document).ready(function($) {
$.scrollify({
...
});
});
The reason behind the error is, that the Scrollify Script should initialize after the document has finished loading. Thus, the solution is to move it to the end
Move these two lines at the end of the body tag, as shown below:
<body>
..
..
..
<script src="..\js\Scrollify\jquery.scrollify.js"></script>
<script>
$(document).ready(function() {
$.scrollify({
section : ".sectionalScrolling",
});
});
</script>
</body>
Make sure that the script is right before the closing body tag.

Django/jQuery: handling template inheritence and JS files loading

In Django, how can you handle the fact that you need to wait for that a JS file is loaded before actually using it?
let's see the problem with this example:
base.html
<!DOCTYPE html>
<html>
<head>...</head>
<body>
{% include "content.html" %}
<script src="jquery.js"></script>
<script src="awesome-script.js"></script>
</body>
</html>
content.html
<script>
$(document).ready(function(){
...
});
</script>
This logically fail ($ is undefined). I could load jQuery before calling the script, but I'm trying to avoid loading JS file before my main content to keep the website loading as fast as possible.
So, what can I do? Thanks.
Extending Wtower's suggestion - keep his accepted.
I would really insist on using the template inheritance based approach in his examples. I would like to introduce a few more elements to that approach, to cover some other common needs :
<!DOCTYPE html>
<html>
<head>{% block scripts-head %}{% endblock %}</head>
<body>
{% block content %}{% endblock %}
{% block scripts %}
<script src="jquery.js"></script>
{% endblock %}
<script>{% block script-inline %}{% endblock %}</script>
</body>
</html>
There are 3 ideas here:
Adding a placeholder in the header, in case you could need scripts there at some point. Self explanatory.
Including common scripts in the base file. If they are common, the belong in the base file, you should not have to repeat yourself in every template. Yet you put it inside the block, so it can be overriden along the hierarchy.
{% extends "base.html" %}
{% block scripts %}
{{ block.super }}
<script src="a-local-lib.js"></script>
{% endblock %}
The key is in using {{ block.super }} to bring any script that was defined in the parent template. It works especially well when you have several levels of inheritance in your templates. You get to control whether script go before or after inherited scripts. And of course, you can completely override the block, not including {{ block.super }} if you so wish.
Basically the same idea, but with raw javascript. You use it the same way: every template that needs to include some inline javascript will have its {{ block script-inline }}, and will start with {{ block.super }} so whatever the parent put in there is still included.
For instance, I use Ember in my project, and have a couple of initializers to setup project settings and load bootstrap data. My base app-loading templates has a global project settings initializer, and child templates define local settings and data.
Since your script uses jQuery, you can simply use the $(document).ready() and $(window).load() functions of jQuery to bind a function on the event that DOM is ready and all window contents have been loaded, respectively.
If you do not use jQuery, take a look at these relative questions to understand how to imitate the above behaviour with pure JS:
pure JavaScript equivalent to jQuery's $.ready() how to call a function when the page/dom is ready for it
Javascript - How to detect if document has loaded
EDIT 1: The inclusion order matters. You have to include the jQuery scripts before any scripts that require jQuery are executed.
EDIT 2: You can organize your templates better by keeping the scripts separately from the main content, either with a second template:
base.html
<!DOCTYPE html>
<html>
<head>...</head>
<body>
{% include "content.html" %}
{% include "js.html" %}
</body>
</html>
js.html
<script src="jquery.js"></script>
<script src="awesome-script.js"></script>
<script>
$(document).ready(function(){
...
});
</script>
(in this case you render base.html)
Or with blocks (recommended):
base.html
<!DOCTYPE html>
<html>
<head>...</head>
<body>
{% block content %}{% endblock %}
{% block scripts %}{% endblock %}
</body>
</html>
content.html
{% extends 'base.html' %}
{% block content %}
...
{% endblock %}
{% block scripts %}
<script src="jquery.js"></script>
<script src="awesome-script.js"></script>
<script>
$(document).ready(function(){
...
});
</script>
{% endblock %}
(in this case you render content.html)

Django: How to keep JavaScript code separate in static folder when it uses a python variable

I have a bunch of canvases that needs to be rendered. I don't want put the
JavaScript code in a python loop, because I feel it's bad practice
home.html
{% load staticfiles %}
<head>
<script type="text/javascript" src="{% static
'canvas/canvasrender.js' %}"></script>
</head>
{% for canvas in user_canvas_set %}
<canvas class = "canvas" id="{{canvas.id}}" width="400" height="200"
canvas_post= ""{{canvas.canvas_post}}"" >
Your browser does not support the HTML5 canvas tag.</canvas>
**<script>
canvasrenderNP.canvaswrite("{{canvas.id}}","{{canvas.canvas_post}}")
</script>**
{% endfor %}
I made a custom function that returns an array of the users canvas ids, because I use the canvas id as the id for the canvas element.
home.html
<script>
alert("{{user_canvas_ids}}")
</script>
I get the desired output:
[247, 248, 251, 252]
Now when I put this in a static file
canvasrender.js
alert("{{user_canvas_ids}}")
then load it into
home.html
{% load staticfiles %}
<head>
<script type="text/javascript" src="{% static
'canvas/canvasrender.js' %}"></script>
</head>
output:
"{{user_canvas_ids}}"
I am confused to as what is going on. I thought that the script tag inserts the js file in between the "<script> </script>"
I know I can make a element like so and get the attribute, but I feel like that is not good practice, or is it fine?
<p id="canvas_ids" canvas_ids ="{{user_canvas_ids}}"> </p >
Is there anything else I can do so that I can avoid writing JavaScript code
in the HTML file?
Why this is not a duplicate question. It does not have anything about why the linked js file in the html page can not keep reference to the python variable. But if the JavaScript is coded in the html page it can
As you mentioned in your own comment, you can save user_canvas_id in a js variable in home.html and access it in your js file. Something like this:
<head>
<script>var user_canvas_id = "{{ user_canvas_id }}"</script>
<script type="text/javascript" src="{% static 'canvas/canvasrender.js' %}"></script>
</head>
I am confused to as what is going on. I thought that the script tag inserts the js file in between the "<script> </script>"
Kinda, but this is done client-side, by the browser who has no idea about the special meaning of curly braces in Django templates.
And static in the context of Django means just that: That Django serves that file as-is, without running it through the template engine. (Which wouldn't help here anyway, as for the JavaScript file in isolation, the value of user_canvas_ids would be unknown, so the template engine couldn't substitute anything useful for it.)

Call JavaScript function from Twig

I'm working on a Symfony2 project and I want to call a JavaScript function and pass an array of JSON objects (which I get from a controller) from a Twig.
But a first, very simple test already failed, like:
main.js:
function helloWorld(name) {
console.log("hello " + name);
}
linked to main.js in the twig and called the function:
<body>
<script>helloWorld("world!")</script>
{% block javascripts %}
<script src="{{ asset('js/main.js') }}"></script>
{% endblock %}
</body>
which results in a ReferenceError:
"Uncaught ReferenceError: helloWorld is not defined"
What do I have to do differently to make this work?
EDIT: Thanks to the two who took the time to answer. The described twig actually consists of a bunch of nested twigs and the placement of the javascript include was based on the Symfony documentation, guess that's why I didn't see the obvious. Should have detected the problem myself when phrasing the question though....
Invert the order of the functions:
<body>
{% block javascripts %}
<script src="{{ asset('js/main.js') }}"></script>
{% endblock %}
<script>helloWorld("world!")</script>
</body>
The script with the definition of the helloWorld definition is put after the function is executed. This means JavaScript doesn't yet know the function and triggers this error.
Solution: Put your javascript below your imports (before </body>, in the javascripts block for instance) or put the imports before the page javascript (in the head for instance).

Categories

Resources