Re Rendering on Model Change - ldco2016/microurb_web_framework GitHub Wiki
Anytime my Model gets updated, I want to re-render this HTML, essentially reproduce the template and stick it back on the page.
To do so, in my Model Class I added in the events
property. Additionally, anytime I change any properties on an instance of a Model, in this case the User Model, I would also trigger an event called change
inside the setter:
import { AxiosPromise, AxiosResponse } from "axios";
interface ModelAttributes<T> {
set(value: T): void;
getAll(): T;
get<K extends keyof T>(key: K): T[K];
}
interface Sync<T> {
fetch(id: number): AxiosPromise;
save(data: T): AxiosPromise;
}
interface Events {
on(eventName: string, callback: () => void): void;
trigger(eventName: string): void;
}
interface HasId {
id?: number;
}
export class Model<T extends HasId> {
constructor(
private attributes: ModelAttributes<T>,
private events: Events,
private sync: Sync<T>
) {}
on = this.events.on;
trigger = this.events.trigger;
get = this.attributes.get;
set(update: T): void {
this.attributes.set(update);
this.events.trigger("change");
// Object.assign(this.data, update);
}
The change
event is what tells other parts of my application that some data has updated.
When I create an instance of a view class I will listen for the Model that gets passed in, specifically for a change
event. When that change
event occurs I must have set some new data on my Model and I should attempt to re-render my View.
I will add in some code to my constructor()
to ensure anytime I receive this model
, right away I am going to start listening for the change
event and when its triggered I am going to run that render()
.
import { User } from "../models/User";
export class UserForm {
constructor(public parent: Element, public model: User) {
this.model.on("change", () => {
this.render();
});
}
One thing I might do to slightly improve this is maybe extract it to a helper method like so:
import { User } from "../models/User";
export class UserForm {
constructor(public parent: Element, public model: User) {
this.bindModel();
}
bindModel(): void {
this.model.on("change", () => {
this.render();
});
}
I like to keep the constructor()
as simple as possible just to make it easier to understand exactly what happens when I create an instance of user form.
It kind of works, but everytime I click on the button it duplicates the HTML, so how to fix that?
I will head back to my render()
method and say the instant I start to render a second time I am going to look at the parent
element that contains all the HTML, remove it, and replace with the newly rendered template.
To empty out the parent element I will do the following:
render(): void {
this.parent.innerHTML = "";
const templateElement = document.createElement("template");
templateElement.innerHTML = this.template();
this.bindEvents(templateElement.content);
this.parent.append(templateElement.content);
}
So I emptied out the parent
element, re-render the template with templateElement
, bind my events with this.bindEvents()
and stick it into the parent element with this.parent.append()
.