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

errisy-bindable

v1.0.3

Published

a native JavaScript object-to-object binding framework based on TypeScript decorators

Downloads

1

Readme

errisy-bindable

  • the native JavaScript object-to-object binding via TypeScript decorators with out-of-box type-to-type serialization-deserialztion solution.

Well, of course you can also set up the bindings with JavaScript only without TypeScript. But like what you normally do with Angular2 projects, with TypeScript, it is a lot earsier.

Please use ES5 mode in TypeScript compiler javascript ES6 changed the class definition strategy to

class ClassName extends Ancestor{

}

Since errisy-bindable has constructor manipulation in the @obs.bindable decorator, and the ES6 constructor can not be properly accessed by the new internal class constructor in the @obs.bindable decorator. So please use ES5 at the moment.

ES6 mode will be supported later.

to install errisy-bindable

npm install errisy-bindable

Why?

Many javascript framework has the binding feature for HMTL templates, such AngularJS, KnockoutJS, etc. But with the power of typescript decorators, it is possible to set up object to object bindings with simple decorator codes.

Bindings and Events are the basis of UI automation. This project was inspired by the concept of WPF(Windows Presentation Foundation). When I try to apply MVVM pattern to canvas UI framework such as EaselJS, I found that I must set up a higher level of automation and abstraction of the EaselJS APIs to achieve MVVM. So I developed errisy-bindable.

I believe that I can also apply errisy-bindable on native HTMLElements or frameworks such as React as well to achieve simple MVVM pattern.

This native JavaScript two-way binding framework offers a front-end UI style that is very similar to WPF MVVM two-way bindings.

What does it do?

object-to-object binding

There is no real object-to-object binding in most of the front end frameworks such as Angular or Knockout. The bindings are only between UI field/presentation and the object (at least in the case of Angular 1 & 2).

What is real object-to-object binding? It means when binding is set up, changing the value of one object will affect the bound property and vice versa.

weak binding to field (not to object itself).

If you have object A, and you set up A.x binding to A.y, where A.y is a property that anything can be assigned to there. So errisy-bindable ensures that when you set another object to A.y, the A.x will be automatically updated to the new object.

wrap of native elements

Those bindings only works with objects you defined. For native elements/javascript objects, since they won't send changed signal to our bindable objects, we use wrap method to wrap them.

try out the test:

In the following test you will see that errisy-bindable does wrap, two-way binding.

export class NativeElement {
    private _value: string;
    public get value(): string {
        return this._value;
    }
    public set value(value: string) {
        console.log(`value of NativeElement is set to ${value}`);
        this._value = value;
    }
}

@obs.bindable
export class Leg {
    @obs.property
    public length: number;
}

 

@obs.bindable
export class Dog   {

    @obs.property public leg: Leg;
    @obs.property public native: NativeElement;

    @obs.bind(() => Dog.prototype.leg.length, PathBindingMode.syncFrom)
        .before(() => Dog.prototype.BeforeLegLengthChanged)
        .after(() => Dog.prototype.AfterLegLengthChanged)
        .wrap(() => Dog.prototype.native.value)
        .property
    public legLength: number;

    @obs.event
    public BeforeLegLengthChanged() {
        console.log('BeforeLegLengthChanged', arguments);
    }

    @obs.event
    public AfterLegLengthChanged() {
        console.log('AfterLegLengthChanged', arguments);
    }
}


class TestCases {
    public bind() {
        let dog = new Dog();
        let leg = new Leg();
        let native = new NativeElement();
        dog.native = native;

        console.log('>>> Set dog.leg = leg');
        dog.leg = leg;

        let doc = obs.getDecorator(dog, 'leg', true);

        console.log('leg decorator: ', doc);

        console.log('>>> Set leg.length = 20');
        leg.length = 20;

        console.log('>>> Check dog.legLength: ', dog.legLength, ' <-- this means after you assign let to dog.leg, when you change leg.length, dog.legLength is automatically updated.');

        console.log('>>> Set dog.legLength = 30');
        dog.legLength = 30;

        console.log('>>> Check leg.length: ', leg.length);
    }

}

observe collection and subscribe collection events

Similar to previous case, you can set up A.x to observe the collection A.y, and listen the event of every element in A.y.

Typed Serialization and Deserialization

errisy-bindable has an out-of-box serialization and deserialization system. For a @obs.bindable decorated type/class, you can serialize it into string and deserialize to the original type/class. This is very useful feature in the front-end UI. In complex front UI, you may need to rebuild the UI from a simple deserialization, rather than writing codes to build them manually. If you have properly set up UI framework element binding to the @obs.bindable objects, the UI can be rebuild during deserialization.

In my case, I can serialize multiple gene vectors view in my project, where EaselJS is wrapped with errisy-bindable:

Example

That's pretty much all you need to build your own MVVM on top of any UI framework.

How does it work?

bindable ts enables simple binding set up with member decorators @obs.bind(()

Set up binding simply and specify behaviors of a property with before/after etc.

@obs.bindable 
class Person {
    @obs.property
    public Name: string;
    @obs
      .bind(()=>Person.prototyope.Name.FirstName)
      .before(()=>Person.prototype.beforeFirstNameChange)
      .after(()=>Person.prototype.FirstNameChanged)
      .property
    public FirstName: string;
    @obs.event
    public beforeFirstNameChange = () => {
        console.log('before first name is changed.');
    }
    @obs.event
    public FirstNameChanged = () => {
        console.log('first name is changed.');
    }
}
@obs.bindable
class Name{
    @obs.property
    public Surname: string;
    @obs.property
    public FirstName: string;
}

let p = new Person();
p.FirstName = 'Jack'; // p.Name.FirstName will change as well.

Observe an Observable Array

ObservableArray is another feature of the bindable ts. It can monitor another ObservableArray (ObservationSource), transform the elements with observer, and keep the transformed elements in it. It can also transform its own elements with populator and write into the PopulationTarget array.

@obs.bindable 
class Bird {
    @obs.property
    public Name: string;
}
@obs.bindable
class Branch {
    @obs.observable(ObservableArray).property
    public birds: ObservableArray<Bird>;
}
@obs.bindable
class host {
    @obs.property
    branch: Branch;
    @obs.observable(ObservableArray).default(()=>ObservableArray.prototype.parent).observe(() => host.prototype.branch.birds).property 
    public catched: ObservableArray<Bird>;
}

let h = new host();
console.log('just initialized', h.branch?h.branch.birds.asArray():null, h.catched.asArray());
h.branch = new Branch();
console.log('after set branch', h.branch.birds.asArray(), h.catched.asArray());
h.branch.birds.push(obs.new(new Bird(), b => b.Name = 'macaw'));

console.log('after add macaw', h.branch.birds.asArray(), h.catched.asArray());

Set up event listener

@obs.bindable
class base {
    @obs.property
    seed0: sender = new sender();

    @obs.listen(()=>base.prototype.seed0.tick).event
    method = () => {
        console.log('--- base.method invoked ---');
    }
}
@obs.bindable
class host extends base {
    @obs.property
    seed1: sender = new sender();
    @obs.property
    seed2: sender = new sender();


    @obs
      .listen(()=>host.prototype.seed1.tick, ()=>host.prototype.seed2.tick) //the event can listen multiple sources
      .event
    method = () => {
        console.log('--- host.method invoked ---');
    }
}
@obs.bindable
class sender {
    @obs.event
    public tick = () => {
    }
}

let h = new host();
console.log('h.seed0.tick()');
h.seed0.tick();
console.log('h.seed1.tick()');
h.seed1.tick();
console.log('h.seed2.tick()');
h.seed2.tick();