Defining an Event Map - ldco2016/microurb_web_framework GitHub Wiki
I can now show some HTML to a user which is a great step forward, but now I think I need to work on ability to have some event handlers tied to this HTML as well.
Let's say I add a button to my template with a text of Click Me
like so:
export class UserForm {
constructor(public parent: Element) {}
template(): string {
return `<div>
<h1>User Form</h1>
<input />
<button>Click Me</button>
</div>`;
}
render(): void {
const templateElement = document.createElement("template");
templateElement.innerHTML = this.template();
console.log(this.parent);
this.parent.append(templateElement.content);
}
}
If I now head back to the browser, the button appears but if I click it nothing happens and we didn't really have any easy way to somehow add an event handler to the button. So I needed to have the ability to detect a click on the button and run some custom code anytime a click occurs.
So here is a timeline on how to accomplish this:

This is a timeline describing everything that happens inside a render method and I added one additional step along the way.
So whenever I call the render method I call the template method and I get back that HTML string and at that point in time its just a string, to actually turn it into HTML, I insert that HTML string into a template element. That's when it actually gets turned into something useful.
Right after that is when I decided that it would be a good time to bind some event handlers to the HTML that is inside of that template element.
Right after that I continue to take that content of a template and insert it into the DOM.
Right above my template I added in an event handler that I want to run anytime I click on the button element like so:
export class UserForm {
constructor(public parent: Element) {}
onButtonClick() {
console.log("Howdy");
}
template(): string {
return `<div>
<h1>User Form</h1>
<input />
<button>Click Me</button>
</div>`;
}
render(): void {
const templateElement = document.createElement("template");
templateElement.innerHTML = this.template();
console.log(this.parent);
this.parent.append(templateElement.content);
}
}
So I needed to tie that onButtonClick
method to the button element. Keeping in mind that the HTML string is worthless, its only useful once it has been inserted into the templateElement
.
So what I did was add in a method called eventsMap
and everytime I call it, I return an object with keys and values that are strings contain an event name like click or hover or change and then after that a colon and selector to the element that I want to bind the element to.
export class UserForm {
constructor(public parent: Element) {}
eventsMap() {
return {
"click:button": this.onButtonClick,
};
}
onButtonClick() {
console.log("Howdy");
}
template(): string {
return `<div>
<h1>User Form</h1>
<input />
<button>Click Me</button>
</div>`;
}
render(): void {
const templateElement = document.createElement("template");
templateElement.innerHTML = this.template();
console.log(this.parent);
this.parent.append(templateElement.content);
}
}
So what I am trying to express here is that I want to somehow set up a click event handler to a button inside of my template and anytime that thing gets clicked I want to run this function here this.onButtonClick
.
So essentially the key inside this object there is going to be a ton of meaning associated with them. So I need to parse that key 'click:button'
and understand that I am trying to set up a click event handler on the button.
I need to somehow express to Typescript that I am going to be returning some keys where I don't really know what the keys are going to be ahead of time like so:
export class UserForm {
constructor(public parent: Element) {}
eventsMap(): { [key: string] } {
return {
"click:button": this.onButtonClick,
};
}
onButtonClick() {
console.log("Howdy");
}
template(): string {
return `<div>
<h1>User Form</h1>
<input />
<button>Click Me</button>
</div>`;
}
render(): void {
const templateElement = document.createElement("template");
templateElement.innerHTML = this.template();
console.log(this.parent);
this.parent.append(templateElement.content);
}
}
This tells TypeScript, I am going to return an object, but I don't know what the keys are going to be, but they are going to be strings.
Then I am going to say the value for everything inside the object is going to be a function that takes no arguments and returns nothing like so:
export class UserForm {
constructor(public parent: Element) {}
eventsMap(): { [key: string]: () => void } {
return {
"click:button": this.onButtonClick,
};
}
onButtonClick() {
console.log("Howdy");
}
template(): string {
return `<div>
<h1>User Form</h1>
<input />
<button>Click Me</button>
</div>`;
}
render(): void {
const templateElement = document.createElement("template");
templateElement.innerHTML = this.template();
console.log(this.parent);
this.parent.append(templateElement.content);
}
}
So this eventsMap
is how I am going to relate the different events I am going to watch for inside my template
to the different events I want to run.