Calling a function from a button is easy in javascript:
b.onclick = f;
Calling a method from a button can also be done:
Myclass.prototype.m = function() {
var t = this;
b.onclick = t.f;
}
But we want to call a method of our class from a button through another function. Is there any way to do this without passing in the original object?
Here is the code that does not work. this.e is interpreted in the context of the button.
<!DOCTYPE html>
<html>
<body>
</body>
<script>
function A() {}
A.prototype.e = function() {
console.log("bar");
}
A.prototype.f = function() {
console.log("foo!");
this.e();
}
A.prototype.g = function() {
var b = document.createElement("button");
b.innerHTML = "say foo!";
b.onclick = this.f;
document.getElementsByTagName("body")[0].appendChild(b);
}
var a = new A();
a.g();
</script>
</html>
Use Function.prototype.bind to change the context of the this keyword to your a instance
<!DOCTYPE html>
<html>
<body>
</body>
<script>
function A() {}
A.prototype.e = function() {
console.log("bar");
}
A.prototype.f = function() {
console.log("foo!");
this.e();
}
A.prototype.g = function() {
var b = document.createElement("button");
b.innerHTML = "say foo!";
b.onclick = this.f.bind(this);
document.getElementsByTagName("body")[0].appendChild(b);
}
var a = new A();
a.g();
</script>
</html>
Since the flow interrupted you should bind the following
<!DOCTYPE html>
<html>
<body>
</body>
<script>
function A() {}
A.prototype.e = function() {
console.log("bar");
}
A.prototype.f = function() {
console.log("foo!");
this.e();
}
A.prototype.g = function() {
var b = document.createElement("button");
b.innerHTML = "say foo!";
b.onclick = this.f.bind(this)
document.getElementsByTagName("body")[0].appendChild(b);
}
var a = new A();
a.g();
</script>
</html>
Related
i like to pass to a function pointer to function that the addEventListener will use .
if you run this you will get an error .
what is the "Javascript" way to pass a function pointer ( don't know how to call it ) to addEventListener ?
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
<script>
var data = {
"foo1" : "aaa",
"foo2" : "bbb",
"foo3" : "ccc"
}
var createLabel = function(mykey,func) {
var label = document.createElement('label');
label.innerHTML = mykey;
label.id = "lbl_"+mykey;
label.addEventListener("click", () =>{
self.func(mykey);
}, false);
document.getElementById("container2").appendChild(label);
var br = document.createElement('br');
document.getElementById("container2").appendChild(br);
};
var popolateDS = function() {
self = this;
var i = 0;
for(var key in data) {
(function () {
var mykey = key;
if (data.hasOwnProperty(key)) {
if(i==0) {
createLabel(key,dsOnClick1);
i++;
}
createLabel(key,dsOnClick2);
}
}()); // immediate invocation
}
}
var dsOnClick1 = function(key) {
alert("dsOnClick1 "+key);
}
var dsOnClick2 = function(key) {
alert("dsOnClick2 "+key);
}
</script>
</head>
<body>
<div id="container2">
</div>
<button onclick="popolateDS()">click</button>
</body>
</html>
You don't need to refer to this as self.func, you can just call func like below and it'll work as expected:
label.addEventListener("click", () =>{
func(mykey);
}, false);
I am trying to make a pure js mvc app where I update an h1 with the text of an input field. I got to the point that the the value of the input in the model can be logged nicely but for some reason the h1 is not changing at all.
Could you give me some help that why is that and how to solve it?
my code:
window.onload = function() {
var model = new Model();
var controller = new Controller(model);
var view = new View(controller);
};
function Model() {
this.inputtext = "zzzzz";
this.heading = this.inputtext;
console.log('model called');
};
function Controller(model) {
var controller = this;
this.model = model;
this.handleEvent = function(e) {
switch (e.type) {
case "click":
controller.clickHandler(e.target);
break;
case "input":
controller.keyupHandler(e.target);
break;
default:
console.log(e.target);
}
}
this.getModelHeading = function() {
console.log("from getmodel: " + controller.model.inputtext + "heading " + controller.model.heading);
return controller.model.heading;
}
this.keyupHandler = function(target) {
controller.model.inputtext = target.value;
controller.getModelHeading();
}
console.log('controller called');
};
function View(controller) {
this.controller = controller;
this.heading = document.getElementById("heading");
this.heading.innerHTML = controller.getModelHeading();
this.inputtext = document.getElementById("inputtext");
this.inputtext.addEventListener('input', controller);
console.log('view called');
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" : content="width=device-width">
<title>Vanilla MVC Framework</title>
<script type="text/javascript" src="./Config.js"></script>
<script type="text/javascript" src="./Model.js"></script>
<script type="text/javascript" src="./Controller.js"></script>
<script type="text/javascript" src="./View.js"></script>
</head>
<body>
<input id='inputtext' /></input>
<h1 id='heading'></h1>
</body>
</html>
You need to link the view to the controller, then modify the view from the controller.
window.onload = function() {
var model = new Model();
var controller = new Controller(model);
var view = new View(controller);
};
function Model() {
this.inputtext = "zzzzz";
this.heading = this.inputtext;
console.log('model called');
};
function Controller(model) {
var controller = this;
this.model = model;
this.handleEvent = function(e) {
switch (e.type) {
case "click":
controller.clickHandler(e.target);
break;
case "input":
controller.keyupHandler(e.target);
break;
default:
console.log(e.target);
}
}
this.getModelHeading = function() {
// console.log("from getmodel: " + controller.model.inputtext + "heading " + controller.model.heading);
controller.model.heading = controller.model.inputtext;
return controller.model.heading;
}
this.keyupHandler = function(target) {
controller.model.inputtext = target.value;
controller.view.heading.innerHTML=controller.getModelHeading();
}
console.log('controller called');
};
function View(controller) {
this.controller = controller;
this.heading = document.getElementById("heading");
this.heading.innerHTML = controller.getModelHeading();
this.inputtext = document.getElementById("inputtext");
this.inputtext.addEventListener('input', controller);
controller.view = this;
console.log('view called');
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" : content="width=device-width">
<title>Vanilla MVC Framework</title>
<script type="text/javascript" src="./Config.js"></script>
<script type="text/javascript" src="./Model.js"></script>
<script type="text/javascript" src="./Controller.js"></script>
<script type="text/javascript" src="./View.js"></script>
</head>
<body>
<input id='inputtext' />
<h1 id='heading'></h1>
</body>
</html>
You update the h1 element only in the constructor of View class.
In keyUp event handler you update the only model but you haven't reassigned the view.heading.innerHtml value.
Only your View should know about where in DOM to display a model.property. Therefore, my suggestion to you add this code in your View:
function View(controller) {
var _self = this;
this.controller = controller;
this.heading = document.getElementById("heading");
updateHeading.call(_self);
this.inputtext = document.getElementById("inputtext");
this.inputtext.addEventListener('input', function(e){
controler.handleEvent(e);
updateHeading.call(_self);
});
console.log('view called');
function updateHeading(){
this.heading.innerHTML = controller.getModelHeading();
}
}
In the following code I get an error: TypeError: i.Print is not a function when the button is clicked. What is the cause of this error, and how do I fix it? Using Firefox debugger when I look at the value of i in the button's click handler, I see that i.prototype.Print has value Outer/Inner.prototype.Print().
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<p id="prn">Value here</p>
<button id='btn'>Print</button>
<script src="https://code.jquery.com/jquery-1.12.4.min.js">
</script>
<script>
function TestObject(i)
{
$("#btn").on("click", function() {
i.Print();
i.Change(Math.random() * 10 + 5);
});
}
function TestPrototype()
{
var o = function Outer() {
function Inner(v)
{
var iv = v;
function print()
{
$("#prn").text(iv);
}
};
Inner.prototype.Print = function() {
print();
console.log(iv);
};
Inner.prototype.Change = function(nv) {
iv = nv;
};
return {
getInner : function(v) {
var i = Inner;
i(v);
return i;
}
};
}();
var i1 = o.getInner(10);
TestObject(i1);
}
;(function() {
TestPrototype();
}());
</script>
</body>
</html>
You need to create an object using the constructor,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<p id="prn">Value here</p>
<button id='btn'>Print</button>
<script src="https://code.jquery.com/jquery-1.12.4.min.js">
</script>
<script>
function TestObject(i)
{
$("#btn").on("click", function() {
i.Print();
i.Change(Math.random() * 10 + 5);
});
}
function TestPrototype()
{
var o = function Outer() {
function Inner(v)
{
// instatiate member variables
this.iv = v;
this.print = print;
function print()
{
$("#prn").text(this.iv);
}
};
Inner.prototype.Print = function() {
// access member variable
console.log(this.iv);
this.print();
print();
};
Inner.prototype.Change = function(nv){
iv = nv;
};
return {
getInner : function(v) {
var i = Inner;
return new i(v);
}
};
}();
var i1 = o.getInner(10);
TestObject(i1);
}
;(function() {
TestPrototype();
}());
</script>
</body>
</html>
Let's say I want to replace all instances of options on a form (Agree/Disagree/Neutral). I can't seem to make this happen for any more than the first instance of each, rather than down the entire page.
Example
Here is where I'm at so far:
<script>
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(function() {
//Songwriting
sqsRadio = document.getElementsByClassName("option")[0].innerHTML;
myRadio = sqsRadio.replace("Strongly Disagree", "Fortement Désaccord");
document.getElementsByClassName("option")[0].innerHTML = myRadio;
sqsRadio = document.getElementsByClassName("option")[1].innerHTML;
myRadio = sqsRadio.replace("Disagree", "Désaccord");
document.getElementsByClassName("option")[1].innerHTML = myRadio;
sqsRadio = document.getElementsByClassName("option")[2].innerHTML;
myRadio = sqsRadio.replace("Neutral", "Neutre");
document.getElementsByClassName("option")[2].innerHTML = myRadio;
sqsRadio = document.getElementsByClassName("option")[3].innerHTML;
myRadio = sqsRadio.replace("Agree", "d'Accord");
document.getElementsByClassName("option")[3].innerHTML = myRadio;
sqsRadio = document.getElementsByClassName("option")[4].innerHTML;
myRadio = sqsRadio.replace("Strongly Agree", "Fortement d'Accord");
document.getElementsByClassName("option")[4].innerHTML = myRadio;
});
</script>
Am messing around with prototypes to get a better understanding of how they work. I can't work out why I can't call hideHeader, whereas I can access a variable (this.header.el)
function App() {
this.init();
this.el = document.getElementById('box');
}
App.prototype.init = function () {
document.write('hello world');
this.header = new Header();
this.header.hideHeader();
this.header.el.style.display = 'none';
};
new App();
function Header() {
this.el = document.getElementById('header');
}
Header.prototype.hideHeader = function() {
this.el.style.display = 'none';
}
You should reorder your code so that you define hideHeader before you try to invoke it.
Like this:
function App() {
this.init();
this.el = document.getElementById('box');
}
function Header() {
this.el = document.getElementById('header');
}
Header.prototype.hideHeader = function() {
this.el.style.display = 'none';
}
App.prototype.init = function () {
document.write('hello world');
this.header = new Header();
this.header.hideHeader();
this.header.el.style.display = 'none';
};
new App();
JavaScript is an interpreted language, it's not compiled. It is evaluated sequentially as it is loaded into memory.
You just need to change the order of how you are doing things. For example:
function App() {
this.init();
this.el = document.getElementById('box');
}
function Header() {
this.el = document.getElementById('header');
}
Header.prototype.hideHeader = function() {
this.el.style.display = 'none';
}
App.prototype.init = function () {
document.write('hello world');
this.header = new Header();
this.header.hideHeader();
this.header.el.style.display = 'none';
};
new App();
<div id="header"></div>
<div id="box"></div>