Why is this code indicating that my object's properties are undefined?
document.getElementById("mkObj").addEventListener('click', () => {
var globalDragon = mkObj(document.getElementById("cn").value, parseInt(document.getElementById("ch").value), document.getElementById("cl").value);
document.getElementById("hit").addEventListener('click', (globalDragon) => {
hit(globalDragon, 25);
printObjDetails(globalDragon);
});
document.getElementById("details").addEventListener('click', (globalDragon) => {
let dragon_here = globalDragon;
printObjDetails(dragon_here);
});
});
Why can't I just make the Dragon object by clicking the mkObj button and then click the hit button or details button and have it show the object's state? Why is it showing that globalDragon.name is undefined?
I had the code looking like this before and it did not work either so I just make everything be within the mkObj click scope, thinking that that would solve the issue but it didn't:
document.getElementById("mkObj").addEventListener('click', ()=>{
var globalDragon = mkObj( document.getElementById("cn").value, parseInt( document.getElementById("ch").value), document.getElementById("cl").value );
});
document.getElementById("hit").addEventListener('click', (globalDragon)=>{
hit(globalDragon, 25);
printObjDetails(globalDragon);
});
document.getElementById("details").addEventListener('click', (globalDragon)=>{
let dragon_here = globalDragon;
printObjDetails(dragon_here);
});
I believe what you actually want is
// declare the variable in the top scope,
// so that all three click handlers can access it
var globalDragon;
document.getElementById("mkObj").addEventListener('click', () => {
// write a new object into the global variable
globalDragon = mkObj(
document.getElementById("cn").value,
parseInt( document.getElementById("ch").value),
document.getElementById("cl").value
);
});
document.getElementById("details").addEventListener('click', () => {
// read from the global variable
printObjDetails(globalDragon);
});
document.getElementById("hit").addEventListener('click', () => {
// modify the object
hit(globalDragon, 25);
printObjDetails(globalDragon);
});
Notice how I removed the parameters of the functions that were also named globalDragon. The event handlers get passed an event object as their arguments.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I am building an app with Javascript and OpenLayers and while it's going fairly well, I am stuck at what I feel could be an easy problem for someone experienced.
Here is part the code where the problem lives :
const baseLayerElementsRight = document.querySelectorAll(
'[name="baseLayerRadioButtonRight"]'
);
let layerRender = {};
for (let baseLayerElementRight of baseLayerElementsRight) {
baseLayerElementRight.addEventListener(
'change',
function() {
let baseLayerElementValueRight = this.value;
layerGroupRight.getLayers().forEach(function(element) {
let baseLayerNameRight = element.get('title');
element.setVisible(
baseLayerNameRight === baseLayerElementValueRight
);
let elementVisibility = element.get('visible');
if (elementVisibility) {
layerRender = element;
console.log(layerRender);
}
});
},
false
);
}console.log(layerRender)
So Basically, I need to apply a method on the "layerRender" object variable outside of the event callback and I am quite new to programming and I struggle to find a solution to access the variable value
The console.log in the callback's event output the Object I want everytime I click on a given radio type input, but the console.log outisde it outputs an empty Object and of course don't update everytime I the event is happening.
How could I do to access the layerRender value outside of the callback?
Thanks a lot
your last console.log only happens once as the code runs through... you first declare the variable. Then you add an eventListener in a for loop then finally do console.log code executes. and it executes NOT when you're clicking
const baseLayerElementsRight = document.querySelectorAll(
'[name="baseLayerRadioButtonRight"]'
);
let layerRender;
for (let baseLayerElementRight of baseLayerElementsRight) {
baseLayerElementRight.addEventListener(
'change',
function() {
console.log('Click happened');
layerGroupRight.getLayers().forEach(function(element) {
let baseLayerNameRight = element.get('title');
element.setVisible(
baseLayerNameRight === this.value
);
let elementVisibility = element.get('visible');
if (elementVisibility) {
layerRender = element; // assign element to layerRender
// console.log if element is visible only
console.log(layerRender);
}
});
},
false
);
}
console.log(layerRender); // Happens when function initialise NOT when click happens
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
I'm trying to call an object method from another method within the same constructor, and it doesn't seem to be working - I just get the error TypeError: undefined is not a function (evaluating 'this.uiDisplayOptions()').
I'm instantiating the object using using the new keyword var ui = new _ui().
Anyone know why it's not working? I've seen examples of this kind of setup being suggested.
Here's the code:
function _ui() {
this.uiDisplayOptions = function() {
var len = channels[currentChannel].stepsChannel;
$("select#length option")
.prop('selected', false)
.filter('[value="' + len + '"]')
.prop('selected', true);
var rand = channels[currentChannel].randomAmtChannel;
$("select#randomness option")
.prop('selected', false)
.filter('[value="' + rand + '"]')
.prop('selected', true);
var dir = channels[currentChannel].readDirection;
$("select#readdirection option")
.prop('selected', false)
.filter('[value="' + dir + '"]')
.prop('selected', true);
}
this.uiSetListeners = function() {
// Select Channel
$("#selectChannel0").addClass("green");
$(".channelselect").click(function() {
$(".channelselect").removeClass("green");
$(this).addClass("green");
currentChannel = $(this).data("channel");
displayUpdateChannel();
this.uiDisplayOptions();
});
// Select Row
$("#selectRow0").addClass("red");
$("#selectRow0").click(function() {
currentRow = 0;
$("#selectRow1").removeClass("red");
$(this).addClass("red");
});
$("#selectRow1").click(function() {
currentRow = 1;
$("#selectRow0").removeClass("red");
$(this).addClass("red");
});
// Increment/Decrement Selected Row Pattern
$("#patternInc").click(function() {
selectPatternRow(1);
displayPattern();
});
$("#patternDec").click(function() {
selectPatternRow(-1);
displayPattern();
});
// Shift Left/Right Selected Row Pattern
$("#shiftLeft").click(function() {
selectShiftRow(-1);
displayPattern();
});
$("#shiftRight").click(function() {
selectShiftRow(1);
displayPattern();
});
// Handle Row 'Pattern Locks'
$(".lock").click(function() {
var step = $(this).data("lockstep");
switch(toggleLockBit(step)) {
case 0:
$(this).removeClass("red green");
break;
case 1:
$(this).addClass("red");
break;
case 2:
$(this).removeClass("red").addClass("green");
break;
}
displayPattern();
});
// Handle Channel Length change
$("#length").change(function() {
selectCurrentChannelLength($(this).val());
displayChannelLength();
});
// Handle Channel Randomness change
$("#randomness").change(function() {
selectCurrentChannelRandomAmt($(this).val());
displayRandomAmt();
});
}
}
this.uiSetListeners = function() {
// Select Channel
$("#selectChannel0").addClass("green");
$(".channelselect").click(function() {
$(".channelselect").removeClass("green");
// this here does not refer to the this of the object being created.
// it refers to the anonymous function being created in the click call.
// jQuery is probably invoking this and binding this to undefined,
// but even if it wasn't then this code would behave incorrectly.
$(this).addClass("green");
currentChannel = $(this).data("channel");
displayUpdateChannel();
this.uiDisplayOptions();
});
});
When inside a function the this's value may change. It has it's own binding called a ThisContext and cannot be guaranteed to be pointing at the object you are calling this from within (especially with the introduction of bind, apply and call). Inside uiSetListeners, this is generally bound to the function (which in turn is bound to the object, assuming you are invoking the constructor correctly, and not using any bind magic).
However inside your click, handler, you are delegating the function to jQuery. jQuery doesn't know about your object so it doesn't bind this (or binds it to undefined), and it isn't associated with an object by default (as the function is being declared anonymously and not bound to an object). In other words, your click handler is pointing to a different this than your this.uiSetListeners statement is.
The way to fix this is by using a var that = this; kind of mechanism. If you take this approach, you should probably define var that = this at the top of your constructor function (so others can see what's going on) and replace any incidence of this inside of the constructor function with that.
This ensures that should another user call your constructor with call, bind et al, the object will be bound correctly to the supplied this.
var that = this;
that.uiSetListeners = function() {
// Select Channel
$("#selectChannel0").addClass("green");
$(".channelselect").click(function() {
$(".channelselect").removeClass("green");
$(this).addClass("green");
currentChannel = $(that).data("channel");
displayUpdateChannel();
that.uiDisplayOptions();
});
});
Note that ES6 fixes this with the fat arrow notation.
this.uiSetListeners = function() {
// Select Channel
$("#selectChannel0").addClass("green");
$(".channelselect").click(() => {
$(".channelselect").removeClass("green");
$(this).addClass("green");
currentChannel = $(this).data("channel");
displayUpdateChannel();
this.uiDisplayOptions();
});
});
You should be perfectly able to invoke other methods from within the constructor as long as you remember to take care with your this.
It is generally preferable to use YourConstructor.prototype.methodName instead, as this will first of all reduce nesting but also uses the prototype chain. Assigning functions to this in the constructor does not assign them to the prototype chain, which also means they will be recreated each time a new object is created. You only really need to assign functions to this inside of a Constructor if their implementation is dependent on the values passed into the constructor and it is not appropriate to capture those values in the constructor as state on the created object.
you can't call a function like this inside a constructor, this will refer to global object window until you call your constructor function using new keyword.
var ui = new _ui();
refer the current object context on the top of you constructor function.
function _ui() {
var _that = this;
}
and refer all current constructor function using _that reference.
I hope it will solve your problem.
I have this small code:
ScenesController.prototype.viewAction = function() {
this.flash = this.di.HelperFlash.hasSupport();
this.$playerElem = !this.flash? $('#html_player') : $('#flash_player');
// the first click is just a sample, I need the same object in the Quailty Change method
$('.scenes_view_video_quailty').on('click', function() { echo($(this));});
$('.scenes_view_video_quailty').on('click', this.viewVideoQuailtyChange.bind(this));
};
ScenesController.prototype.viewVideoQuailtyChange = function(e) {
e.preventDefault();
if (!this.flash) {
echo(this);
echo($(this));
}
};
When I'm clicking the link, I would need pass 2 this variable to the QualityChange method. One with the object (in the bind) and the other is the click event, because I need the clicked element too.
I was trying with the .on('click', {$this: $(this)}, this.method) solution, but dosen't work, the evend.data.$this looks a different object.
I need the same object as I have in the first click method.
(echo = console.log)
Alias the this that refers to the current instance as something else (traditionally, self) and use this to refer to the clicked element
ScenesController.prototype.viewAction = function() {
var self = this;
this.flash = this.di.HelperFlash.hasSupport();
this.$playerElem = !this.flash? $('#html_player') : $('#flash_player');
$('.scenes_view_video_quailty').on('click', function() { echo(self, $(this));});
};
To call a method setting it's this reference you would use Function.apply, for example:
$('.scenes_view_video_quailty').on('click', function(){
self.viewVideoQuailtyChange.apply(self, [$(this)])
});
You can attach any number of variables with bind
You could have a proper method like:
ScenesController.prototype.viewVideoQuailtyChange = function(secondThis) {
}
then use the bind as:
this.viewVideoQuailtyChange.bind(this, $(this));
With this solution you do lose the event though, so it might need some more thought. I'll look into it and update the answer :)
Can I get value from jquery event function?
I want to get something like this:
function Init() {
var my_variable = $some_object.click(function() {
var my_variable = 'value';
return my_variable // I need to get the variable value from click event
// but I don't know ways to do it
});
console.log(my_variable); // I want to have possibility to use the value here
}
No.
The function that sets the event handler will have finished running before the event handler runs.
No, you can't do that. You can only capture the value in a variable defined outside the scope of your handler:
function Init() {
var my_variable = '';
$some_object.click(function() {
my_variable = 'value';
});
console.log(my_variable); //Prints empty string
$some_object.trigger('click');
console.log(my_variable); //Prints 'value'
}
The answer to your question is No!. You cannot return a value from event handler.
Now next thing which made you curious is how to get some data which comes from the event handler itself. This is where event propagation comes and passing some data along with that.
Checkout below fiddle which shows how data which was created in event handler of button click, is being passed for any custom purpose.
http://jsfiddle.net/kowmwq9j/
Below is simple html and understandable javascript code
<div id='parent'>
<button id='test'>CLick</button>
</div>
var a=document.getElementById('test');
a.addEventListener('click', function(){
var str='sample';
//creating a custom event with name 'build' and passing object as data
var event = new CustomEvent('build', { 'detail': str });
//dispatches the event which invokes the affected listeners
this.dispatchEvent(event);
})
//Listening for 'build' event
document.getElementById('parent').addEventListener('build', getData, true);
function getData(e){
alert(e.detail);
}
Links shared which can help one to understand the concept. dispatchEvent & createCustomEvent .Hope that helps to answer your question!
Added some comments & links which will help those who aren't aware of the functions & behavior used.
If I understand the question maybe you can do something like this...
Variable = 5 is used within 2 functions...each function does something with it's value...
the last function uses the totals of the first 2 functions and again does something.. So the point is that u can access the 2 totals variables and use them in the third function... As long as you set your function variable as global...so don't put VAR in front of it. If you set var in front of it u are saying that your variable is private for that function...
Change the value of the original variable and all the values changes ....
variable = 5; // this is a global variable
source = $('div#een h2'); // put your source here
function Init(){
source.on('click', function(){
Total1 = variable * 2;
console.log(Total1); // It outputs 10
});
};
Init();
function Init2(){
source.on('click', function() {
Total2 = variable * 5;
console.log(Total2); // It outputs 25
});
};
Init2();
function Init3(){
source.on('click', function() {
Total3 = Total1 * Total2; // here we use the 2 Totals...
console.log(Total3); // outputs the Total of both totals... should be 250
});
};
Init3();
How can I pass parameters to a function declared like something = function(){};
window.prototype.initInterface = function(){
this.mainPane = document.createElement('div');
this.mainPane.style.border="5px solid grey";
this.mainPane.style.margin="0px";
this.mainPane.style.width="420px";
this.mainPane.style.height="600px";
this.exitButton = document.createElement('input');
this.exitButton.setAttribute("type", "button");
this.exitButton.setAttribute("value", "exit");
this.exitButton.onclick = function(){
document.body.removeChild(this.mainPane);
};
this.mainPane.appendChild(this.exitButton);
document.body.appendChild(this.mainPane);
}
When the user presses the exit button I want to remove the mainPane from the body of the html page.
this.exitButton.onclick = function(this.mainPage){
document.body.removeChild(this.mainPane);
};
Does not work
How can I do this?
For your exitButton.onclick function to have access to variables you create in the enveloping initInterface function you want a to create a closure in the exitButton.onclick function by returning a function that performs the action you want and passing that the variable.
exitButton.onclick = function () {
return (function() {
document.body.removeChild(mainPane);
})(mainPane);
};
Read more on how closures work here and here and see a working example fiddle.
Alternatively, you forget about closures and walk up the DOM from the button which triggers the event to your mainPane
exitButton.onclick = function() {
// in here "this" is the object that triggered the event, exitButton
document.body.removeChild(this.parentNode);
}
As an aside, window.prototype does not exist if you are doing this in a browser; window is the object at the top of prototype chain in browser scripting. You want just window.initInterface = function () {} which is the exact same thing as function initInterface() {} because everything you do in javascript in the browser becomes a property of window.
This function is the function w/o function name. It could only be used once and you may not easy to find out what parameters should be passed.
You can create another function like :
function go(a1){}
And call it like window.prototype.initInterface = go(a1);
Or you can get some DOM parameters in this unnamed function by using functions like getDocumentById("DOM ID") etc.