In yii2 I have put all my js code in 1 file using yii2-assets-auto-compress plugin, including jQuery lib. Loading this file is async to speed up page load. But, if there are forms on the page, yii adds yiiActiveForm() at the end of </body>. So, the error is jQuery is not defined.
How to manage this problem? Firstly, I can make call yiiActiveForm() manually from script.js, but how to turn it off automatically load at the end of the body? Generally, that's not convenient, because there might be other scripts that append js code. Maybe someone knows how append js code with this yii2-assets-auto-compress plugin?
<script src="/assets/js-compress/script.js?" async="async"></script>
<script type="text/javascript">
jQuery(document).ready(function () {
jQuery('#w0').yiiActiveForm([],[]);
});
</script>
</body>
async downloads the file during HTML parsing and will pause the HTML parser to execute it when it has finished downloading.
You should either load Jquery outside your compressed scripts inside the head.
Or load the script inside the <head> of the document means inside the layout file either using script tags
<script type="text/javascript" src="/path/to/compressed.js" async="async"></script>
or using
<?php $this->registerJsFile('/path/to/compressed.js',['aync'=>'aync'])?>
if you are using AssetManager to load the script file
Then load it like this
public $js = [
['js/compressed.js','async'=>'async','position' => yii\web\View::POS_HEAD],
];
Also, you should configure the asset manager to not load the core script jquery so that it does not load jquery twice.
'assetManager' => [
'bundles' => [
'yii\web\JqueryAsset' => [
'sourcePath' => null,
'js'=>[]
],
],
],
HERE is a good read.
Related
In my rails app there is a JS script in partial view
const f2s = window.document.createElement("script");
f2s.defer = true;
(f2s.src = "https://face2.oktium.com/face2widget.js"),
(f2s.onload = function () {
new window.Oktium(face2params).init();
new window.Oktium(face2paramsMobile).init();
}),
document.head.appendChild(f2s);
it works fine when page load for first but when comes again from back or another page which have same code its not working. How can I work that with turbolinks?
From turbolinks docs
Working with Script Elements
Your browser automatically loads and evaluates any <script> elements present on the initial page load.
When you navigate to a new page, Turbolinks looks for any <script> elements in the new page’s <head> which aren’t present on the current page. Then it appends them to the current <head> where they’re loaded and evaluated by the browser. You can use this to load additional JavaScript files on-demand.
Turbolinks evaluates <script> elements in a page’s <body> each time it renders the page. You can use inline body scripts to set up per-page JavaScript state or bootstrap client-side models. To install behavior, or to perform more complex operations when the page changes, avoid script elements and use the turbolinks:load event instead.
Annotate <script> elements with data-turbolinks-eval="false" if you do not want Turbolinks to evaluate them after rendering. Note that this annotation will not prevent your browser from evaluating scripts on the initial page load.
Loading Your Application’s JavaScript Bundle
Always make sure to load your application’s JavaScript bundle using <script> elements in the <head> of your document. Otherwise, Turbolinks will reload the bundle with every page change.
<head>
...
<script src="/application-cbd3cd4.js" defer></script>
</head>
If you have traditionally placed application scripts at the end of <body> for performance reasons, consider using the <script defer> attribute instead. It has widespread browser support and allows you to keep your scripts in <head> for Turbolinks compatibility.
You should also consider configuring your asset packaging system to fingerprint each script so it has a new URL when its contents change. Then you can use the data-turbolinks-track attribute to force a full page reload when you deploy a new JavaScript bundle.
You can wrap your JS script inside such handler inside script tag in the head
<script defer>
document.addEventListener('turbolinks:load', () => {
// your code here
})
</script>
Also in Rails there is mechanism how to add some tags dynamically, you can add in the <head> in layout/application
<%= yield(:face2) %>
And then in your specific view
<% content_for(:face2) do %>
<script defer src="https://face2.oktium.com/face2widget.js" data-turbolinks-eval="false"></script>
<script>
document.addEventListener('turbolinks:load', () => {
new window.Oktium(face2params).init()
new window.Oktium(face2paramsMobile).init()
})
</script>
<% end %>
You should wrap your JS code inside
$(document).on('turbolinks:load', function() {
...
}
Bit of a repetition of what others have suggested, but I just wanted to stress that it was the wrapping of the functionality needed for the partial/view including variable declarations that worked for me. Initially I used the following in the erb which worked with some exceptions.
<div id="cart-counter" data-turbo-permanent>1 item</div>
This kind of worked but when user clicked button type submit on other pages, it broke again.
Tried many things, and as others have described, the following worked:
wrapped the script I needed for that view with :
document.addEventListener("turbo:load", ()=>{
// functionality
}
To call all js files in just one line on my header I am currently using
function alljs(jsfile) {
var src = document.createElement("script");
src.setAttribute("type", "text/javascript");
src.setAttribute("src", jsfile);
document.getElementsByTagName("head")[0].appendChild(src);
}
alljs("path/to/my/jsfile1.js");
alljs("path/to/my/jsfile2.js");
alljs("path/to/my/jsfile3.js");
then all I have to do is put this on my header:
<script type="text/javascript" src="my/path/all.js" ></script>
but recently I have to include jquery files in my system
I notice that calling a jquery file by adding
alljs("path/to/my/jqueryfile1.js");
to my all.js file doesn't work...
I have to do a second line of <script> on my header just to call the jquery file...
My question is: is there a similar way to call all jquery files in just one file?
Iam using load() for loading external html file.
$("#header_section").load("header.html");
$("#sidemenu_section").load("side_menu.html");
Here, HTML file is loaded and css also loaded but script file is not loading in the page
<script src="js/utility.js"></script>
I tried to declare the above script file inside the head and inside the body. Both are not working.
Check your relative path to the utility.js file and make sure to load juery.js library before load utility.js file.
and finally try this,
<script type="text/javascript" src="${pageContext.request.contextPath}/js/utility.js"></script>
to load the utility.js file.
I think you forget to add jquery.min.js file. use below code.
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="js/utility.js"></script>
</head>
jQuery may only execute your code with the type attribute set to "text/javascript", per this bug filed a long time ago:
http://bugs.jquery.com/ticket/3733
Try this ...
<script type="text/javascript" src="http://your.cdn.com/first.js"></script>
<script type="text/javascript">
loadScript("http://your.cdn.com/second.js", function(){
//initialization code
});
</script>
The jQuery code that adds HTML to the DOM always strips out <script> tags. It runs them and then throws them away.
An exception to that behavior is when you use "$.load()" with the hack that allows you to load a fragment of a page:
$.load("http://something.com/whatever #stuff_I_want", function() { ... });
In that case, the scripts are stripped and not evaluated/run.
I have recently discovered the new trend of including all .js script at the end of the page.
From what i have read so far seems pretty ok and doable with an exception.
The way I am working is using a template like:
<html>
<head>
<!-- tags, css's -->
</head>
<body>
<!-- header -->
<div id="wrapper">
<?php
include('pages/'.$page.'.php');
?>
</div>
<!-- footer -->
<!-- include all .js -->
</body>
</html>
Now, if I want to use this example on my page http://www.bootply.com/71401 , I would have to add the folowing code under my jquery inclusion.
$('.thumbnail').click(function(){
$('.modal-body').empty();
var title = $(this).parent('a').attr("title");
$('.modal-title').html(title);
$($(this).parents('div').html()).appendTo('.modal-body');
$('#myModal').modal({show:true});
});
But that would mean I either use that in every page - even if I do not have use for it, either generate it with php in the $page.'php' file and echoing it in the template file, after the js inclusion.
I am sure though, better methods exist and I don't want to start off by using a maybe compromised one.
Thanks!
Please avoid using inline scripts as they are not good maintainable and prevent the browser from caching them. Swap your inline scripts in external files.
Fore example you could put all your JavaScript in one file an check the presence of a specific element before initialize the whole code. E.g.:
$(document).ready(function(){
if($('.thumbnail').length) {
// your thumbnail code
}
});
A better way to execute "page specific" JavaScript is to work with a modular library like requirejs. You can modularize your scripts depending on their functionality (like thumbnails.js, gallery.js etc.) and then load the necessary script(s) depending e.g. on the existence of an element:
if($('.thumbnail').length) {
require(['ThumbnailScript'], function(ThumbnailScript){
ThumbnailScript.init();
});
}
The best way you can go is create a separate file for this code.
Let's name it app.js. Now you can include it under the jQuery inclusion.
<script type="text/javascript" src="app.js"></script>
This will prevent code repeat.
One more thing, pull all the code in $(document).ready(). Here is an example. So your app.js file will look like this:
$(document).ready(function(){
$('.thumbnail').click(function(){
$('.modal-body').empty();
var title = $(this).parent('a').attr("title");
$('.modal-title').html(title);
$($(this).parents('div').html()).appendTo('.modal-body');
$('#myModal').modal({show:true});
});
})
The problem:
I'm using zombie.js to test my client-side javascript, but I am running into a problem. Zombie.js does not provide synchronous <script> tag execution, and, in fact seems to not execute external JS files at all. A basic test confirms this:
<script type="text/javascript" src="test1.js"></script>
<script type="text/javascript" src="test2.js"></script>
<script type="text/javascript" src="test3.js"></script>
<script type="text/javascript">
console.log("Inline javascript.");
</script>
Each test#.js contains a single line: console.log("TEST#.JS");
When I render this in a regular browser, the console displays the expected:
TEST1.JS
TEST2.JS
TEST3.JS
Inline javascript.
But when I run it with zombie.js, I only see a single line Inline javascript.
Here's what I have tried to get around the issue:
using document.createElement to dynamically append a script tag to the document
using document.write to add the script block into the html
using a setTimeout on console.log("Inline javascript") in combination with 1 and 2 to give the test scripts some time to load.
Is there any way to resolve this issue, besides placing the JS code from all my external JS files into a huge <script> block?
Are you sure the browser object has the "runScripts" option set to true? If not you can use the following syntax:
browser.visit('... your page url ...', { runScripts: true }, function (e, b) {
console.log('executing callback');
});