@valkyr/mvc
Version:
A small model view controller implementation for web frameworks.
128 lines • 5.07 kB
JavaScript
;
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