js to communicate with dom in wordpress - javascript

I am trying to listen to a click event of a link using javascript inside a wordpress project. But I could notice, NodeList is getting empty. Seem to be it's having an issue when communicating with the DOM. My attempt is as below. I created a folder called theme and inside the index.php there, below lines were added.
<?php get_header(); ?>
Next1
Next2
Then inside the functions.php file imported the external scripting file as below.
<?php
function pet_data1(){
wp_enqueue_script('pet_adoption_style1',
get_stylesheet_directory_uri().'/script.js', array(), false, false);
}
add_action('wp_enqueue_scripts', 'pet_data1');
?>
Next the header.php file takes as below.
<!DOCTYPE html>
<html lang="en">
<head>
<?php wp_head();?>
</head>
</html>
Finally, script.js file which is not given the expected output is as in below.
const nextBtns = document.querySelectorAll(".btn-next");
console.log("nextBtns",nextBtns)
When I print the nodeList, length is zero. But there should be 2 nodes which contains the btn-next class. So I think there should be an issue with wordpress structure which I have followed. Since I am new to wordpress, I need your support to fix this out.

The issue is not with "Wordpress structure", but because you're loading the script in <head>, but attempting to access elements in the document body before waiting for the DOM to be ready.
<script> tags in the <head> will be downloaded and executed, before the browser parses the rest of the HTML found after <head> This causes issues with your selectors since when the script is executed, those elements that would have matched your selectors do not exist in the DOM tree at runtime:
Source: https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html
There are two solutions:
Ensure that script.js is loaded in the footer, which means the DOM has been parsed and is ready, or
Wrap all DOM querying logic in script.js in a callback that is invoked upon the firing of DOMContentLoaded event:
window.addEventListener('DOMContentLoaded', () => {
const nextBtns = document.querySelectorAll(".btn-next");
console.log("nextBtns",nextBtns)
});

Related

Rails js script code not working while screen back due to Turbolinks

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
}

how to make an ajax call with jquery loaded in the body section not head section

I have a layout file where i included Jquery just before closing tag.
//layout.handlebars
<!DOCTYPE html>
<html>
<head></head>
<body>
{{{body}}} // renders the body content
<script src='/js/jquery-2.2.4.min.js'></script>
</body>
</html>
I also have a page specific javascript(helper.js) that makes an Ajax call.
<div>Some sample data</div>
<script src="/js/helper.js"></script>
but the problem here is jquery is loaded at the end of the page but i am referring to it in the external javascript before jquery is loaded. which shows me '$' is not defined and i know that is obvious.
One solution to this will be like adding jquery to the head section but that is not what i want.
Is there any approach that i can apply to make an ajax call from external file without moving Jquery to head section.
Any help is much appreciated!!
Is there any approach that i can apply to make an ajax call from external file without moving Jquery to head section.
Yes, I assume you already understand the cause of the issue. As you see below the final content is ..
<!DOCTYPE html>
<html>
<head></head>
<body>
<div>Some sample data</div>
<script src="/js/helper.js"></script> <!--Jquery is not loaded yet, and hence $ is undefined -->
<script src='/js/jquery-2.2.4.min.js'></script>
</body>
</html>
As you already know one option is to move jquery anywhere in the HTML but make sure its loaded before any other jquery dependent files. Now since you don't want to take this option. we have another option.
Solution:
Our only aim is to make sure the jquery library is loaded prior to any other jquery dependent files.
We can get the files on document.ready using $.getScript()
$(function(){
$.getScript( "/js/helper.js", function( data, textStatus, jqxhr ) {
console.log( "Load was performed." );
});
});
Extras: If you feel this is a overhead and you cannot add this code to all the files in your page (since there can be too many files ), You can write a generic function and a global array variable , This function will check for file paths in the array and execute each one synchronously and remove from the array. Make sure this generic function is called in every document.ready event.
One Solution is that You can put the jquery script at the start of body tag before {{{body}}} section .. In this way your helper script will be rendered after jquery and your problem will be solved .....
Well its not pretty but you could use some kind of test and wait loop something like
<script>
(function test(){
if( window.jQuery ){
//your jQuery code
} else {
setTimeout(function(){ test(); }, 200);
}
})
</script>

Inline Javascript works but not when external

I have this short Javascript code that I want to put in a external file. The reason being is because there will be many .htm pages that would use it. So instead of putting it all inline at every single file, I want to put it in an external file.
But the thing is, it doesn't work. The script is basically a "back to top" button. It works flawlessly when I put the script in the .htm file. Another note by the way, I'm loading the .htm file in a Div, could that cause problems? Edit: The file is loaded through the .load() jQuery function.
I have also tried putting the script inline in my index.html but it fails to work there too.
Here is the code:
$('.backtotopwrapper').click(function(){
$('body,html').animate({scrollTop: "0px"},1500);
});
Update: I have tested my other .js code and the ones that have nothing to do with the .htm file work. The code that is specific to the elements inside the .htm is the only one that doesn't work.
OK, 3 files :
main.html
loremIpsum2.html
myScroll.js
1). In main.html I call jQuery and myScroll.js external files
Also I have an empty wrapper div (<div id="loader"></div>) where I put the contents of loremIpsum2.html using jQuery .load() so
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>link to external js file</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="myScroll.js"></script>
<script>
/* <![CDATA[ */
$(document).ready(function() {
$("#loader").load("loremIpsum2.html");
}); // ready​​​
/* ]]> */
</script>
</head>
<body>
<div id="wrap">
<div id="loader"></div>
</div><!--wrap-->
</body>
</html>
2). In loremIpsum2.html, I have just a bunch of paragraphs but at the end I have my button :
<a class="backtotopwrapper" href="javascript:;">go to top</a>
3). In myScroll.js i Have the function for my scrolling button :
$(function () {
$('body').on("click", ".backtotopwrapper", function () {
$('body,html').animate({
scrollTop: 0
}, 1500);
});
});
Since I am loading the file where the button is via .load(), I am using .on() in its delegated form.
See DEMO and feel free to explore the source code.
NOTE : .on() requires jQuery v1.7+
I had the same problem but didn't perform any solution mentioned here, i actually dicovered what made it work for me when my external scripts werent working but the same code works internally.
Just remove any spaces/special characters from your external script filename e.g instead of calling it "admin-script.js", call it "adminscript.js", without the special characters like the hyphen, then refer to the script with the new name and thats it, it worked for me.

Javascript - Dynamically load a fragment of HTML and run script

I'm building a webpage and I want to re-use some HTML I have elsewhere on my website. The page I am building (index.html) can dynamically get and insert the HTML I want (existing.html) using XMLHttpRequest. However, the HTML I want to get is populated by some Javscript. That Javascript is not being executed when I load it into my new page:
index.html:
<html>
<head>
<script type = "text/javascript">
... //use XMLHttpRequest to load existing.html
initExistingHTML(); //this is function which populates loaded HTML, is not executed
</script>
</head>
<html>
existing.html:
<div>
<script type = "text/javascript">
function initExistingHTML() {
... // do some stuff
}
</script>
</div>
How can I load existing.html and run the script which populates it?
Once the page has loaded, add in existing.html via innerHTML. Rather than calling its functions, just let existing.html's code execute, which will do the same as if it were in the onload section.
EDIT: Or, you could just correct that typo you have. initExistingHTML != initExistingHtml.
lol

Dynamic (2 levels) Javascript/CSS Loading IE6

i am trying to dynamically include js (and css) files into a webpage like this:
index.html -> loader_a.js -> a_foo.js, a_bar.js, a_foo.css and so on.
While this works without a problem in FF (using appendChild) i cant get it to run in IE6.
I've tried various available solutions (adding to dom node, ajax call and eval and more from (http://ntt.cc/2008/02/10/4-ways-to-dynamically-load-external-javascriptwith-source.html) here and there and others like post #2013676) but it's not doing what its supposed to do.
When i check with DebugBar i see that my include files (eg a_foo.js) is actually loaded, but its content is empty - on other included files (1 Level/directly) this content is show so i assume there is the problem ...
The "error" i get is alway undefined object which is o/c b/c the function i call is not loaded properly so not much of a help. I dont get any errors on the includes.
I've validated the javascripts so those whould be ok.
Does anyone have the ultimate solution for this?
I can recreate my tests and post some code if it helps.
Thanks,
regards,
Thomas
Sample HTML:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML lang=en><HEAD><TITLE>Test</TITLE>
<script type="text/javascript" src="mmtest_files/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="mmtest_files/multiload.js"></script>
<script type="text/javascript" >
function init2() {
// using the data from the loaded js files
var a= mmf("a");
document.getElementById('status').innerHTML = "Variable set:" + a;
}
// magic...
include(['mmt.js'],init2);
</script>
<BODY >
<H2>Test me!</H2>
<SPAN id=status>status old</SPAN>
</BODY></HTML>
JS 1 is multiload from answer 1
JS2 is a test include:
function mmf(param)
{
return "Called with" + param;
}
You need to use document.write in ie, in order to load scripts in parallel.
See: Loading Scripts Without Blocking
I have such a script btw: Loading Multiple Javascript Files In Order Asynchronously
(it may need some enchancements in Chrome)
UPDATE
There is a callback function, it is optional. It can be used to couple dependent script to the files. EG:
function myjQueryCode() {
// ...
}
include(['jquery.js','jquery-ui.js'], myjQueryCode);
So that your jquery dependent code will run after the files has been loaded.

Categories

Resources