JavaScript: function fires in different order - javascript

I don't understand why function alert() fires before setting style to indicator in this code:
JavaScript:
var MyClass = function()
{
th = this;
th.func = function(){alert('yes');};
th.Click = function(){
document.getElementById('indicator').style.color = "#0f0";
document.getElementById('indicator').innerHTML = "YES";
th.func(); // here it fires before above style changing
};
th.Start = function()
{
var a = document.getElementById('button1');
a.addEventListener('click', th.Click, false);
};
th.Init = function()
{
th.Start();
};
}
var a = new MyClass().Init();
Html:
<button id='button1'>Click Me</button>
<div id='indicator' style='color:#f00'>NO</div>
I want it to fire after.

That is because of the Single Threaded Nature of the Javascript. The alert / modal window actually stops everything else from running until it is dismissed.
That includes the changing of color. Javascript actually says hey browser start changing colors and moves on but as it hits an alert the changing of colors or whatever processes that happen will be paused and it will not start continuing again until the modal window aka alert is dismissed. A workaround might be to do something like this: codepen
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<button id='button1'>Click Me</button>
<div id='indicator' style='color:#f00'>NO</div>
<script type="text/javascript">
var MyClass = function() {
th = this;
th.func = function() { window.alert('yes'); };
th.Click = function() {
document.getElementById('indicator').style.color = "#0f0";
document.getElementById('indicator').innerHTML = "YES";
// The setTimeout fix
// ====
setTimeout(th.func, 100);
};
th.Start = function()
{
var a = document.getElementById('button1');
a.addEventListener('click', th.Click, false);
};
th.Init = function()
{
th.Start();
};
}
var a = new MyClass().Init();
</script>
</body>
</html>

Related

How to add JavaScript to newly created document with DOMImplementation.createHTMLDocument()

The following code snippet creates a new DOM document with a button inside it and adds it to an iframe.
I want to add a JavaScript code inside the new DOM document so that when I click the button id dose something like alert.
I tried the following code but it doesn't work.
<html>
<head>
</head>
<body>
<p><button id="btn" >Click Here</button> to create a new document and insert it below.</p>
<iframe id="theFrame" src="about:blank"></iframe>
<script type="text/javascript">
document.getElementById("btn").onclick = function () {
var frame = document.getElementById("theFrame");
var doc = document.implementation.createHTMLDocument("New Document");
var button = doc.createElement("button");
button.innerHTML = "Alert";
button.setAttribute("id","btn1");
var script = doc.createElement("script");
script.innerHTML = "document.getElementById('btn1').onclick = function() {alert('button clicked!')};";
try {
doc.body.appendChild(button);
} catch(e) {
console.log(e);
}
try {
doc.body.appendChild(script);
} catch(e) {
console.log(e);
}
// Copy the new HTML document into the frame
var destDocument = frame.contentDocument;
var srcNode = doc.documentElement;
var newNode = destDocument.importNode(srcNode, true);
destDocument.replaceChild(newNode, destDocument.documentElement);
}
</script>
</body>
You really don't need to create a new document.
Just get a reference to the document within the frame and do everything within that context.
document.getElementById("btn").onclick = function () {
var frame = document.getElementById("theFrame");
// reference to the iframe document instead of createHTMLDocument
var doc = frame.contentDocument
var button = doc.createElement("button");
button.innerHTML = "Alert";
button.setAttribute("id","btn1");
var script = doc.createElement("script");
script.innerHTML = "document.getElementById('btn1').onclick = function() {alert('button clicked!')};";
try {
doc.body.appendChild(button);
} catch(e) {
console.log(e);
}
try {
doc.body.appendChild(script);
} catch(e) {
console.log(e);
}
}
Plunker demo

Refer JS object in HTML element generated by this object

My JavaScript object create some HTML elements (two buttons for example) and after user click on these buttons I should call some method of this object. So the question is how I can refer JS object in HTML element to call its method?
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Title Goes Here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
function myObj(){
this.a = null;
this.setA = function(a){
this.a = a;
}
this.requestA = function(){
$( "body" ).append($('<input><button onclick="referenceToMyObject.setA($(this).prev().val());">Set A</button>'));
}
return this;
}
</script>
</head>
<body>
<script>
var myObjInst = myObj();
myObjInst.requestA();
</script>
</body>
Creating the event handler inline (onclick="foo()") won’t allow you to reference the object, and is discouraged in any case because you should avoid evaluating strings as code. In addition, your code bypasses JavaScript’s idea of objects somewhat. You can reformulate it as follows:
function MyObj() {
this.a = null;
}
MyObj.prototype.setA = function(a) {
const old = this.a;
this.a = a;
console.log("Updated a from", old, "to", this.a);
};
MyObj.prototype.requestA = function() {
const input = $("<input type='text'>");
const button = $("<button>Set A</button>");
button.click((e) => {
this.setA($(e.target).prev().val());
});
const body = $("body");
body.append(input);
body.append(button);
};
$(document).ready(() => {
const myObjInst = new MyObj();
myObjInst.requestA();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Here, we use button.click to define the event handler and new MyObj() to instantiate the object. Apart from that, I cleaned up the code a bit and added a bit of logging so you can see what’s going on.
You could still define setA and requestA within the constructor, as you do in your example. I chose to define them on the prototype since their behaviour is the same across instances.
Try this and please let me know if this works for you.
(working example in JSFiddle https://jsfiddle.net/galeroy/9nocztk4/1/)
<!doctype html>
<html>
<head>
<script>
var myObject = {
createButton: function(){
var p = document.getElementById('par')
var b = document.createElement('button');
b.innerHTML = 'click me';
b.setAttribute('onclick', 'myObject.myMethod()'); // this is the important part
p.appendChild(b);
},
myMethod: function(){
alert("Button created by object, when clicked, calls another method in the same object")
}
}
function init(){
myObject.createButton();
}
</script>
</head>
<body onload="init()">
<p id="par"></p>
</body>
</html>

Wrapping an object with a delegate

A bad title and this might not be the best way to do what I'm trying to do (still learning javascript) but I'm trying to wrap a object using a delegate. The object in this case is an XMLHttpRequest.
var wrapper = function() {
this._delegate = /* get the delegate */
this._delegate.onreadystatechange = function() {
wrapper.readyState = this.readyState;
/* stuff that synchronizes wrapper goes here */
if(wrapper.onreadystatechange) {
wrapper.onreadystatechange();
}
};
return this;
}
The above is a simplification but when problem is that when I add an onreadystatefunction to the wrapper object like:
wrapper.onreadystatechange = function() {alert("hi)};
and the wrapper._delegate.onreadystatechange function is called, wrapper.onreadystatechange is always undefined and the alert popup never comes up. I think I'm getting my scope stuff wrong but I'm not exactly sure how to fix this. Would appreciate other suggestions but I would also like to know how to fix what I'm doing wrong. Thanks!
EDIT
Yup it was an incomplete example. sorry about that. I realized after trying to rewrite it into a complete example what my cause my issue. It seems if I don't have the outer "WRAP_FUNCTION" then it will work fine. I had written something like
WRAP_FUNCTION = (function() {
var originalXMLHttpRequest = window.XMLHttpRequest;
var wrapper = function() {
if(wrapper.wrapped) {
this._delegate = new originalXMLHttpRequest;
} else {
this._delegate = new window.XMLHttpRequest
}
this._delegate.onreadystatechange = function() {
wrapper.readyState = this.readyState;
/* stuff that synchronizes wrapper goes here */
if(wrapper.onreadystatechange) {
wrapper.onreadystatechange();
}
};
return this;
};
wrapper.prototype.open = function(method, url, async) {
this._delegate.open(method, url, async);
}
wrapper.prototype.send = function() {
this._delegate.send();
}
wrapper.wrapped = true;
return wrapper;
}
window.XMLHttpRequest = WRAP_FUNCTION;
HTML code:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="xmlhttp.js"></script>
<script type="text/javascript">
(function() {
var test = new XMLHttpRequest();
test.open("GET", "xmlhttp.js", true);
test.onreadystatechange=function()
{
if (test.readyState==4 && test.status==200)
{
alert("yay");
}
};
test.send();
})();
</script>
</body>
</html>
Try this.
var wrapper = function() {
// in this time var wrapper not yet defined completly
// if you want use wrapper on the finction
// need to use this instead of wrapper
var self= this;
this._delegate = /* get the delegate */
this._delegate.onreadystatechange = function() {
//this means _delegate is in this time
//if you want to use this(wrapper)
//set the value out of function
//like var self= this
//wrapper.readyState = this.readyState;
self.readyState = this.readyState;
/* stuff that synchronizes wrapper goes here */
//if(wrapper.onreadystatechange) {
// wrapper.onreadystatechange();
//}
if(self.onreadystatechange) {
self.onreadystatechange();
}
};
return this;
}

onscroll div in a JavaScript object

i want to build a div with scroll, that when you scroll this div, it will active anothe function.
i need to build this in a Object.
there is any way to do this?
i write here an example source (that not work) of what i want.
<script type="text/javascript">
function onsc(divName, divChange) {
this.play = function() {
window.onload = function() {
document.getElementById(divName).onscroll = function() {
this.scroll(n)
}
};
}
this.scroll = function(n) {
document.getElementById(divChange).innerHTML = "you scroll!";
}
}
c[1] = new onsc("div1", "div1_i").play();
</script>
<div id="div1_i">this div will change when you scroll</div>
<div id="div1" style="background:#C6E2FF; width:300px; height:200px; overflow-y:scroll;">
<p style="height:800px;">txt</p>
</div>
Your code was nearly there. I made a few changes and put into a JSFiddle for you.
I added comments at what you missed. Most importantly the context of this changes when you entered into that function on the onscroll event.
JavaScript
function onsc(divName, divChange) {
// First of all make `this` inherit to below functions
var self = this;
this.play = function () {
document.getElementById(divName).onscroll = function() {
// Changed this to call the parent and place the correct DIV
self.scroll(divChange)
}
}
this.scroll = function (n) {
document.getElementById(divChange).innerHTML = "you scroll!";
}
}
c = new onsc("div1", "div1_i").play();
Demo
Have a look at my JSFiddle: http://jsfiddle.net/bJD8w/2/

oninput event fires once. May also have a scope issue

Good Evening,
I am having trouble with modifying the date value in my test object. The oninput event seems to only fire once when the document is loaded. The oninput event does not seem to fire when the date is changed.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
var TestObj = new function(){
this.date = "2014-01-01";
this.LoadMenu = function() {
var newDateInput = document.createElement('input');
newDateInput.type = "date";
newDateInput.value = this.date;
document.getElementById("container").appendChild(newDateInput);
newDateInput.oninput = this.updateDate(newDateInput.value);
};
this.updateDate = function (newDate){
this.date = newDate;
alert(this.date);
document.getElementById("outputBox").innerHtml = this.date;
};
};
</script>
</head>
<body onload="TestObj.LoadMenu();">
<div id="container">
<div id="outputBox">Test</div>
</div>
Chrome: 34.0.1847.116
This is caused because of the way you are trying to associate the handler function of your event, in your code you have:
newDateInput.oninput = this.updateDate(newDateInput.value);
but what you might want is:
newDateInput.oninput = this.updateDate;
Also, if you want this to work properly you might want to declare the newDateInput in the outer scope (in the scope of the "class").
I think what you want to do is something like this:
var TestObj = new function(){
this.date = "2014-01-01";
var newDateInput;
this.LoadMenu = function() {
newDateInput = document.createElement('input');
newDateInput.type = "date";
newDateInput.value = this.date;
document.getElementById("container").appendChild(newDateInput);
newDateInput.oninput = this.updateDate;
};
this.updateDate = function (event){
this.date = newDateInput.value;
alert(this.date);
document.getElementById("outputBox").innerHTML = this.date + '';
};
};
Please let me know if that works for you.

Categories