somebody help me how to bind a function to a dom async - javascript

My first js file content:
(function(){
var html = '<div class="wrapper"><a class="test">111</a></div>'
var app = document.getElementById('app');
setTimeout(function(){
app.innerHTML = html;
},10)
})()
My secondjs file content:
var app = document.getElementById('app');
app.addEventListener('click',function(e){
console.log(e.target);
e.target.addEventListener('click',function(){
alert(111)
})
});
Dom:
<div id="app"></div>
The question is how can I bind a function with dom 'test' by javascript, without Event commissioned. My English is not very good, hope you can understand and help me resolve this problem.

An old-school solution is set onclick handler directly on your a tag.
(function(){
var html = '<div class="wrapper"><a onclick="testClicked(event)" class="test">111</a></div>'
var app = document.getElementById('app');
setTimeout(function(){
app.innerHTML = html;
},10)
})()
function testClicked(e){
alert(111);
}
<div id= 'app'></div>

Don't use setTimeout to fix asynchronous loading issues. HTML5 parsing is asynchronous, and timing of when the setTimeout callback is invoked can be unpredictable. The DomContentLoaded event allows you to execute code when the document is ready in the order you specify:
document.addEventListener("DOMContentLoaded", function(){
var html = '<div class="wrapper"><a class="test">111</a></div>'
var app = document.getElementById('app');
app.innerHTML = html;
});
Notice the anonymous function is not immediately invoked using an IIFE and is instead called as an event handler. Listeners added to the same node are executed in the order they were added. If the second script is always loaded synchronously after the first, you can add a second event listener in the second file to find the .test element and add a click handler to it:
document.addEventListener("DOMContentLoaded", function() {
var app = document.getElementById('app');
app.querySelector("a.test").addEventListener('click',function(e){
alert(111);
});
});
This approach is an example and assumes that the JavaScript file structure presented in the question is the most suitable for the app - there will always be other ways of doing the same thing.
Run this snippet for a demonstration (does not use external script files):
<script>
document.addEventListener("DOMContentLoaded", function(){
var html = '<div class="wrapper"><a class="test">111</a></div>'
var app = document.getElementById('app');
app.innerHTML = html;
});
</script>
<div id="app"></div>
<script>
document.addEventListener("DOMContentLoaded", function() {
var app = document.getElementById('app');
app.querySelector("a.test").addEventListener('click',function(e){
alert(111);
});
});
</script>

Related

How to use hide() in Javascript

I am trying to hide a div the id of which I stored in a variable named 'post_container_id'. My code is:
document.addEventListener('DOMContentLoaded', function() {
// Add event listener to following button
document.querySelectorAll('.post-edit').forEach(item => {
var itemid = item.getAttribute('id').slice(5,)
item.addEventListener('click', () => edit_post(itemid));
})
});
function edit_post(itemid) {
var post_container_id = `#post-container-${itemid}`;
(function(){
$(post_container_id).hide(1000);
});
};
This does not hide the div. It does not throw any error either. The function does get triggered (I checked it by logging to console). What am I doing wrong?
There is a mistake here:
(function(){
$(post_container_id).hide(1000);
});
You are just declaring the function, you should also call it:
(function(){
$(post_container_id).hide(1000);
})();
Also, the callback is useless in this case, you can just solve it as:
function edit_post(itemid) {
var post_container_id = `#post-container-${itemid}`;
$(post_container_id).hide(1000);
};
$("#hide").click(function(){
edit_post(1);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="post-container-1">secret</div>
<button id="hide">Click to hide</button>
You can also use vanilla JavaScript to hide/show the element directly by changing the style display property. As follows
function edit_post(itemid) {
const post_container_id = document.querySelectorAll(`#post-container-${itemid}`);
post_container_id.style.display = 'none';
};
Without jQuery,
document.getElementById(post_container_id).style.display = "none"

improve code on updating content inside div

I learned that you can update a content inside div by using jQuery. I want to improve this code as the content is being change after it loads. I want it to be permanent regardless if it's loading or not.
Here's my code.
function changeContent () {
var myelement = document.getElementById("topbarlogin");
myelement.innerHTML= "HELLO";
}
window.onload = changeContent ;
This is my html code
<div class="signuplink" id="topbarlogin">Login</div>
Either call your function at the end of your body tag without window.load in script tag...
It will execute function() faster than the window.load
Stack Snippet
<body>
<div class="signuplink" id="topbarlogin">Login</div>
<script>
function changeContent() {
var myelement = document.getElementById("topbarlogin");
myelement.innerHTML = "HELLO";
}
changeContent();
</script>
</body>
...Or you can use DOMContentLoaded EventListener...it is equivalent to the $(document).ready() jQuery
function changeContent() {
var myelement = document.getElementById("topbarlogin");
myelement.innerHTML = "HELLO";
}
document.addEventListener("DOMContentLoaded", function(event) {
changeContent();
});
<div class="signuplink" id="topbarlogin">Login</div>
On DOM Ready use .html() to set HTML of div.
// This is you DOM Ready
$(function(){
// Set HTML using jQuery
$("#topbarlogin").html("HELLO");
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="signuplink" id="topbarlogin">Login</div>
Please try this
$("#topbarlogin").html("Hello");

How to pass data from content-script to page-level?

I'm injecting all my js code to front page, but it needs pictures for ui and stuff, that can be imported only with the help of chrome.extension.getUrl and can be called only from content-script, so I've found tons of advices how to pass data to content page, and nothing of about how pass data back, is it possible at all?
My code now looks like this:
my js code, that will be injected with other code:
var Content = {};
$(document).contentReady = function(content) {
Content = content;
$(document).ready(function () {/*cool stuff here, that require content*/});
}
var event = new CustomEvent('LoadContent');
window.dispatchEvent(event);
content-script:
document.querySelector('head').appendChild(jsCode);
window.addEventListener("LoadContent", function(evt) {
var content =
{
data: "url(" + chrome.extension.getURL('content.smth') + ")"
};
document.contentReady(content);
}, false);
And, obviously, I get document.contentReady is not a function
But declaring function in document was the only(!) advice of about how to pass data back from content-script after about 2 hours of googling.
Nothing stops you from making the CustomEvent-based communication bi-directional, and it can pass data with detail property:
// Page script
window.addEventListener('RecieveContent', function(evt) {
// do something cool with evt.detail
});
var event = new CustomEvent('LoadContent');
window.dispatchEvent(event);
// Content script
window.addEventListener('LoadContent', function(evt) {
content = /* ... */
var event = new CustomEvent('RecieveContent', {detail: content});
window.dispatchEvent(event);
});
A more in-depth answer can be found here.
However, you should ask yourself whether you even need the page-level script to query for data, since you fully control when it's injected. You can use uni-directional approach after you make sure the code has executed:
// Page script
window.addEventListener('RecieveContent', function(evt) {
// do something cool with evt.detail
});
// Content script
jsCode.onload = function() {
// This fires after the page script finishes executing
content = /* ... */
var event = new CustomEvent('RecieveContent', {detail: content});
window.dispatchEvent(event);
}
document.querySelector('head').appendChild(jsCode);
You can pass JS data to the page by creating a new script tag. For example:
function injectScript(code) {
var body = document.getElementsByTagName('body')[0];
var s = document.createElement('script');
s.innerHTML = code;
body.appendChild(s);
}
injectScript('var foo = 2;');
So for your particular example, you should be able to do:
injectScript('document.contentReady({data: url(' + blahblah + '})');
Not pretty (what is when you're working with overwriting content scripts?) but it works.
Content Scripts do not share window object with normal scripts on the page. Both of them work on different context.
In your case, you are registering an event listener on window and listening for the event on other context (window). Hence, your event listener will never be called.
However, there is one alternative approach I can see to communicate between content script and normal script is by using MutationObserver.
Idea
Define a node with some Id under which you will create subnodes corresponding to an event.
Register Mustation Observer in your script.
From content script, add the nodes with data as data-* api.
Implementation Example
Content Script
var submitEvent = function(category, action, label) {
var eventObserverPlaceholder = document.getElementById('events-observer-placeholder'),
$eventEl = $('<span></span>').attr({
'data-category': category,
'data-action': action,
'data-label': label
});
eventObserverPlaceholder.appendChild($eventEl.get(0));
};
Normal Script for registering Mutation Observer:
RQ.Methods.addObserverForEvents = function(targetNode) {
var observer = new MutationObserver(RQ.Methods.handleMutationList);
// Notify me when a new child is added
var observerConfig = {
attributes: false,
childList: true,
characterData: false
};
observer.observe(targetNode, observerConfig);
return observer;
};
RQ.mutationObserver = RQ.Methods.addObserverForEvents(document.getElementById('events-observer-placeholder'));
Links
https://davidwalsh.name/mutationobserver-api
https://developer.mozilla.org/en/docs/Web/API/MutationObserver
Working Example:
I have used the same approach in Requestly Chrome Extension for submitting events to Google Analytics.
Content Script: https://github.com/requestly/chrome-extension/blob/master/src/Shared/utils.js#L26
Normal Script: https://github.com/requestly/web/blob/gh-pages/js/scripts/tracker.js#L35

Function out of scope?

I have a function defined as follows:
window.onload = function() {
var ids = document.getElementById("idname");
function myFunction(){
/...*use ids var in here*./
}
}
I am trying to call myFunction from button onclick in html:
<button onclick="myFunction();"></button>
But it says myFunction is not defined. I understand because this is inside window.onload. How can I fix this? I need window.onload because I need to use document.getElementById("testID") to get content.
I need window.onload because I need to use document.getElementById("testID") to get content
No, you don't need window.onload. You simply have to put the code somewhere after the element with ID testID in the document.
Example:
<div id="testID"></div>
<script>
var ids = document.getElementById("testID");
function myFunction(){
/...*use ids var in here*./
}
</script>
However, if you want to keep using window.onload, then I suggest to not use inline event handlers, but bind the handler with JS:
window.onload = function() {
var ids = document.getElementById("testID");
ids.onclick = function(event){
/...*use ids var in here*./
}
};
(that might be a good thing to do anyway).
Lastly, you can get the a reference to the element inside the event handler using this or event.target:
<div id="testID"></div>
<script>
document.getElementById("testID").onclick = function(event) {
// access element via `this` or `event.target`
};
</script>
Learn more about event handling.
You defined it within a function so it's locked to that scope. Maybe you want to define it outside of that:
function myFunction() {
var ids = document.getElementById("idname");
// ...
}
window.onload = function() {
// ...
}
As a note, this is extremely old-school JavaScript. You could clean this up considerably using something like jQuery which would look something like this:
$(function() {
// Any initialization after page load.
});
function myFunction() {
var ids = $('#idname');
// ...
}

The difference between using a self invoking function and document ready

How come this doesn't work in loading header content...
(function ($) {
var mheaderwrapper = '<div id="header"></div><div class="header-menu"></div>';
var mheadercontent = '/shop/Pages/global_header.html';
var mmenucontent = '/shop/Pages/global_megamenu.html';
var mjqueryhover = 'js/jquery.hoverIntent.minified.js';
var mjquerymenu = 'js/jquery.custom-menu.js';
$('#wrapper').prepend(mheaderwrapper);
$('#header').load(mheadercontent);
$('.header-menu').load(mmenucontent, function(){
$.getScript(mjqueryhover);
$.getScript(mjquerymenu);
});
})(jQuery);
but this does...
$.mheader = function() {
var mheaderwrapper = '<div id="header"></div><div class="header-menu"></div>';
var mheadercontent = '/shop/Pages/global_header.html';
var mmenucontent = '/shop/Pages/global_megamenu.html';
var mjqueryhover = 'js/jquery.hoverIntent.minified.js';
var mjquerymenu = 'js/jquery.custom-menu.js';
$('#wrapper').prepend(mheaderwrapper);
$('#header').load(mheadercontent);
$('.header-menu').load(mmenucontent, function(){
$.getScript(mjqueryhover);
$.getScript(mjquerymenu);
});
}
$(function() {
$.mheader();
});
This :
(function ($) {....})(jQuery);
executes immediately, and only maps jQuery to $ to make sure the dollar sign really is "jQuery" within the self executing function. It's not a "DOM ready" function.
This:
$(function() {....});
will wait until the DOM is ready before any code is executed.
You can use the second one inside the first one :
(function ($) {
$(function() {
//code here
});
})(jQuery);
to do both!
When you have a function in the <head> section like that, it is executing immediately, and is doing so before your HTML elements have started loading. Your elements #wrapper, #header, and anything with the .header-menu class do not yet exist at the time your code is executing, which is why it fails.
In the second example, using the domready event delays the firing of your code until after the DOM is ready (and your HTML elements exist), so the code works.
By the way,
$(function() {
// executes when DOM is ready
});
is just a shortcut for:
$(document).ready(function() {
// executes when DOM is ready
});
The above examples are specifically functionality provided by jQuery. Don't confuse the former with the immediately-executing function structure, which is pure JavaScript:
(function() {
// executes NOW
})();
See adeneo's answer for how to properly combine the two.
$(document).ready actually runs after the DOM is created.
Self-invoking functions run instantly if inserted into <head> section, before the DOM is constructed.

Categories

Resources