Use prototype javascript in dom element - javascript

Forgot my initial typo in original snippet here is exaly want I trying to do:
How can I use prototyped variable in Dom element event?
Suppose :
function MyProto(){
this.valeur = "toto";
}
MyProto.prototype = {
func1: function() {
var t = document.createTextNode("func1 called ");
document.body.appendChild(t);
var br = document.createElement("br");
document.body.appendChild(br);
this.func2();
},
func2: function() {
var t = document.createTextNode("func2 called");
document.body.appendChild(t);
}
};
var proto = new MyProto();
document.getElementById("myButton").addEventListener("click",proto.func1);
<button id="myButton">Press here</button>
In this example, when I press button it throw me this.func2 is not a function. I must to mention that ultimately the Dom element will be generated by HtmlHelper from Asp.Net MVC.

First Problem
That's just a typo, you are calling funct1 instead of func1
Second Problem (Update)
The problem is when you add the listener your way:
.addEventListener("click",proto.func1)
this will be the clicked element, not your proto instance, to solve this problem you can wrap it in another function clause, like the snippet below.
function MyProto() {
this.valeur = "toto";
}
MyProto.prototype = {
func1: function() {
var t = document.createTextNode("func1 called ");
document.body.appendChild(t);
var br = document.createElement("br");
document.body.appendChild(br);
this.func2();
},
func2: function() {
var t = document.createTextNode("func2 called");
document.body.appendChild(t);
}
};
var proto = new MyProto();
document.getElementById("myButton2").addEventListener("click", function() {
proto.func1()
});
<button id="myButton1" onclick="proto.func1()">First Button</button>
<button id="myButton2">Second Button</button>

Answering the initial question: Fixing the typo works with your inline event
Answering SECOND question - how to use addEventListener and retain this:
Safe solution - wrap call in a function in the event handler:
function MyProto(){
this.valeur = "toto";
}
MyProto.prototype = {
func1: function() {
var t = document.createTextNode("func1 called ");
document.body.appendChild(t);
var br = document.createElement("br");
document.body.appendChild(br);
console.log(this)
this.func2();
},
func2: function() {
var t = document.createTextNode("func2 called");
document.body.appendChild(t);
}
};
var proto = new MyProto();
document.getElementById("myButton1")
.addEventListener("click",() => proto.func1() )
.as-console-wrapper {
height: 125px;
opacity: 0.3;
}
<button type="button" id="myButton1">addEventListener now works</button>
<hr/>
Trials to find how to retain the prototype this when using addEventlListener WITHOUT wrapping in a function.
NOTE button 2 shows the code I wrote which is now used by OP for followup question
function MyProto(){
this.valeur = "toto";
}
MyProto.prototype = {
func1: function() {
var t = document.createTextNode("func1 called ");
document.body.appendChild(t);
var br = document.createElement("br");
document.body.appendChild(br);
console.log(this)
this.func2();
},
func2: function() {
var t = document.createTextNode("func2 called");
document.body.appendChild(t);
}
};
var proto = new MyProto();
document.getElementById("myButton2").addEventListener("click",proto.func1)
document.getElementById("myButton3").addEventListener("click", proto.func1.bind(proto))
.as-console-wrapper {
height: 125px;
opacity: 0.3;
}
<button type="button" id="myButton1" onclick="proto.func1()">Here <i>this</i> is the prototype</button>
<button type="button" id="myButton2">addEventListener has unexpected <i>this</i></button>
<button type="button" id="myButton3">addEventListener bound <i>this</i></button>
<hr/>

Related

How does the this keyword work for an function expression and arrow function?

Lately I've been reading 'The Secrets of JavaScript Ninja' by John Resig and I've reached listing 4.10 i.e "Binding a Specific Context to a Function" in which the code is meant to print when the button is clicked.
The author shows the code will run successfully only if an arrow function is used instead of the normal function expression. Why doesn't the code work fine with the function expression? and how does this keyword works?
Here is the code with the function expression:
function Button() {
this.clicked = false;
this.click = function() {
this.clicked = true;
if (button.clicked) {
"The button has been clicked"
};
};
}
var button = new Button();
var elem = document.getElementById("test");
elem.addEventListener("click", button.click);
<button id="test">Click Me!</button>
and here's the code with the arrow function (which works flawlessly):
function Button() {
this.clicked = false;
this.click = () => {
this.clicked = true;
if (button.clicked) {
console.log("The button has been clicked");
}
};
}
var button = new Button();
var elem = document.getElementById("test");
elem.addEventListener("click", button.click);
<button id="test">Click Me!</button>
You can run the following code.
function Button1() {
this.clicked = false;
this.click = function() {
this.clicked = true;
console.log('bt1',this);
if (button1.clicked) {
console.log("The button has been clicked 1");
};
};
}
function Button2() {
this.clicked = false;
this.click = () => {
this.clicked = true;
console.log('bt2',this);
if (button2.clicked) {
console.log("The button has been clicked 2");
}
};
}
var button1 = new Button1();
var button2 = new Button2();
var elem = document.getElementById("test");
elem.addEventListener("click", button1.click);
elem.addEventListener("click", button2.click);
<button id="test">Click Me!</button>
'this' is only a HTML in normal function.
if yuo use 'button1.click.bind(button1)', will run successfully.

How to unbind document keypress event with anonymous function

This is page's code.
I can't modify this.
var Example = {};
Example.create = function() {
var obj = new Example.object();
return obj;
}
Example.object = function(){
this.initialize = initialize;
function initialize() {
window.addEventListener('load', activate);
}
function activate() {
document.addEventListener('keypress', keyPressed);
}
function keyPressed(e) {
alert("Hello!");
}
};
Example.defaultObject = Example.create();
Example.defaultObject.initialize();
I have tried many things...
document.onkeypress = null;
document.keypress = null;
document.removeEventListener('keypress');
$(document).unbind('keypress');
$(document).off("keypress");
$("*").unbind('keypress');
$(document).bind('keypress', function(e) { e.stopPropagation(); });
but all failed.
How can I unbind event of document keypress?
You have to pass the listener to remove it: (a variable pointing the function aka the function name)
document.removeEventListener('keypress', keyPressed);
https://developer.mozilla.org/de/docs/Web/API/EventTarget/removeEventListener
You will have to save it somewhere to remove it later
Root cause of the issue is removeEventListener method. This method expect second parameter which is listener method
document.removeEventListener('keypress', Example.defaultObject.keyPressed);
Here you go for Solution on your problem.
var Example = {};
Example.create = function() {
var obj = new Example.object();
return obj;
}
Example.object = function(){
this.initialize = initialize;
function initialize() {
window.addEventListener('load', activate);
document.getElementById('disable').addEventListener('click', deActivate);
}
function activate() {
document.addEventListener('keypress', keyPressed);
}
function deActivate() {
document.removeEventListener('keypress', keyPressed);
document.querySelector('h1').innerHTML = 'Page Key Press Listener Removed';
}
function keyPressed(e) {
alert("Hello!");
}
};
Example.defaultObject = Example.create();
Example.defaultObject.initialize();
<body>
<h1>Page has Key Press Listener</h1>
<input id="disable" type="button" value="deactivate">
</body>

Prototype function linked to button not working

I have a class (I think this is called) and created an object called peter in my code. I now want to level up Peter as follows:
// Define the class
function character(name, level){
this.name = name;
this.level = level;
}
// Create Peter at level 1
var peter = new character("Peter", 1);
// This will display the name of the character, level and a button to level him up
character.prototype.display = function() {
document.getElementById("name").innerHTML += this.name;
document.getElementById("level").innerHTML += this.level;
// This line calls `levelup()` on load which is not what I want
// and clicking the button no more calls `levelup`!
document.getElementById("levelupbutton").onclick = this.levelup();
// This line would call the function on click, but it looks like `this`
// is not being passed down to the function `levelup` so I get NaN on
// this.level down below?
//document.getElementById("levelupbutton").onclick = this.levelup;
};
character.prototype.levelup = function() {
alert("Level up in progress!");
this.level++;
alert(this.level);
}
peter.display();
jsfilldle
I'm probably incorrectly calling the function and I can't seem to figure out how to do it correctly. Can anyone give me some pointers? I'm new to OOP, so if the solution involves something OOP, could you please try to explain it as much as possible?
You need to bind this to levelup and not call it in line to get your desired behavior. Updated your fiddle with the correct answer.
levelupbutton.onclick = this.levelup.bind(this);
function character(name, level){
this.name = name;
this.level = level;
}
var peter = new character("Peter", 1); // Instantiate new objects with 'new'
character.prototype.display = function(){
document.getElementById("name").innerHTML += this.name;
document.getElementById("level").innerHTML += this.level;
document.getElementById("levelupbutton").onclick = this.levelup.bind(this);
};
character.prototype.levelup = function(){
alert("Level up in progress!");
this.level++;
alert(this.level);
}
peter.display();
<span>Character Name:</span> <span id="name"></span><br />
<span>Character Level:</span> <span id="level"></span><br />
<button id="levelupbutton">Level Up!</button>
When attaching a handler function to an element, the value of this inside of the handler is a reference to the element. It is the same as the value of the e.target property of the event argument that is passed to the handler.
Reference: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#The_value_of_this_within_the_handler
You could use Function.prototype.bind() method which will create a new function that will have its this set to the provided value.
Just attach the click handler like this:
document.getElementById("levelupbutton").addEventListener('click',
this.levelup.bind(this)
);
Why use addEventListener?
addEventListener is the way to register an event listener as
specified in W3C DOM..
Fiddle: http://jsfiddle.net/abhitalks/sjfxorxz/6/
Snippet:
function character(name, level) {
this.name = name;
this.level = level;
}
character.prototype.levelup = function() {
this.level++;
document.getElementById("level").innerHTML += this.level;
}
character.prototype.display = function() {
document.getElementById("name").innerHTML += this.name;
document.getElementById("level").innerHTML += this.level;
document.getElementById("levelupbutton").addEventListener('click',
this.levelup.bind(this)
);
}
var peter = new character("Peter", 1);
peter.display();
<span>Character Name:</span> <span id="name"></span><br />
<span>Character Level:</span> <span id="level"></span><br />
<button id="levelupbutton">Level Up!</button>
Alternatively, you could also save the reference and use that inside an anonymous function call instead of inlining it.
For example:
character.prototype.display = function() {
var self = this;
document.getElementById("levelupbutton").addEventListener('click',
function () {
self.levelup();
});
}
Fiddle 2: http://jsfiddle.net/abhitalks/sjfxorxz/9/
Snippet 2:
function character(name, level) {
this.name = name;
this.level = level;
}
character.prototype.levelup = function() {
this.level++;
document.getElementById("level").innerHTML += this.level;
}
character.prototype.display = function() {
var self = this;
document.getElementById("name").innerHTML += this.name;
document.getElementById("level").innerHTML += this.level;
document.getElementById("levelupbutton").addEventListener('click',
function () {
self.levelup();
});
}
var peter = new character("Peter", 1);
peter.display();
<span>Character Name:</span> <span id="name"></span><br />
<span>Character Level:</span> <span id="level"></span><br />
<button id="levelupbutton">Level Up!</button>

To access class attribute using Prototype JS

function Popup() {
}
Popup.prototype.openPopup = function() {
var div = document.getElementById("test");
div.style.display = 'block';
};
Popup.prototype.closePopup = function() {
var div = document.getElementById("test");
div.style.display = 'none';
};
window.onload = function() {
var popup = new Popup();
var opnpopup = document.getElementsByClassName('clck');
opnpopup.addEventListener('click', function() {
popup.openPopup();
});
var cnclpopup = document.getElementById('cancel');
cnclpopup.addEventListener('click', function() {
popup.closePopup();
});
}
HTML code :
<button id="clck" class="clck">click here</button>
<div id="test" class="popup">
This is a test message
<div id="cancel" class="cancel" ></div>
</div>
In above js when i access the class name 'clck' by using document.getElementsByClassName('clck') the popup is not displayed but when we access it through 'id' then it works..So whats the issue please explain
getElementsByClassName returns an array-like object. Check it out here: getElementsByClassName
"Returns an array-like object of all child elements which have all of
the given class names."
opnpopup is an array containing all elements with class clck. You can't bind events on arrays.
window.onload = function() {
var popup = new Popup();
var opnpopup = document.getElementsByClassName('clck');
for ( index = 0; index < opnpopup.length; index++ )
opnpopup[ index ].addEventListener('click', function() {
popup.openPopup();
});
var cnclpopup = document.getElementById('cancel');
cnclpopup.addEventListener('click', function() {
popup.closePopup();
});
}
This code should work, so you bind the click event to all elements in this array.

JavaScript Namespaces + Setter

Well, I'm using object orientation in JavaScript, but instead of using new, I just call the method from the namespace. In the moment, I have the following code:
var Component = {
Button: function(_text, use_image) {
button = $.createElement('button')
if (use_image != false)
{
button.innerHTML = _text;
}
else
{
button.innerHTML = _text
}
var text = _text
return button
}
}
When I want to return a button, I do:
x = Component.Button("Click me")
And after I can use x. But if I want to change the text of x, I must use x.textContent. I'd like to instantiate this and use a setter to apply its text, this way:
x = new Component.Button("Click me")
x.text = "Don't click me"
document.getElementsByTagName("body")[0].appendChild(x)
And if I try to apply the setter text, it becomes global, I want to have a unique for each button. Mix namespaces with get/set.
Thank you in advance
One way can be like, I am not sure if this is the best approach. Looking for more answers
var Component = {
Button: function(_text, use_image) {
var button = {
node : document.createElement('button'),
setText : function(txt){this.node.innerHTML = txt;}
};
if(_text){button.setText(_text);}
return button;
}
};
x = Component.Button("Click me");
x.setText("Don't click me");
document.getElementsByTagName("body")[0].appendChild(x.node);
y = Component.Button("Click me2");
y.setText("Don't click me2");
document.getElementsByTagName("body")[0].appendChild(y.node);
http://jsfiddle.net/2LCyn/
How about something like this:
var Component = (function($){
var buttonCount = 0;
function Button(text, use_image){
this.id = ++buttonCount;
this.text = text;
this.use_image = use_image;
this.$element = $('<button/>').text(text);
this.bindEvents();
}
Button.prototype.bindEvents = function(){
var that = this;
this.$element.on('click', function(){
console.log('hello, I\'m button ' + that.id);
});
};
Button.prototype.setText = function(text){
this.text = text;
this.$element.text(text);
};
return {
Button: Button
}
})(jQuery);
var button1 = new Component.Button('hello', false);
button1.setText('helloooo');
$('body').append(button1.$element);
var button2 = new Component.Button('world', true);
$('body').append(button2.$element);
http://jsfiddle.net/ATmAx/1/

Categories

Resources