UNPKG

@valkyr/mvc

Version:

A small model view controller implementation for web frameworks.

128 lines 5.07 kB
"use strict"; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _Controller_debounce; Object.defineProperty(exports, "__esModule", { value: true }); exports.Controller = void 0; const Debounce_1 = require("./Debounce"); class Controller { /** * Creates a new controller instance with given default state and pushState * handler method. * * @param state - Default state to assign to controller. * @param pushState - Push state handler method. */ constructor(state = {}, pushState) { this.state = state; this.pushState = pushState; /** * Records of rxjs subscriptions. They are keyed to a subscription name for * easier identification when unsubscribing. */ this.subscriptions = {}; /** * Internal debounce instance used to ensure that we aren't triggering state * updates too frequently when updates are happening in quick succession. */ _Controller_debounce.set(this, new Debounce_1.Debounce()); } /* |-------------------------------------------------------------------------------- | Factories |-------------------------------------------------------------------------------- */ /** * Creates a new controller instance with given push state handler. * * @remarks This factory method will pass the static state as defined on the * controller. * * @param pushState - Push state handler method. */ static make(pushState) { return new this({ ...this.state }, pushState); } /** * Loop through all registered subscriptions and executes the unsubscribe * handler for each subscription. This should be triggered when the view is * unmounted. */ async destroy() { for (const subscription of Object.values(this.subscriptions)) { subscription.unsubscribe(); } return this; } query(name, query = {}, next) { this.subscriptions[name]?.unsubscribe(); return new Promise((resolve) => { const { model, where, ...options } = query; this.subscriptions[name] = model.subscribe(where, options, (value) => { this.setState(name, next !== undefined ? next(value) : value); resolve(value); }); }); } /* |-------------------------------------------------------------------------------- | RXJS Methods |-------------------------------------------------------------------------------- */ /** * Subscribe to a resource which provides a rxjs observable subscription. This * subscription is automatically managed and will unsubscribe when the subscribe * method is executed and when the controller is destroyed. * * @remarks If the subscription does not immediately resolve a value then set * the suspend argument to false. * * @param name - Name of the state key we are pushing the subscription values to. * @param rxjs - RXJS Subject or Observable instance that can be subscribed to. * @param next - Custom handler to execute instead of direct assignment to state. */ subscribe(name, rxjs, next) { this.subscriptions[name]?.unsubscribe(); this.subscriptions[name] = rxjs.subscribe((value) => { this.setState(name, next !== undefined ? next(value) : value); }); } setState(key, value) { if (value === undefined) { return (state) => { this.setState(key, state); }; } this.state[key] = value; __classPrivateFieldGet(this, _Controller_debounce, "f").run(() => { this.pushState({ ...this.state }); }, 0); } /* |-------------------------------------------------------------------------------- | Resolvers |-------------------------------------------------------------------------------- */ /** * Returns all the prototype methods defined on the controller as a list of * actions bound to the controller instance to be used in the view. * * @returns List of actions. */ toActions() { const actions = {}; for (const name of Object.getOwnPropertyNames(this.constructor.prototype)) { if (name !== "constructor") { actions[name] = this[name].bind(this); } } return actions; } } exports.Controller = Controller; _Controller_debounce = new WeakMap(); Controller.state = {}; //# sourceMappingURL=Controller.js.map