This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 10 months ago.
I have the following code in my ngOnInit:
ngOnInit(): void {
let selectedArea:any = null;
let areas = document.querySelectorAll<SVGElement>('path'); // gets an array of all of the paths in the DOM
areas.forEach((area) => { // for each svg path
area.addEventListener('mouseover', function () {
area.style.fill = '#2100b6'; // add hover
});
area.addEventListener('mouseout', function () {
area.style.fill = ''; // return to default on mouse out
});
area.addEventListener('click', function () {
if (selectedArea) {
area.style.fill="black";
}
if (selectedArea !== area.id) {
selectedArea = area.id;
area.setAttribute('class', 'selectedArea'); // changed
area.style.fill="black";
}
console.log(selectedArea);
});
this.selectedRegion = selectedArea
});
}
selectedRegion : number = 0
"selectedArea" logs the selected region's code from an SVG map.
I tried to get that into the new variable "selectedRegion", but it did not work.
So, I want to use "selectedArea" outside of ngOninit, but I don't have any idea, how to do it.
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
I'm trying to filter an api response in React to certain news items, but when I call the setState function my console is throwing the error that it cannot setState of property undefined. I'm new to React so excuse me if this is an obvious fix.
class LeagueTables extends Component {
constructor(props) {
super();
this.state = {
sportsNewsFiltered: []
};
this.mountNews = this.mountNews.bind(this);
}
mountNews() {
var tempArr = [];
var urlNews =
"https://newsapi.org/v2/top-headlines?sources=bbc-
sport&apiKey=" + SECRETS.API_KEY;
var reqNews = new Request(urlNews);
fetch(reqNews)
.then(response => response.json())
.then(function(json) {
for (var i = 0; i < json.articles.length; i++) {
if (json.articles[i].url.includes("football")) {
tempArr.push(json.articles[i]);
}
}
})
.then(function() {
this.setState({
sportsNewsFiltered: tempArr
});
});
}
componentDidMount() {
this.mountNews();
}
You are loosing this context so Change it to arrow function
.then(() => {
this.setState({
sportsNewsFiltered: tempArr
});
});
So this in your set state is referring to the function its in not the react class as you want, to fix this simply have:
() =>{...}
Instead of:
function () {...}
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
I have the following javascript class similar to this:
class ModalFormButton {
constructor() {
this.contactForm = new ContactForm();
let utils = new Utils();
this.$signupModal = $(utils.getModalTmpl());
}
loadContactForm() {
this.$signupModal.modal();
this.contactForm.load();
}
contactBtnHandler(e) {
e.preventDefault();
let utils = new Utils();
var $t = $(this),
$modalTitle = $t.data('modal-title'),
$modalFormId = $t.data('modal-form-id');
$('body').append(this.$signupModal);
this.$signupModal.find('.modal-title').html($modalTitle);
this.$signupModal.find('.modal-body').load($t.attr('href') + ' #' + $modalFormId,this.loadContactForm);
};
registerHandlers() {
$('.modal-form-btn').click(this.contactBtnHandler);
};
load() {
this.registerHandlers();
};
}
My problem is that when contactBtnHandler is called I don't have access to class properties because the context belongs to modal-form-btn.
I know I can solve this using an arrow function, but I am wondering about if its possible to separate in a function the logic in the callback (here is a short example but I have longer functions) in a way similar to the one I am using.
Thanks
You can try binding "this" to your class in your callback handler
registerHandlers() {
$('.modal-form-btn').click(this.contactBtnHandler.bind(this) );
};
One could do:
getHandler (){
return e => {
//this is ModalFormButton
};
}
And then:
$('.modal-form-btn').click(this.getHandler());
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
I am using Javascript ES6 classes. I have created a Player class as below:
class Player {
constructor() {
.....
.....
}
changeShipDirection(shipName, direction) {
let redraw = false;
this.ships.filter(function(ship) {
if (ship.name === shipName) {
ship.direction = direction;
if (ship.location.length > 0) {
redraw = true;
let coordinates = this.getCoordinatesOfShip(ship.name);
}
}
});
return redraw
}
getCoordinatesOfShip(shipName) {
let coordinates = [];
this.ships.filter(function(ship) {
if (ship.name === shipName) {
coordinates = ship.location;
}
});
return coordinates;
}
}
I get the following error:
Cannot read property 'getCoordinatesOfShip' of undefined
I have cases where I use the same technique i.e. calling a method within the class and it works.
That's because this inside that function you passed to filter is not bound to the class. There are multiple ways to fix it.
One is to use arrow function which retains the this binding of the scope it's defined in
this.ships.filter((ship) => {
if (ship.name === shipName) {
ship.direction = direction;
if (ship.location.length > 0) {
redraw = true;
let coordinates = this.getCoordinatesOfShip(ship.name);
}
}
});
Another can be to first retain the this reference for the outer function in some other variable and then use that inside the function passed to filter -
var self = this
this.ships.filter(function(ship) {
if (ship.name === shipName) {
ship.direction = direction;
if (ship.location.length > 0) {
redraw = true;
let coordinates = self.getCoordinatesOfShip(ship.name);
}
}
});
Yet another way is to bind that function to the this bound to the outer function -
this.ships.filter(function(ship) {
if (ship.name === shipName) {
ship.direction = direction;
if (ship.location.length > 0) {
redraw = true;
let coordinates = this.getCoordinatesOfShip(ship.name);
}
}
}.bind(this));
This question already has answers here:
JavaScript - Owner of "this"
(6 answers)
Closed 8 years ago.
I have this function right here which takes the parts of my object and illuminates them successively with a delay (it switches the opacity of an element to 1 and then switches the previous element opacity to 0 to illuminate them successively).
The problem is that I cannot use the this keyword to access the parent objects parts in the illuminateInternal function.
This hinders any possible reuse of my object since I will have maleBackNoZoom and maleBackFullZoom objects.
I don't want to change the variable names of the illuminateInternal function when I re-use my object so I would like to use something like the this keyword in the illuminateInternal function as well.
maleBackNoZoom = {
parts:{
armsRight: findItemById("29") ,
armsLeft: findItemById("28"),
legsRight: findItemById("21"),
legsLeft: findItemById("22"),
back: findItemById("24"),
buttocks: findItemById("23"),
neck: findItemById("26"),
head: findItemById("27")
},
illuminate: function() {
var propertiesToIlluminate = [], prop, illuminateInternal, i = 0, delay = 200, intervalId;
for (prop in this.parts) {
propertiesToIlluminate.push(prop);
}
illuminateInternal = function () {
var property = propertiesToIlluminate[i];
var previousProperty = propertiesToIlluminate[i-1];
maleBackNoZoom.parts[property].opacity = 1;
console.log(previousProperty);
if (typeof previousProperty !== 'undefined'){
maleBackNoZoom.parts[previousProperty].opacity = 0;
}
paper.view.update();
i++;
if (i === propertiesToIlluminate.length) {
maleBackNoZoom.parts[property].opacity = 0;
clearInterval(intervalId);
setInterval(function(){paper.view.update()},delay);
}
};
intervalId = setInterval(illuminateInternal, delay);
}
}
You can define local variable inside illuminate method which will store reference to its object. And then you can use it as alias of this.
var self = this;
illuminateInternal = function () {
..
self.parts[property].opacity = 1;
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript Closure Problem
In the following code, TrueThis.aChoices[i]['CallBack'] is a function when the click event is created and "false" when the click event actually occurs. How do I get the function reference into the click event handler?
My Object:
ATK.MultiChoiceDialog = function() {
var TrueThis = this;
var aChoices;
this.Show = function(sTitle,sPrompt,aChoices){
this.aChoices = aChoices;
var HTML = '[snip]';
$('body').append(HTML);
for(var i in this.aChoices)
{
console.log(TrueThis.aChoices[i]['CallBack']); // shows "function"
$('#ATKDialogButton'+i).click(function(e){
console.log(TrueThis.aChoices[i]['CallBack']); // shows "false" ???
if(TrueThis.aChoices[i]['CallBack'])
{
TrueThis.aChoices[i]['CallBack'].call(aChoices[i]['Context']);
}
});
}
}
};
I've also tried this:
for(var i in this.aChoices)
{
var CB = TrueThis.aChoices[i]['CallBack'];
console.log(CB); // function
$('#ATKDialogButton'+i).click(function(e){
console.log(CB); // false
if(TrueThis.aChoices[i]['CallBack'])
{
TrueThis.aChoices[i]['CallBack'].call(aChoices[i]['Context']);
}
});
}
jQuery has a built-in way of handling this by passing event data to the callback function being bound to the event.
ATK.MultiChoiceDialog = function() {
var TrueThis = this;
var aChoices;
this.Show = function(sTitle,sPrompt,aChoices){
this.aChoices = aChoices;
var HTML = '[snip]';
$('body').append(HTML);
for(var i in this.aChoices){ // in js the '{' should be on same line
console.log(TrueThis.aChoices[i]['CallBack']); // shows "function"
$('#ATKDialogButton'+i).click({i:i},function(e){ // data passed in with {i:i}
console.log(TrueThis.aChoices[e.data.i]['CallBack']); // shows "function"
if(TrueThis.aChoices[e.data.i]['CallBack']){ // in js the '{' should be on same line
TrueThis.aChoices[e.data.i]['CallBack'].call(aChoices[e.data.i]['Context']);
}
});
}
}
};
Thanks to the comments, I've got this working. First create a new function to "fix" the value of i, which returns the function for the event handler.
this.FixI = function (i){
return function(e){
if(TrueThis.aChoices[i]['CallBack'])
{
TrueThis.aChoices[i]['CallBack'].call(TrueThis.aChoices[i]['Context']);
}
}
}
Use the new function to generate the even handlers function in the loop:
for(var i in this.aChoices)
{
$('#ATKDialogButton'+i).click(TrueThis.FixI(i));
}
UPDATE: It looks like Kevin B found a Jquery way of addressing the problem that doesn't require an extra "preserver" function.