Okay, so in my program, I'm having to supply a callback as an event listener as part of the init()
method of my class, and I'd like this callback to be another method from the same class (onPageShown(ev)
from code below).
const pageShownEvent = new Event("pageShown");
class App
{
private pages: NodeListOf<HTMLDivElement>;
public onPageShown(ev: Event) {
console.log("Method called as callback");
}
public init() {
this.pages = <NodeListOf<HTMLDivElement>> document.querySelectorAll(".page");
console.log(this.pages);
for(let i = 0; i < this.pages.length; ++i)
{
this.pages[i].addEventListener("pageShown", this.onPageShown);
}
/*this.pages.forEach((pg: HTMLDivElement) => {
pg.addEventListener("pageShown", this.onPageShown);
});*/
}
// singleton instance
private static instance: App;
private constructor() {
this.pages = null
}
// ensure only 1 instance is created
public static getInstance() {
if(!App.instance) {
App.instance = new App()
}
return App.instance;
}
}
const myApp = App.getInstance();
However, the problem is that whenever I use the this
pointer to access onPageShow
like so, it doesn't seem to be added or interpreted as a callback function. No errors are thrown and auto-completion still works as expected, hinting that this
is still pointing at the right object.
this.pages[i].addEventListener("pageShown", this.onPageShown);
The only way I get it to work is by explicitly supplying onPageShown
through the class instance given by getInstance()
(its a singleton class), in which case it works perfectly and I see the correct output in the console.
this.pages[i].addEventListener("pageShown", App.getInstance().onPageShown);
At first I thought this
was pointing to the wrong object as I was using the callback implemented forEach()
, but even after I switcher to using a regular for-loop, the problem persisted.
It may seem that my current solution works just as well, but it requires me to set the methods I want to use as callbacks to public, when I'd much rather have them be private (this
should have no problem accessing private member, should it not?).
If anyone would be able to provide some wisdom, it would be much appreciated.
EDIT: I was wrong, it seems both ways of obtaining a pointer to the current object allow me to call private functions as long as its done within said object. However, I still don't know why out of my two code snippets, one works and one doesn't.
EDIT 2: compiled JS code that throws error "uncaught TypeError: this.onPageShown is not a function at HTMLDocument.App.init"
var pageShownEvent = new Event("pageShown");
var App = /** @class */ (function () {
function App() {
this.pages = null;
}
App.prototype.onPageShown = function (ev) {
console.log("Method called as callback");
};
App.prototype.navToPage = function (pageId) {
console.log("Nav to page " + pageId);
document.querySelector(".active").classList.remove("active");
document.getElementById(pageId).classList.add("active");
document.getElementById(pageId).dispatchEvent(pageShownEvent);
};
App.prototype.init = function () {
this.pages = document.querySelectorAll(".page");
console.log(this.pages);
for (var i = 0; i < this.pages.length; ++i) {
this.pages[i].addEventListener("pageShown", App.getInstance().onPageShown);
/*
TypeError thrown here
*/
this.onPageShown(null);
}
/*this.pages.forEach((pg: HTMLDivElement) => {
pg.addEventListener("pageShown", App.getInstance().onPageShown);
});*/
document.querySelectorAll(".nav-link").forEach(function (link) {
link.addEventListener("click", function (ev) {
//console.log("click");
ev.preventDefault;
var target = ev.target;
var currentPage = target.getAttribute("data-target");
console.log(currentPage);
App.getInstance().navToPage(currentPage);
/*document.querySelector(".active").classList.remove("active");
document.getElementById(currentPage).classList.add("active");
document.getElementById(currentPage).dispatchEvent(pageShownEvent);*/
//history.replaceState({}, currentPage, `#${currentPage}`);
});
});
//history.replaceState({}, "1", "#1");
};
// ensure only 1 instance is created
App.getInstance = function () {
if (!App.instance) {
App.instance = new App();
}
return App.instance;
};
return App;
}());