npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mvvm.js

v1.0.0

Published

Model-View-ViewModel Simple Framework

Downloads

3

Readme

MVVM.js

NPM Build Status Code Coverage

This package provides a simple framework that is implementing the Model-View-ViewModel architectural pattern.

Why?

This repository demonstrates a pure Model-View-ViewModel architectural pattern implementation. The framework provides a component model similar to all the modern frontend frameworks and can be used for reactive rendering in trivial JavaScript or TypeScript applications.

Features

  • Reactivity based on observables similar to Vue.js.
  • Decorators defining a data-flow similar to Angular.
  • JSX syntax support similar to React.
  • JSX Fragments support.
  • Lazy DOM updating based on observables without expensive diffing.

Introduction

Model

The model is a data-layer of an application.

const model = { name: 'John' };

View

The view is a representation of a model describing appearance on the screen and bindings between the model data and the representation.

View-Model

The view-model is an abstraction of the view exposing public properties and commands. A data inside the view can be changed through the view-model, and the user's interaction can be handled from the external code via the commands.

Binding

The binding is an expression bound to a particular part of the representation. The view is evaluating the expression upon rendering. In case, when the expression is relying on some observables, the expression will be re-evaluated upon the observable change. Bindings are working one-way only, and provide one-way incoming data flow. There is no way to update the binding from a view.

@Bind('style.display') visibility() {
  return !this.visible && 'none';
}

Command

The command is a function that will be invoked from the representation upon some user interaction. Commands can be listened from the external code and provide one-way outgoing data-flow.

@Command click() {}

Input

The input is a two-way data binding between a model property and a property available from the representation. Properties marked as inputs are observables. The view subscribes for the changes of used inputs and performs partial rerendering on demand. The inputs provide two-way data-flow for the data between a model and its representation.

@Input name?: string;

Expression

The expression is a value that depends on some data that may change in the future. The view automatically evaluates all the expressions during the rendering. In case, when it is relying on some observable, the value will be reevaluated upon change.

render() {
  return <div class={() => this.visible ? 'show' : 'hide'} />
}

Observable

The observable is a value that may change later, and the changes can be observed from the outside.

Component

The component is a composition of the view and the view-model. There can be Class and Functional components. Components accept properties on input, which represent a model. The code of the functional component is the view. In the case of the class component, the render method with all the bindings correspond to the view. And all the inputs and commands define the view-model.

import { Component, Input } from 'mvvm.js';

class Button extends Component {
  @Input label?: string;

  render() {
    return <button>{this.label}</button>;
  }
}

Reference

The reference is a model value that refers to property from another object. In case, when a model property should be passed down to another view-model, the property should be passed as a reference. Every update of the referring property from the child component will take place in the referred object.

<Toggle active={$reference(this, 'visible')} />

Get Started

Installation

npm install --save mvvm.js

Usage

import { Bind, Command, Component, Default, Input } from 'mvvm.js';
import { render } from 'mvvm.js/lib/dom';

interface ButtonProps {
  icon?: string;
  label?: string;
  visible?: boolean;
  click?(button: UIButton): void;
}

class Button extends Component<ButtonProps> {
  @Input icon?: string;

  @Input label?: string;

  @Input @Default(true) visible?: boolean;

  @Command click() {}

  @Bind('style.display') visibility() {
    return !this.visible && 'none';
  }

  render() {
    return (
      <a role="button" class="btn btn-primary" title={() => this.label} onClick={this.click}>
        {() => this.icon && <i class={`fa fa-${this.icon}`}></i>}
        {() => this.label}
      </a>
    );
  }
}

render(
  <Button label='Button' />,
  document.querySelector('#root')!,
);

API

You can find the complete API reference here.

Example

You can see a working demo here (source code).