WP: Enqueue JS at very end of the loading site - javascript

I've got a script, which changes div's placement a little. To work fine, it must be loaded at very end of the page loading - it's because my WP page have few different plugins, some of them uses the js to display content on page, and moving that content is what I want to achieve.
I've tried to put 999999 priority to add_action parameter, also tried to cheat with js function settimeout, but that's not the point - it must work every time, and my "solutions" didn't provide me that. There was always some linked scripts which were loaded later than mine, timeout works sometimes, but only sometimes...
Plugins which i think could collide: Woocommerce, Easy FancyBox, Instagram Feed.
Thx for help!
[EDIT]
So, i need to change this:
<div class="foo">
<div class="bar">
<div class="destination">
</div>
</div>
<div class="origin">
</div>
</div>
To this:
<div class="foo">
<div class="bar">
<div class="destination">
<div class="origin">
</div>
</div>
</div>
</div>
My js code is:
var from = document.getElementsByClassName("origin");
jQuery("window").on("load",function(){
jQuery.each(from, function(i, el) {
jQuery(el.parentNode.parentNode).find(jQuery(".destination"))[0].appendChild(el);
});
});
And only what i need is to load it up last after all js files.
Also, the function which works sometimes looks that:
var from = document.getElementsByClassName("origin");
setTimeout(function() {
jQuery.each(from, function(i, el) {
jQuery(el.parentNode.parentNode).find(jQuery(".destination"))[0].appendChild(el);
});
},1);

instead of using $( document ).ready(function() { try to use $( window ).on( "load", function() {

You're over-complicating things ... especially by mixing vanilla JS DOM methods and jQuery so much.
$('.destination').each(function() {
$(this).parent().next().appendTo($(this));
})
For each .destination element, go up to its parent (.bar - could explicitly pass that selector into parent(), but there seems no need here), grab the next sibling of that - and append it to the current destination element we started with, done.
https://jsfiddle.net/a04fp226/
That wrapped into document ready should do the trick - provided the elements exist at that point already. If not, you need to figure out the correct time when to run this - that would depend on how those elements are created in the first place. If another script adds them on document ready, it becomes about execution order.

Related

How to separate content with .each() - jQuery

I have two hidden <div> elements which are hidden at the bottom of my page like so:
<div class="hidden-unit" style="display:none;">
<h1>ad unit one</h1>
</div>
<div class="hidden-unit" style="display:none;">
<h1>ad unit two</h1>
</div>
Further up my page I have another two div elements, like so...
<div class="visible-unit"></div>
<div class="visible-unit"></div>
I would like to loop through each of the hidden units, place the content from the first .hidden-unit into the first .visible-unit and then likewise for the second.
The content that sits within each .hidden-unit will actually be an inline script used for displaying ads, this is passed through from an array into a view that I have created in PHP so there is a strong possibility that more content could be added to the array or removed, so this loop needs to accommodate for such situations.
I have tried a number of solutions using jQuery's .each() but I can't seem to get it right. I've also created a JSFiddle should anyone want to demonstrate a solution:
https://jsfiddle.net/p89sq2df/3/
I've tried loads of different combinations and the latest attempt only seems to be populating the .visible-unit elements with the 'ad unit two' text.
$('.hidden-unit').each(function() {
$('.visible-unit').html($(this).html());
});
Anyone had to do anything like this before? I appreciate it's an odd one.
You can try using the index:
$('.hidden-unit').each(function(index) {
$('.visible-unit').eq(index).html($(this).html());
});
var visibleUnits = $('.visible-unit').toArray();
var x = 0;
$('.hidden-unit').each(function() {
visibleUnits[x].html($(this).html());
x++;
});
The gotcha is that there could be more .hidden-unit elements than .visible-unit elements, which would cause an exception. But this you put you on the right track.
You need to use the index the elements so you update matching instances. This can be done using each or html(function)
$('.visible-unit').html(function(index){
return $('.hidden-unit').eq(index).html();
});
Since you mention that the content is loaded by script originally, you may need to allow time for any asynchronous loading (if any) in the scripts
DEMO
Rather than trying to match indices and having to maintain two lists of divs, you can clone the hidden divs and add them to a container, or insert them before or after another element if you really don't want a container element.
$(".hidden-unit").clone()
.removeClass("hidden-unit")
.removeAttr("style")
.addClass("available-unit")
.appendTo(".container");
Working fiddle here: https://jsfiddle.net/ygn34zL8/

Backbone JS fire event upon rendering template

I'm using underscore.js template function to render templates in my views
<script type="text/html" id="friends-svg">
<%% if (this.model.get("returning_user")) { %>
<svg></svg>
<%% } else { %>
<div id="message-container">
<h3>You are a new User. Please wait while your Facebook Data is Loaded</h3>
<div id="progressbar"></div>
</div>
<%% } %>
</script>
For example the above code renders a div that I will target with jquery to create a progressbar if the user is not a returning user, and an svg element will be rendered that I will target with D3 if the user is a returning user.
The problem is that I believe my functions for creating the progressbar or for making the D3 graph are being called before the html in the template has been appended to the DOM. For example my plotData function is being called when the collection is fetched
this.listenTo(this.collection, "reset", this.plotData);
I have played around with where to call the function
this.createProgressbar()
But essentially I think I need to somehow create a custom event listener for when certain elements such as svg or #progressbar div are appended to the DOM. Is it possible to create a custom event/s for when these elements are appended to the DOM?
You may be interested in waitForKeyElements.js written by BrockA. Although the he has written it for userscripts, it may be helpful. It listens for the element and when it is added to the DOM it runs the function. That is what you are asking for but I don't think it is the best way to get what you want. I personally would just call the function that you would put in waitForKeyElements after your element has been placed in the DOM. In a userscript you can't do this because you can't just insert a function anywhere in the execution of the page. That is why this was create for userscripts and not just any script.
So if you went with waitForKeyElements you would have something like this:
waitForKeyElements ("svg", function(){doStuffToSVG});
waitForKeyElements ("#progressbar", function(){doStuffToProgressbar});
So when you run the code that inserts whichever element on the page it will call the function. This is almost the same as doing something like this:
<head><script src="js/progressBarFileToLoad.js"></script></head>
<body>
...
<svg></svg>
<script type="text/javascript">doStuffToProgressbar;</script>
...
</body>
But the waitForKeyElements way has an interval (setInterval) running every 300 milliseconds that is completely avoidable by the latter example. Not to mention the extra work that goes into clearing the other interval when you realize it isn't needed anymore and all the other stuff that you will need to do.
If you code is running before the element is added to the page then place it in your html after the element is added to the page. If for some reason you can't change when the element is added to the page and you can't change what all is added to the page then I guess listen for when it is added.
Also, if you decide to go with waitForKeyElements, be sure to read the comments in that file. It shows how to change the interval time and the iFrame to search for the element which could greatly improve performance.

After injecting html, a cached jQuery selector gives different result from non-cached selector

Found the solution! Don't bother creating an answer
Turns out I was injecting the html twice - once before creating the selectors, and then, due to some unfinished refactoring, a second time; thus overwriting the relevant parts of the DOM. The cached selectors were still referencing the old DOM part, though, and so kept it from being garbage collected. Changing the old part had, of course, no impact on the newer parts, something that was clearly shown by making jQuery do the selection anew.
Question
I am in the process of trying to create a widget. After running its script, the widget finds a with a certain code tag (referenced as $rootElem below), downloads a piece of html code and injects it into this div. After doing this, it starts attaching events to input elements, building ui elements like sliders, etc.
AFAIK, after injecting html into the DOM, the resulting DOM should be equivalent to just having the html there to begin with. Turns out that jQuery thinks otherwise. Just to be specific, I am first injecting the html, and second starting to find and cache selector results.
The following to code blocks should be equivalent (do the same thing); change a piece of html like <span>awaiting calculation ...</span> into something like <span>1234</span>. And, lo and behold, if I put all the html into the same document (not injecting it), they actually are doing the same thing.
Caching the selector result for later retrieval
var $result = $rootElem.find( "div.result p:nth-of-type(1) span" );
$.subscribe( "/server/calculateLoan/finished", function ( e, firstPayment ) {
$result.text( firstPayment ) );
} );
Doing the selection every time
$.subscribe( "/server/calculateLoan/finished", function ( e, firstPayment ) {
$rootElem.find( "div.result p:nth-of-type(1) span" ).text( firstPayment ) );
} );
But if I move the widget's html code out of the main document, and inject it before working on it, only the non-cached (latter) version works. Actually the first one also seems to work. If I set a break point in the anonymous function I can see a weird thing happening:
> $result.text()
<span>awaiting calculation ...</span>
> $rootElem.find( "div.result p:nth-of-type(1) span" ).text()
<span>awaiting calculation ...</span>
> $result.text("1234") //This is not showing in the browser window!
[<span>1234</span>]
> $result.text() //This is not showing in the browser window!
[<span>1234</span>]
> $($result.selector).text() //What kind of magic is this?!
<span>awaiting calculation ...</span>
> $rootElem.find( "div.result p:nth-of-type(1) span" ).text()
<span>awaiting calculation ...</span>
It seems as if the cached jQuery selector points to another DOM element (whose changes are not shown) than if I search for the same element. And this only happens when injecting the html, not when the widget's html has been copy-pasted into the page. Anyone cares to explain what is happening?
This happens in both Chrome and Firefox.
The html bit on the main page looks like this:
<div id="widget_calculator"><!-- dynamic fetch --> </div>
The widget's html
<h1>Widget calculator</h1>
<div class="user-inputs">...</div>
<div class="result">
<p><span>awaiting calculation ...</span></p>
</div>
The code that injects the html
function fetchHtmlTemplate( templateUrl ) {
// set globals
$ = jQuery;
$rootElem = $( "#widget_calculator" );
$.get( templateUrl, function ( htmlTemplate ) {
$rootElem.html( htmlTemplate );
buildWidget();
} );
}

Javascript not making div show

I'm having trouble making a div show up using javascript.
<div class=" notification success">
x
<p>An email has been sent confirming your identity.</p></div>
<script type="text/javascript">
var notification = '.notification';
$(notification).show();
</script>
</div>
Any ideas?
Place your jquery js in a document.ready() otherwise you cant ensure that the DOM is fully loaded and ready.
Your need is just a one liner like so
$(document).ready(function()
{
$('.notification').show();
});
You need to have double or single quotes surrounding the selector if you're naming a specific element ("#id", ".class").
Best way to do this is to avoid using the variable. It's just three extra characters anyways.
Also, put your code into a $(document).ready(function(){}); function like this:
$(document).ready(funciton(){
$(".notification").show();
});
To minimize the amount of code you're putting in, you can just use this instead:
$(function(){
$(".notification").show();
});
$(function(){}); can replace $(document).ready(), as by default jQuery selects the document.

Manipulating <body> with jQuery? (Or figuring a better solution)

I'm trying to create a JS-script to make modifications to add a footer to HTML -documents on the fly. The idea is to append a div-element at the end of the document to contain the footer, and to provide a floating fixed footer, I also need to have all of the other content wrapped in a div, basically I need something like this:
<html>
<head>
<title>Foobar</title>
</head>
<body>
<div id="contentWrapper">
<!-- Content is here -->
</div>
<div id="footerWrapper">
<!-- Footer goes here -->
</div>
</body>
</html>
The problem is, that the HTML is generated from a system where the end user's have had a little too much control over the structure (it's a blogging platform), and there's no guarantee of a certain sturcture hence I need to wrap the content in a div to ensure the footer works ok.
What I tried, and realized that doesn't work is:
$(document.body).wrap($('<div/>').attr('id','footerWrapper'));
The problem with this is that due to the fact that the HTML structure is generated by the user, I have been forced to inject links to the JS-file inside the <body>-tag. So now when I call wrap(), it seems that everything is first removed from $(document.body) and then appended in the new div. Since the JS-files are linked from inside , calling wrap() seems to remove them momentarily, and it seems that the scripts are unloaded by the browser and everything stops working and I'm left with a blank page. Not exactly what I had in mind.
Next idea was to first copy the JS-tags to the head-element to preserve them, so I wrapped them in a div (yeah, ugly, I know), and tried to copy them to the :
$(document.head).append($('#copyToHead').html());
That didn't do anything, and seems that $(document.head) isn't usable with functions such as .html() and .append().
So, now I'm out of ideas. Anyone have any ideas?
$(document.head) isn't usable with functions such as .html() and .append().
That would be because document.head is undefined
Use $("head")[0]
not clear on what your are trying to add to the head part. if you are simply trying to add a div to the end here is a solution:
$(document).ready(function(){
$(document.body).append($('<div></div>').attr('id','mydiv').html('This is footer'));
});
idea
If leave fact, that $(document.body) doesn't exist, wrapping everything into div and then setting id through attr might be problematic (don't ask me why—it just happens). So I played with it and created this little snippet (with preview, 100% working).
Since you can't play with html, but can "append" script I did whole document manipulation through inline script.
code
<script type="text/javascript">
$(document).ready(function(){
$("body")
.wrapInner('<div id="wrapper"/>')
.append('<div id="footer">footer text</div>');
});
</script>
preview
http://jsbin.com/ezoqo4/3
edits:
further simplification and proper markup generation
I believe this should serve you better:
$('body')
.children ().wrapAll ($('<div/>').attr('id','contentWrapper'))
.end ()
.append ($('<div/>').attr('id','footerWrapper'))
;
Ref: wrapAll

Categories

Resources