Skateside / pocket-grimoire-2

A "thinking out loud" upgrade to the Pocket Grimoire
0 stars 0 forks source link

Allow a Model and a View to request data #14

Open netcall-jlo opened 2 months ago

netcall-jlo commented 2 months ago

Thinking aloud, but this in RoleSelectController is a bit weird view.on("random-select", () => view.tickRoles(model.getRandomRoleIds()));

Something like this would be a lot tidier

class RoleSelectView extends View<{
    // ...
}> {
    addListeners() {
        // ...
        findOrDie("#role-select-random").addEventListener("click", () => {
            this.request("getRandomRoleIds").then((ids) => this.tickRoles(ids));
        });
    }
}

.request() should be able to pass them method name and any parameters. The Controller can activate those methods, otherwise they're just empty Promise generators that never resolve.

netcall-jlo commented 2 months ago
type IModelExpose = Record<string, (...args: any[]) => any>;

class Model {

    getRandomRoleIds(count: number) {
        return new Array(count).fill("a");
    }

    expose(): IModelExpose {

        return {
            getRandomRoleIds(count = 1) {
                return this.getRandomRoleIds(count);
            },
        };

    }

}

class View {

    public button: HTMLButtonElement;
    private exposed: IModelExpose;

    addListeners() {

        this.button.addEventListener("click", () => {
            this.processIds( this.request('getRandomIds') || [] );
            this.processIds( this.request('getRandomIds', this.getCount()) || [] );
        });

    }

    getCount() {
        return 4;
    }

    processIds(ids: string[]) {
        // ...
    }

    request(method: string, ...args: any[]) {

        const { exposed = {} } = this;
        const func = exposed[method];

        if (typeof func === 'function') {
            return func(...args);
        }

    }

    setExposed(exposed: IModelExpose) {
        this.exposed = exposed;
    }

}

class Controller<M extends Model, V extends View> {

    public model: M;
    public view: V;

    constructor(model: M, view: V) {

        this.model = model;
        this.view = view;

        this.view.setExposed(this.model.expose());

    }

}

const controller = new Controller(new Model(), new View());