I have as basic onClick in a button that outputs an alert
function test(){
alert('here');
}
<button onClick="test()">Press</button>
In StackBlitz this doesn't work - https://stackblitz.com/edit/js-umarwe?embed=1&file=index.js&hideNavigation=1
Is this because of ES6
How does this work in ES6
Why it doesn't work
The reasons it is not working is that behind Stackblitz there is an asset building system which treats your Javascript code as modules.
That means that variables defined in those modules are only available inside those modules and do not become attached to the global namespace (as you expected and seem to be used to).
Minimum required to fix it
To achieve that, you need to explicitly attach those variables to the global object, which inside a browser happens to be window.
Simply adding the following line at the end of your index.js file makes your code work:
window.test = test;
A better way
Please note that using inline event handlers directly on the element (like onclick) is considered bad practice (and does have practical disadvantages, but that would lead too far). Instead, you should use Javascripts Element.prototype.addEventlistener() function. Steps to get there:
Add an id to your button so your Javascript can find it:
<button id="testButton">Press</button>
Next, put that element in a variable:
const button = document.getElementById('testButton');
Last step: Add the event listener for the click event:
button.addEventListener('click', test)
Here's the full index.js for that refactored version:
// Import stylesheets
import './style.css';
function test(){
alert('here');
}
const button = document.getElementById('testButton');
button.addEventListener('click', test);
How to make it even safer and better
One more note: If you place the script tag loading the Javascript in the head section of the document, you either need to add a defer attribute on the tag, or wrap the part of the code that needs to access the DOM in a DOMContentLoaded event handler:
// Import stylesheets
import './style.css';
function test(){
alert('here');
}
document.addEventListener('DOMContentLoaded', function () {
const button = document.getElementById('testButton');
button.addEventListener('click', test);
}
Otherwise the HTML has not yet been parsed by the browser when your Javascript tries to find the button and attach the event listener.
Modify test function declaration in index.js file:
window.test = function(){
alert('here');
}
It doesn't recognize test function on click event because test function you declared is not in the same scope.
You can do this.
window.test = () =>{
alert('here');
}
I don't know stackBlitz..
but, I understand loading index.js
so window.test = () => {} ...
Related
I'm looking for a way to pass functions as parameters to the script tag. For example, to make the following work:
<script src="http://path/to/widget.js?param_a=1¶m_b=3" data-myfunc={myfunction()}></script>
<script>
myfunction() {
console.log("hello world")
}
</script>
And then trigger the function from the script.
Since we can pass values in attributes and capture using getAttributes : ref
Try this
<script>
// move function definition above and pass function ref - don't call that function
myfunction(){
console.log("hello world")
}
</script>
<script src="http://path/to/widget.js?param_a=1¶m_b=3" data-myfunc={myfunction}></script>
Yes there is a way!
you can delete the " () "
just turn :
<script src="http://path/to/widget.js?param_a=1¶m_b=3" data-myfunc={myfunction()}></script>
into:
<script src="http://path/to/widget.js?param_a=1¶m_b=3" data-myfunc={myfunction}></script>
And over!
It's my pleasure to help you!
by the way if you are interested, please help me also:
The is my question
that's pretty easy however it won't be accurate as you don't know which script tag will work first or if it will be compiled using inline or not.
if it uses inline your code will not work and you have to use the server to render javascript instead
here is an example using pure javascript. in my understanding you want after loading script /widget.js it will execute function stored in data-myfunc:
widget.js
if (document.currentScript) {
const script = document.currentScript.getAttribute('data-myfunc')
if (script) {
new Function(`
// sandbox faker
const window = undefined;
const document = undefined;
const Document = undefined;
const Window = undefined;
// run script
${script}
`)()
}
} else {
console.warn('widget.js loaded inline. Not working')
}
note if you want to declare the function myFunc after the script /widget.js you have to edit my code to use events like DOMContentLoaded to make sure the function exists
I'm trying enter code here in to execute an imported module from a HTML page. I get to see that it's partially getting executed. I need help. My code files are test.html, main.js and say.js. These files are produced below in the same order.
test.html:
<html>
<head>
<script type="module" src="./main.js"></script>
</head>
<body onload="sayHi('Manish')">
</body>
</html>
main.js:
import { sayHi } from './say.js';
sayHi('MK');
say.js:
export function sayHi(user) {
alert('Hello, { $user }');}
This code partially executes
Then after this partial execution, it gives an error
Uncaught ReferenceError: sayHi is not defined
at onload (test.html:7)
The picture of the error is as shown below:
This is the error that says sayHi function is not recognized. Why?
What am I doing wrong here?
One of the great things about modules is that top level declarations, etc., in them don't create globals. One of the bad things about onxyz-attribute-style event handlers is that the functions you call with them have to be globals. Your sayHi isn't a global, so onload="sayHi('Manish')" fails because it doesn't have access to sayHi.
Which is a good thing.
Instead, just call the function from main.js:
import { sayHi } from './say.js';
sayHi('MK');
sayHi('Manish');
Because module scripts are automatically deferred until the end of HTML processing, you know that won't happen until all the HTML is loaded. This is covered by a great graphic in this section of the spec, duplicated here:
If you want to wait longer, until the load event (which doesn't fire until all images and such are loaded), use a modern event handler to do that:
import { sayHi } from './say.js';
sayHi('MK');
window.addEventListener("load", () => {
sayHi('Manish');
});
If you need information from the element you hooked the event on, use a traditional function and access the element as this, or accept the event parameter and use event.currentTarget (you can also use event.target for the element that the event targets, which could be within the element you hooked the event on). So for instance, suppose you have:
<button type="button" data-name="Manish" id="btn-say-hi">
you could have:
import { sayHi } from './say.js';
document.getElementById("btn-say-hi").addEventListener("click", function() {
sayHi(this.getAttribute("data-name"));
});
Also note that as Vikas Saini pointed out your say.js is using a string literal instead of a template literal (and although he/she didn't mention it, also has the wrong syntax for a substitution), so you'll actually see the text Hello { $user } instead of seeing Hello MK or Hello Manish. Either use a template literal with the correct form of substitution (${user}, not { $user }):
export function sayHi(user) {
alert(`Hello, ${user}`);
}
or simple string concatenation:
export function sayHi(user) {
alert("Hello, " + user);
}
Classic case of String interpolation
Use
export function sayHi(user) { alert(`Hello, ${user}`);}
Notice ` in place of ' or "
Reference https://campushippo.com/lessons/how-to-do-string-interpolation-with-javascript-7854ef9d
For the Error, bind the window to load
window.addEventListener("load", () => {
sayHi('testing');
});
Basically my objective was to pass some parameter from the HTML script to the main.js file. I have got the required after both of you have given me hints, especially Vikas Saini. The suggestion of adding an event listener in the main.js file helped a lot. Thanks much. I'm posting the corrected and the latest code files for the benefit of ES6 beginners like me.
The test.html file contents
<html>
<head>
<script type="module" src="./main.js"></script>
</head>
<body>
<input type="text" id="btn-say-hi"label="fill here" placeholder="Fill in here and click"/>
</body>
</html>
The main.js file contents
import { sayHi } from './say.js';
document.getElementById("btn-say-hi").addEventListener("click", function() {
sayHi(this.value);
});
The say.js file contents
export function sayHi(user) { alert(`Hello, ${user}`); }
Kindly note: All these files are in the same directory/folder. I could change the text item value and could get the required execution based on my inputs.
Thanks much to T.J. Crowder and a special thanks to Vikas Saini for the code snippet pertaining to adding the event listener. That was a golden suggestion.
Thanks much guys.
Regards
Manish.
I have anonymous function where I wrapped all javascript code inside (main.js). I pass global variable to one of function inside. But the problem is that variable is created after main.js is loaded. I could use jQuery document ready, but I don't want to wait entire document to be loaded.
main.js
(function(){
function example(){
alert(globalVariable)
}
})();
and phtml file that is loaded after
<script>var globalVariable = 'example'</script>
Is there any way to create custom listener and when this is created example() should be forced? Something like that (just as example to show what I need):
main.js
(function(){
listen(mycustomlistener){
function example(){
alert(globalVariable)
}
}
})();
phtml file
<script>
var globalVariable = 'example'
create listener(mycustomlistener)
</script>
Where is the trigger that you expect from? Is it triggered by you or from an event or from a change?
If it is listener/observer design u are looking for. You could implement your own or use the one available in backbone.wreqr
http://zen-and-art-of-programming.blogspot.in/2013/12/backbonewreqr-jumpstart.html
Also from the above code even though you create a listener your example function wont be called since it is just a functon declaration inside and not the call i.e make it
var eventAggregator = new Backbone.Wreqr.EventAggregator();
//Subscribe for the event!
eventAggregator.on('eventName', function() {
(function example(){
alert(globalVariable)
})(); //observe the call i ve made here which is absent in urs!!!
});
//Raise the event!
eventAggregator.trigger('eventName');
You could also use jquery observer and observable
https://gist.github.com/addyosmani/1321768
This should help you out in what you want.
http://jsbin.com/mugage/1/edit?html,js,output
In and external JS file I have
$(document).ready(function() {
var example = function(){ alert("hello") }
});
and I want to call that function from my html, how would I do that?
<img src="..." ondblclick="example()" />
n.b. I'm aware of jquery dblclick() but curious about how to correctly do the above.
$(document).ready(function() {
window.example = function() {
alert("hello")
}
});
Or define it outside, if possible. It doesn't look like it has to be defined inside document ready at all.
The other solutions here will work, but structurally in your project, the best solution is to remove the event handling code from the HTML and hook up the event entirely via javascript (separate the HTML/JS). Since you already have jQuery in your project, this is very easy. To do that, all you need to do is to put some sort of identification on the image:
<img id="example" src="..." />
Then, in you can just hook up the event code in your ready() function like this
$(document).ready(function() {
$("#example").dblclick(function() {
alert("Hello");
});
});
This has the following advantages:
It creates no global variables - reducing the global namespace pollution.
It separates the HTML from the javascript which keeps all code governing the behavior in one compact spot and is usually a good thing
Using event listeners is a bit more scalable than using .ondblclick - allowing multiple different parts of code to use non-conflicting event handlers on the same object
Your function should be global (in fact, property of window object) if you want to access it from HTML. But best practice is to avoid global variables and functions, using namespace instead:
// let's publish our namespace to window object
if (!window.myNamespace){
// creating an empty global object
var myNamespace = {};
}
// and add our function to it
$(document).ready(function() {
myNamespace.example = function(){ alert("hello"); }
});
We can use it in HTML like this:
<img src="..." ondblclick="myNamespace.example()" />
The best option would be to simply define the function outside document.ready(). There is no reason defining the function within the $(document).ready() event is necessary, as if you call the function within the $(document).ready() function, the document is guarenteed to be ready.
However, you can also define the function on the global window object, like so:
$(document).ready(function() {
window.example = function(){ alert("hello") }
});
You can either move the function declaration outside of the DOM-ready handler:
function example(){ alert("hello") }
$(document).ready(function() {
// code
});
But the better solution is to keep JavaScript in your .js files and avoid the inline event handlers. Give your element an id and fetch it:
<img src="..." id="imgid" />
$(document).ready(function() {
document.getElementById("imgid").ondblclick = function(){ alert("hello") }
});
#Esailija has answered it correctly but if you want to keep it as it is then simply remove var and make it global.
var example;
$(document).ready(function() {
example = function() {
alert("hello")
}
});
If you do not put var the variable/function/object becomes global. Using var you were setting its context within document.ready function.
When I use code like this, it works fine:
function removeWarning() {
var systemStatus = document.getElementById("system-status");
systemStatus.innerHTML = "";
}
function indicateInvalidUsername() {
var systemStatus = document.getElementById("system-status");
systemStatus.innerHTML = "Invalid username";
}
However, when I then want to move the systemStatus to be a global variable, it doesn't work:
var systemStatus = document.getElementById("system-status");
function removeWarning() {
systemStatus.innerHTML = "";
}
function indicateInvalidUsername() {
systemStatus.innerHTML = "Invalid username";
}
What am I supposed to be doing here?
It really depends on where your JavaScript code is located.
The problem is probably caused by the DOM not being loaded when the line
var systemStatus = document.getElementById("system-status");
is executed. You could try calling this in an onload event, or ideally use a DOM ready type event from a JavaScript framework.
Make sure you declare the variable on "root" level, outside any code blocks.
You could also remove the var altogether, although that is not recommended and will throw a "strict" warning.
According to the documentation at MDC, you can set global variables using window.variablename.
My guess is that the system-status element is declared after the variable declaration is run. Thus, at the time the variable is declared, it is actually being set to null?
You should declare it only, then assign its value from an onLoad handler instead, because then you will be sure that it has properly initialized (loaded) the element in question.
You could also try putting the script at the bottom of the page (or at least somewhere after the system-status element is declared) but it's not guaranteed to always work.
Declare systemStatus in an outer scope and assign it in an onload handler.
systemStatus = null;
function onloadHandler(evt) {
systemStatus = document.getElementById("....");
}
Or if you don't want the onload handler, put your script tag at the bottom of your HTML.
A global variable would be best expressed in an external JavaScript file:
var system_status;
Make sure that this has not been used anywhere else. Then to access the variable on your page, just reference it as such. Say, for example, you wanted to fill in the results on a textbox,
document.getElementById("textbox1").value = system_status;
To ensure that the object exists, use the document ready feature of jQuery.
Example:
$(function() {
$("#textbox1")[0].value = system_status;
});
To define a global variable which is based off a DOM element a few things must be checked. First, if the code is in the <head> section, then the DOM will not loaded on execution. In this case, an event handler must be placed in order to set the variable after the DOM has been loaded, like this:
var systemStatus;
window.onload = function(){ systemStatus = document.getElementById("system_status"); };
However, if this script is inline in the page as the DOM loads, then it can be done as long as the DOM element in question has loaded above where the script is located. This is because javascript executes synchronously. This would be valid:
<div id="system_status"></div>
<script type="text/javascript">
var systemStatus = document.getElementById("system_status");
</script>
As a result of the latter example, most pages which run scripts in the body save them until the very end of the document. This will allow the page to load, and then the javascript to execute which in most cases causes a visually faster rendering of the DOM.