class Elemento
{
constructor (numerito)
{
this.numero = document.getElementById(numerito).innerText
this.boton = document.getElementById(numerito)
}
escribir()
{
console.log(this.numero)
}
}
numeroUno = new Elemento("1")
numeroUno.boton.addEventListener("click", numeroUno.escribir)
I'm trying to show in console numerito value when button is clicked but instead it shows "undefined".
I strongly suspect this is a this binding issue - when the event handler numeroUno.escribir is called by the browser after the user clicks the button, it has "lost the context" of the numeroUno object.
One solution this is to use the bind method to fix the this reference of the method, no matter how it is called:
class Elemento
{
constructor (numerito)
{
this.numero = document.getElementById(numerito).innerText
this.boton = document.getElementById(numerito)
this.escribir = this.escribir.bind(this) // add this line
}
escribir()
{
console.log(this.numero)
}
}
You are not utilising the value that you pass to the constructor, try this:
class Elemento
{
constructor (numerito)
{
this.numero = numerito // See here, use the numerito passed to the constructor function
this.boton = document.getElementById(numerito)
}
escribir()
{
console.log(this.numero)
}
}
numeroUno = new Elemento("1")
numeroUno.boton.addEventListener("click", numeroUno.escribir)
The problem can be fixed by explicitly binding the function in the class to this.
Binding syntax is:
function_name = this.function_name.bind(this)
Here is the working solution:
<html>
<head>
<title>demo</title>
</head>
<body>
<div>
<button id="1">Numerito</button>
</div>
<script>
class Elemento {
constructor (numerito) {
this.numero = document.getElementById(numerito).innerText
this.boton = document.getElementById(numerito)
}
escribir() {
console.log("numero = " + this.numero)
}
// JavaScript expects an explicit binding of each function in the class
//
// Binding syntax is:
//
// function_name = this.function_name.bind(this)
escribir = this.escribir.bind(this)
}
numeroUno = new Elemento("1")
numeroUno.boton.addEventListener("click", numeroUno.escribir)
</script>
</body>
</html>
Related
I'm confused about how the states of members of classes in Javascript work.
I'm trying to create a dialog class which has the ability to hide the dialog when a user clicks the cancel button. I've simplified the implementation to show the problem I'm facing.
class FooClass {
bar
createBar() {
this.bar = document.createElement("ons-dialog");
this.bar.innerHTML = "this is bar content";
document.querySelector("#home").appendChild(this.bar);
this.bar.addEventListener(
'click',
this.hideBar);
this.bar.show();
}
hideBar() {
if(this.bar) {
console.log("bar exists: " + this.bar);
this.bar.hide();
} else {
console.log("bar is null!")
}
}
}
foo = new FooClass();
foo.createBar();
When I click the dialog that comes up when the page completes loading, nothing happens and the output in the console is always:
bar is null!
Why does the class lose this.bar after the page completes loading? Furthermore, how can I assign an event listener to some button which closes the dialog within this class?
Here is a codepen.io link with implementation:
https://codepen.io/moonlightcheese/pen/NWpxxMj?editors=1111
In Javascript classes, methods are not automatically bound to the instance. E.g. when using a method from a class as an event handler, like you are doing, this will point to the element you attach the listener to.
To fix that, you have two options:
In the constructor of your class, bind the method to the instance:
constructor() {
this.hideBar = this.hideBar.bind(this);
}
class FooClass {
bar;
constructor() {
this.hideBar = this.hideBar.bind(this);
}
createBar() {
this.bar = document.createElement("ons-dialog");
this.bar.innerHTML = "this is bar content";
document.querySelector("#home").appendChild(this.bar);
this.bar.addEventListener(
'click',
this.hideBar);
this.bar.hidden = false;
}
hideBar() {
if (this.bar) {
console.log("bar exists: " + this.bar.outerHTML);
this.bar.hidden = true;
} else {
console.log("bar is null!")
}
}
}
foo = new FooClass();
foo.createBar();
<div id="home"></div>
Use a class property and assign an arrow function:
hideBar = () => { /* your function code */ }
class FooClass {
bar;
createBar() {
this.bar = document.createElement("ons-dialog");
this.bar.innerHTML = "this is bar content";
document.querySelector("#home").appendChild(this.bar);
this.bar.addEventListener(
'click',
this.hideBar);
this.bar.hidden = false;
}
hideBar = () => {
if (this.bar) {
console.log("bar exists: " + this.bar.outerHTML);
this.bar.hidden = true;
} else {
console.log("bar is null!")
}
}
}
foo = new FooClass();
foo.createBar();
<div id="home"></div>
Please note that due to the missing custom element definition, the custom element ons-dialog does not have a show and hide method (it's simply an HTMLUnknownElement here in the snippet), which is why I replaced that functionality in the snippets using the standard DOM hidden API.
I got a function that creates a button template for Kendo Grid Toolbar based on the parameter received. What I want to do is passing one of the properties inside the parameter called element(it is a jquery element) through onclick function so that I can access that element in the function fnAdd(element).
function(parameter)
{
var template="<button onclick='fnAdd("+param.element+")'>Add</button>";
$('#grid').kendoGrid({
toolbar: template
});
}
Currently, the onclick function is not working. I try to use JSON.stringify on the param and pass it through the onclick and able to get it on fnAdd(), but I can't access the param.element at all.
Anyone know how to solve this?
You can use the bind method to attach your params to achieve this. Sample code below
function add(param) {
let btn = document.createElement('button');
btn.innerHTML = 'NEW - ' + new Date().getTime();
btn.onclick = newButtonOnclick.bind(this, (param || new Date().getTime()))
document.body.append(btn)
}
function newButtonOnclick(param) {
alert(param);
}
button {
display: block;
margin-bottom: 1em;
}
<button type="button" onclick="add();">
Add New Button
</button>
I hope this solution can help you:
Remember the Patter designs, in this case we can use a Factory patter with this you can reuse this code to create chunks of code.
With this example also each button could trigger a different function and can have different params!
// YOUR JAVASCRIPT WITH ACCESS TO THE DOM
// here you call your plugin where the DOM is not present
function getButton() {
let newButtonInString = createButtonPlugin();
// in newButton you just have the string
// now convert it to html using Jquery
let htmlButton = $(newButtonInString);
document.body.append(htmlButton[0]);
}
// YOUR PLUGIN JS
let counter = 1;
function createButtonPlugin() {
// you can take this params from the UI
let paramsExample = {
text: `New Button ${counter}`,
functionParams: {
counter: counter
} // Could be an object or what you want!
}
let bp = new ButtonPrototype(paramsExample);
let newButton = bp.createButton();
counter++;
// return string to the place where you can render the button
return newButton;
}
class ButtonPrototype {
constructor(params){
this.params = params
}
createButton() {
return `<button onclick=fn(${JSON.stringify(this.params.functionParams)})>${this.params.text}</button>`
}
}
function fn (args) {
alert(`Success ${args.counter}`)
}
Your html:
<button onclick="getButton()">add</button>
I also leave the codepen: Just Updated with the new comment you made!
https://codepen.io/ruben-saucedo/pen/GbxXNG
The input named alternativa-*** will have the *** changed in the PHP that comes before. I'm not using a form on PHP only a onClick statement calling the respondeQuestao function. But this code seems to not work. Someone have any suggestion.
$(document).ready(function() {
function respondeQuestao(qid,resposta) {
var alternativa = document.getElementsByName('input[name = "aternativa-"' + qid ']:checked').value;
document.getElementById("demo").innerHTML = 5 + 6;
if(alternativa==resposta) {
$("#botao-questao"+qid).hide();
};
if(alternativa!=resposta) {
};
};
})
Defining a function within the jQuery Ready statement limits the accessibility - define it outside of the jQuery Ready statement but call it when you need it.
function respondeQuestao(qid, resposta) {
var alternativa = $("INPUT[name^='alternativa-']:checked").val();
$("#demo").html(5+6);
if (alternativa == resposta) {
$("#botao-questro" + qid).hide()
} else {
//
}
}
Call the function inside jQuery:
$(function() {
respondeQuestao("id", 11);
});
I hope this helps.
I am creating a simple function to close a flash message div on click event, but my listener is not firing.
I wrote 3 different functions to try to get it working, but nothing is happening and Chrome console isnt telling me anything.
My first was in ES6 class style, this one:
class closeFlashMessages {
constructor () {
this.getFlashMessages = document.querySelector("#flash-messages");
this.addEventListeners();
}
close () {
console.log(this.getFlashMessages);
this.getFlashMessages.className = "hide";
}
addEventListeners () {
if(this.getFlashMessages)
this.getFlashMessages.addEventListener("click", this.close);
}
}
new closeFlashMessages();
My second was this:
(function (){
let getFlashMessages = document.querySelector("#flash-messages");
function close () {
console.log(getFlashMessages);
getFlashMessages.className = "hide";
}
function addEventListeners () {
getFlashMessages.addEventListener("click", function () {
close()
});
}
addEventListeners();
});
My last one is this:
(function (){
let getFlashMessages = document.getElementById("flash-messages");
getFlashMessages.addEventListener("click", close(getFlashMessages));
function close (id) {
console.log(getFlashMessages);
getFlashMessages.className = "hide";
}
});
My HTML:
<div id="flash-messages">
<div class="flash success">
<p>Recept byl přidán do nákupního seznamu.</p>
</div>
</div>
But none of them worked!! I dont understand
With the first two, I was getting undefined on my this.getFlashMessages also not sure why.
My solution is not in ES6
function Init(){
var id = document.getElementById('flash-messages');
var msg = document.querySelector('.flash');
id.addEventListener('click',function(){
msg.className = 'hide';
});
}
Init();
see demo here
I am not very much familiar with ES6.
But if I try similar code sample on a javascript it will be as given below and I hope it will be almost similar in ES6 aswell.
var getFlashMessages = document.getElementById("flash-messages");
getFlashMessages.addEventListener("click", function()
{
clicked(getFlashMessages);
});
function clicked(id){
console.log(id);
id.className = "hide";
}
Here, I am calling anonymous function, and its default argument will be event object as given in https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener.
I've a problem with this simple prototyping:
Game = function (moduleConfig, gameConfig) {
this.moduleConfig = moduleConfig;
this.gameConfig = gameConfig;
// Game-Commands
this.keyCommands = {
moveLeft: false,
moveRight: false
};
this.catcher = null;
this.stage = null;
return this;
}
/**
* Left arrow down
*/
Game.prototype.onKeyboardLeftDown = function () {
this.keyCommands.moveLeft = true;
}
/**
* Left arrow up
*/
Game.prototype.onKeyboardLeftUp = function () {
this.keyCommands.moveLeft = false;
}
I always get the error message: Uncaught TypeError: Cannot set property 'moveRight' of undefined when calling onKeyboardLeftDown and onKeyboardLeftUp. But i have declared moveLeft in the constructor in the keyCommands object.
The two methods were called on key down and key up events:
Game.prototype.init = function () {
// ...
// =========================================================================
// Set keyboard
KeyboardJS.on('left', this.onKeyboardLeftDown, this.onKeyboardLeftUp);
KeyboardJS.on('right', this.onKeyboardRightDown, this.onKeyboardRightUp);
// =========================================================================
};
My index.html looks like this:
<!DOCTYPE html>
<html>
<head>
<title>pixi.js example 1</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #000000;
}
</style>
<script src="js/pixi.dev.js"></script>
<script src="js/keyboard.js"></script>
<script src="js/moduleConfig.js"></script>
<script src="js/moduleResult.js"></script>
<script src="js/game.js"></script>
</head>
<body style="background-color: #EEEEEE">
<script>
var game = new Game(moduleConfig, {
screenWidth: (window.innerWidth - 10),
screenHeight: (window.innerHeight - 10),
bgColor: 0xEEEEEE
});
game.init();
</script>
</body>
</html>
Does some one see the failure? I have searched a lot, but i'm very confused (normally i develop only in c#...)
You're binding is wrong.
// Set keyboard
KeyboardJS.on('left', this.onKeyboardLeftDown, this.onKeyboardLeftUp);
this.onKeyboardLeftDown and this.onKeyboardLeftUp are called without the correct context
to fix this do something like:
KeyboardJS.on('left', this.onKeyboardLeftDown.bind(Game), this.onKeyboardLeftUp.bind(Game));
I would not recommend using bind() - for browser compatibility, but you can use something like lodash's bind or an bind "emulator" like:
function bind(fn, ctx) {
return function bound() {
return fn.apply(ctx, arguments);
};
}
Another way would be
var self = this;
KeyboardJS.on('left',
function(){self.onKeyboardLeftDown()},
function(){self.onKeyboardLeftUp()}
);
Your question is not complete, I do not see the relevant code where you try to define moveRight.
Possible problems:
you might have a typo, that keyCommands is spelled exactly
you might refer to keyCommands outside its scope
you might refer to keyCommands.moveRight before keyCommands is initialized
you might assign another value to keyCommands before referring to moveRight