7.0.25 • Published 4 months ago

j-templates v7.0.25

Weekly downloads
347
License
MIT
Repository
github
Last release
4 months ago

j-templates

Type-safe templating for the browser.

Install

npm install --save-dev j-templates

Hello World - sample

import { Component } from 'j-templates';
import { div } from 'j-templates/DOM';

class HelloWorld extends Component {

    public Template() {
        return div({ text: "Hello world" });
    }

}

var helloWorld = Component.ToFunction("hello-world", null, HelloWorld);
Component.Attach(document.body, hellowWorld({}));

Resulting HTML

<hello-world>
    <div>Hello world</div>
</hello-world>

State Management

Store

The library provides two Store types: StoreSync and StoreAsync. The only difference is StoreAsync uses a WebWorker to calculate changes to the state of the Store.

import { StoreSync } from 'j-templates/Store'

// Creates a store with the passed value as the root
var store = new StoreSync({
    firstProperty: 'first value',
    secondProperty: 'second value',
    array: [] as string[]
});

Any values retrieved from a Store are read-only. A Store provides methods for modifying its root value.

// Update overwrites the root of the store
// Returns a Promise that resolves when the update is complete
store.Update({
    firstProperty: 'new first value',
    secondProperty: 'new second value',
    array: ['first array value']
}).then(() => console.log("Update complete"));

// Merge allows for a Partial<> value to be written
// Returns a Promise that resolves when the merge is complete
store.Merge({
    firstProperty: 'merged first value'
}).then(() => console.log("Merge complete"));

A Store can be passed a callback to compute unique IDs on stored objects. Objects with an ID can be retrieved directly. If a second object with the same ID is saved to the Store it will overwrite the first.

// Second parameter to Store contructor is a callback to calculate object IDs
var store = new StoreSync({}, (obj: any) => obj._id);

// store.Write allows you to write an object with an ID to the store
// Returns a Promise that resolves when the Write is complete
store.Write({ 
    _id: 'very-unique-id',
    property: 'useful data'
}).then(() => console.log("Write complete"));

The above methods are wrappers for the store.Action method. store.Action can be used to perform more complicated updates. Calls to store.Action are queued and executed sequentially so it's important to await any async methods called within the store.Action callback.

// store.Action async callback gets passed StoreReader and StoreWriter objects
// Returns a Promise that resolves when the Action is complete
store.Action(async (reader, writer) => {
    // reader is used to get objects from the Store
    var obj = reader.Get<{ _id: string, property: string }>('very-unique-id');
    // writer is used to modify objects retrieved by the reader
    await writer.Merge(obj, { property: 'changed useful data' });
}).then(() => console.log('Action complete'));

The StoreWriter object has methods similar to Store plus a few extra methods to assist with modifying arrays:

store.Action(async (reader, writer) => {
    var obj = reader.Get<{ 
        _id: string, 
        property: string, 
        array: Array<string> 
    }>('very-unique-id');

    await writer.Push(obj.array, 'new array value');
});

Call Destroy on a Store when finished with it:

store.Destroy();

Scope

A Scope is used to observe changes made to any Stores or Scopes referenced during its value callback. A Store provides a Scope to access its root value:

console.log(store.Root.Value.firstProperty);
// outputs: 'merged first value'

store.Query creates a Scope that can access items from the root or by ID.

// store.Query callback gets passed a StoreReader object
var query = store.Query(reader => {
    // reader.Root is not a scope
    var rootValue = reader.Root;
    var idValue = reader.Get<{ _id: string, property: string }>('very-unique-id');
    return `${rootValue.firstProperty} - ${idValue.property}`;
});

A new Scope can be created from an existing Scope:

// store.Root.Scope callback gets passed the current value of the scope
var childScope = store.Root.Scope(root => root.firstProperty);
console.log(childScope.Value);
// outputs: 'merged first value'

OR a new Scope can be created directly:

import { Scope } from 'j-templates/Store';

// new Scope callback receives no parameters
var scope = new Scope(() => store.Root.Value.firstProperty);
console.log(scope.Value);
// outputs: 'merged first value'

To watch for changes to a Scope:

scope.Watch((scope) => {
    console.log(scope.Value)
});

Call Destroy() on a Scope when finished with it:

query.Destroy();
childScope.Destroy();
scope.Destroy();

Building Components

// 'Component' is the base type required for components. 
// 'NodeRef' is the base type for all types used in template definitions.
import { Component, NodeRef } from 'j-templates';
// div, h1 are template element functions
import { div, h1 } from 'j-templates/DOM';

// Type definition for the data this 'Component' can receive from a 
// parent 'Component'
interface IData {
    title: string;
}

// Type definition for the template definitions this 'Component' accepts 
// from a parent 'Component'
interface ITemplates {
    body: () => NodeRef | NodeRef[];
}

// Type definition for the events this `Component` supports. A `Component` does 
// not support standard DOM events and must define the events that can be 
// listened for by a parent `Component`. The type of the interface property 
// defines the type of the parameter passed when the event fires. Void indicates 
// no parameter is passed to the event.
interface IEvents {
    headerClick: void;
}

// Class definition extending Component. Component accepts three optional 
// generic types defining: Data, Templates, and Events.
class MyComponent extends Component<IData, ITemplates, IEvents> {
    // Store definition
    _store = new StoreSync({ headerToggled: false });
    // Scope definition
    _headerClassScope = this._store.Scope(root => {
        return root.headerToggled ? 'toggled' : 'not-toggled';
    });

    // getter to clean up accessing Scope value
    get HeaderClass() {
        return this._headerClassScope.Value;
    }

    // Component.Template definition function
    public Template() {
        return [
            // h1 element
            h1({
                // dynamic props binding. If a function is not used then a static
                // binding is created.
                // Type maps 1to1 to Partial<HTMLElement> type
                props: () => ({
                    className: this.HeaderClass
                }),
                // static on binding
                // IEvents type
                on: { 
                    click: () => {
                        // this.Fire fires 'Component' events
                        this.Fire("headerClick");
                    }
                },
                // dynamic text binding
                // sets the text of the element
                // this.Data contains data passed from the parent 'Component'
                text: () => this.Data.title 
            }),
            div({ props: { className: "body" } }, () => 
                // Templates passed from a parent component are available through
                // the this.Templates property
                this.Templates.body()
            )
        ]
    }

    // Component.Destroy to clean up Component
    public Destroy() {
        super.Destroy();
        this._headerClassScope.Destroy();
        this._store.Destroy();
    }

}

// Convert Component to function to be referenced in other templates
export var myComponent = Component.ToFunction("my-component", null, MyComponent);

Using Components

import { Component } from 'j-templates';
import { input } from 'j-templates/DOM';
import { myComponent } from './myComponent';

class RootComponent extends Component {

    _state = new StoreSync({ inputValue: "" });
    _inputValueScope = this._state.Scope(root => root.inputValue);
    get InputValue() {
        return this._inputValueScope.Value;
    }

    public Template() {
        return [
            input({ props: () => ({ value: this.InputValue }) }),
            myComponent({
                data: () => ({ title: this.InputValue })
            }, {
                body: () =>
                    div({ text: "passed from RootComponent" })
            })
        ]
    }

    public Destroy() {
        super.Destroy();
        this._state.Destroy();
        this._inputValueScope.Destroy();
    }
}

var rootComponent = Component.ToFunction("root-component", null, RootComponent);
Component.Attach(document.body, rootComponent({}));
7.0.12

6 months ago

7.0.13

6 months ago

7.0.10

6 months ago

7.0.11

6 months ago

7.0.18

4 months ago

7.0.19

4 months ago

7.0.16

4 months ago

7.0.17

4 months ago

7.0.14

4 months ago

7.0.15

4 months ago

6.1.8

8 months ago

6.1.7

8 months ago

6.1.9

8 months ago

6.1.12

7 months ago

6.1.11

7 months ago

6.1.10

8 months ago

7.0.8

6 months ago

7.0.7

6 months ago

7.0.6

6 months ago

7.0.5

6 months ago

7.0.9

6 months ago

7.0.0

6 months ago

7.0.4

6 months ago

7.0.3

6 months ago

7.0.1

6 months ago

7.0.23

4 months ago

7.0.24

4 months ago

7.0.21

4 months ago

7.0.22

4 months ago

7.0.20

4 months ago

7.0.25

4 months ago

6.1.6

9 months ago

6.1.5

9 months ago

6.1.0

9 months ago

6.1.2

9 months ago

6.1.1

9 months ago

6.1.4

9 months ago

6.1.3

9 months ago

6.0.49

9 months ago

6.0.48

9 months ago

6.0.47

9 months ago

6.0.46

9 months ago

6.0.45

9 months ago

6.0.7

10 months ago

6.0.6

10 months ago

6.0.9

10 months ago

6.0.8

10 months ago

6.0.1

10 months ago

6.0.0

11 months ago

6.0.3

10 months ago

6.0.2

10 months ago

6.0.5

10 months ago

6.0.4

10 months ago

6.0.27

10 months ago

6.0.26

10 months ago

6.0.25

10 months ago

6.0.24

10 months ago

6.0.29

10 months ago

6.0.28

10 months ago

6.0.23

10 months ago

6.0.22

10 months ago

6.0.21

10 months ago

6.0.20

10 months ago

6.0.16

10 months ago

6.0.15

10 months ago

6.0.14

10 months ago

6.0.13

10 months ago

6.0.19

10 months ago

6.0.18

10 months ago

6.0.17

10 months ago

6.0.12

10 months ago

6.0.11

10 months ago

6.0.10

10 months ago

6.0.41

9 months ago

6.0.40

9 months ago

6.0.44

9 months ago

6.0.43

9 months ago

6.0.42

9 months ago

6.0.38

9 months ago

6.0.37

9 months ago

6.0.36

9 months ago

6.0.35

9 months ago

6.0.39

9 months ago

6.0.30

10 months ago

6.0.34

9 months ago

6.0.33

10 months ago

6.0.32

10 months ago

6.0.31

10 months ago

5.0.52

11 months ago

5.0.53

11 months ago

5.0.54

11 months ago

5.0.51

2 years ago

5.0.50

2 years ago

5.0.47

2 years ago

5.0.48

2 years ago

5.0.49

2 years ago

5.0.44

2 years ago

5.0.45

2 years ago

5.0.46

2 years ago

5.0.37

3 years ago

5.0.38

3 years ago

5.0.39

3 years ago

5.0.40

3 years ago

5.0.41

3 years ago

5.0.42

3 years ago

5.0.43

3 years ago

5.0.36

3 years ago

5.0.35

4 years ago

5.0.34

4 years ago

5.0.33

4 years ago

5.0.32

4 years ago

5.0.31

4 years ago

5.0.30

5 years ago

5.0.28

5 years ago

5.0.29

5 years ago

5.0.27

5 years ago

5.0.26

5 years ago

5.0.25

5 years ago

5.0.24

5 years ago

5.0.23

5 years ago

5.0.21

5 years ago

5.0.20

5 years ago

5.0.18

5 years ago

5.0.16

5 years ago

5.0.17

5 years ago

5.0.15

5 years ago

5.0.13

5 years ago

5.0.12

5 years ago

5.0.11

5 years ago

5.0.9

5 years ago

5.0.10

5 years ago

5.0.8

5 years ago

5.0.7

5 years ago

5.0.6

5 years ago

5.0.4

5 years ago

5.0.3

5 years ago

5.0.2

5 years ago

5.0.1

5 years ago

5.0.0

5 years ago

4.0.146

5 years ago

4.0.145

5 years ago

4.0.143

5 years ago

4.0.144

5 years ago

4.0.142

5 years ago

4.0.141

5 years ago

4.0.139

5 years ago

4.0.140

5 years ago

4.0.138

5 years ago

4.0.135

5 years ago

4.0.137

5 years ago

4.0.123

5 years ago

4.0.124

5 years ago

4.0.122

5 years ago

4.0.127

5 years ago

4.0.128

5 years ago

4.0.126

5 years ago

4.0.129

5 years ago

4.0.130

5 years ago

4.0.131

5 years ago

4.0.134

5 years ago

4.0.132

5 years ago

4.0.133

5 years ago

4.0.121

5 years ago

4.0.120

5 years ago

4.0.119

5 years ago

4.0.118

5 years ago

4.0.117

5 years ago

4.0.116

5 years ago

4.0.114

5 years ago

4.0.115

5 years ago

4.0.113

5 years ago

4.0.109

5 years ago

4.0.108

5 years ago

4.0.112

5 years ago

4.0.110

5 years ago

4.0.111

5 years ago

4.0.107

5 years ago

4.0.106

5 years ago

4.0.105

5 years ago

4.0.104

5 years ago

4.0.101

5 years ago

4.0.102

5 years ago

4.0.100

5 years ago

4.0.103

5 years ago

4.0.98

5 years ago

4.0.97

5 years ago

4.0.99

5 years ago

4.0.96

5 years ago

4.0.95

5 years ago

4.0.94

5 years ago

4.0.93

5 years ago

4.0.92

5 years ago

4.0.91

5 years ago

4.0.90

5 years ago

4.0.89

5 years ago

4.0.88

5 years ago

4.0.84

5 years ago

4.0.83

5 years ago

4.0.82

5 years ago

4.0.80

5 years ago

4.0.79

5 years ago

4.0.78

5 years ago

4.0.77

5 years ago

4.0.76

5 years ago

4.0.74

5 years ago

4.0.73

5 years ago

4.0.75

5 years ago

4.0.71

5 years ago

4.0.70

5 years ago

4.0.67

5 years ago

4.0.69

5 years ago

4.0.68

5 years ago

4.0.66

5 years ago

4.0.65

5 years ago

4.0.64

5 years ago

4.0.63

5 years ago

4.0.62

5 years ago

4.0.61

5 years ago

4.0.60

5 years ago

4.0.59

5 years ago

4.0.58

5 years ago

4.0.57

5 years ago

4.0.56

5 years ago

4.0.55

5 years ago

4.0.54

5 years ago

4.0.53

5 years ago

4.0.52

5 years ago

4.0.51

5 years ago

4.0.50

5 years ago

4.0.49

5 years ago

4.0.48

5 years ago

4.0.45

5 years ago

4.0.47

5 years ago

4.0.46

5 years ago

4.0.43

5 years ago

4.0.44

5 years ago

4.0.42

5 years ago

4.0.41

5 years ago

4.0.40

5 years ago

4.0.39

5 years ago

4.0.38

5 years ago

4.0.37

5 years ago

4.0.36

5 years ago

4.0.35

5 years ago

4.0.32

5 years ago

4.0.31

5 years ago

4.0.34

5 years ago

4.0.33

5 years ago

4.0.30

5 years ago

4.0.29

5 years ago

4.0.28

5 years ago

4.0.27

5 years ago

4.0.26

5 years ago

4.0.25

5 years ago

4.0.24

5 years ago

4.0.23

5 years ago

4.0.22

5 years ago

4.0.21

5 years ago

4.0.20

5 years ago

4.0.19

5 years ago

4.0.18

5 years ago

4.0.16

5 years ago

4.0.17

5 years ago

4.0.15

5 years ago

4.0.14

5 years ago

4.0.13

5 years ago

4.0.12

5 years ago

4.0.11

5 years ago

4.0.10

5 years ago

4.0.9

5 years ago

4.0.8

5 years ago

4.0.7

5 years ago

4.0.6

5 years ago

4.0.5

5 years ago

4.0.4

5 years ago

4.0.1

5 years ago

4.0.2

5 years ago

4.0.0

5 years ago

3.0.71

5 years ago

3.0.72

5 years ago

3.0.73

5 years ago

3.0.70

5 years ago

3.0.67

5 years ago

3.0.68

5 years ago

3.0.69

5 years ago

3.0.66

5 years ago

3.0.65

5 years ago

3.0.64

5 years ago

3.0.63

5 years ago

3.0.62

5 years ago

3.0.61

5 years ago

3.0.60

5 years ago

3.0.59

5 years ago

3.0.58

6 years ago

3.0.57

6 years ago

3.0.56

6 years ago

3.0.55

6 years ago

3.0.54

6 years ago

3.0.52

6 years ago

3.0.53

6 years ago

3.0.51

6 years ago

3.0.50

6 years ago

3.0.49

6 years ago

3.0.46

6 years ago

3.0.43

6 years ago

3.0.44

6 years ago

3.0.47

6 years ago

3.0.48

6 years ago

3.0.41

6 years ago

3.0.40

6 years ago

3.0.38

6 years ago

3.0.39

6 years ago

3.0.36

6 years ago

3.0.37

6 years ago

3.0.35

6 years ago

3.0.34

6 years ago

3.0.32

6 years ago

3.0.33

6 years ago

3.0.31

6 years ago

3.0.30

6 years ago

3.0.28

6 years ago

3.0.29

6 years ago

3.0.27

6 years ago

3.0.26

6 years ago

3.0.25

6 years ago

3.0.23

6 years ago

3.0.24

6 years ago

3.0.22

6 years ago

3.0.21

6 years ago

3.0.20

6 years ago

3.0.19

6 years ago

3.0.18

6 years ago

3.0.17

6 years ago

3.0.16

6 years ago

3.0.12

6 years ago

3.0.13

6 years ago

3.0.14

6 years ago

3.0.15

6 years ago

3.0.11

6 years ago

3.0.10

6 years ago

3.0.9

6 years ago

3.0.4

6 years ago

3.0.7

6 years ago

3.0.5

6 years ago

3.0.3

6 years ago

3.0.2

6 years ago

3.0.1

6 years ago

3.0.0

6 years ago

2.0.40

6 years ago

2.0.39

6 years ago

2.0.38

6 years ago

2.0.37

6 years ago

2.0.36

6 years ago

2.0.35

6 years ago

2.0.34

6 years ago

2.0.33

6 years ago

2.0.31

6 years ago

2.0.30

6 years ago

2.0.29

6 years ago

2.0.28

6 years ago

2.0.27

6 years ago

2.0.26

6 years ago

2.0.25

6 years ago

2.0.24

6 years ago

2.0.22

6 years ago

2.0.23

6 years ago

2.0.20

6 years ago

2.0.21

6 years ago

2.0.19

6 years ago

2.0.18

6 years ago

2.0.16

6 years ago

2.0.17

6 years ago

2.0.15

6 years ago

2.0.14

6 years ago

2.0.13

6 years ago

2.0.11

6 years ago

2.0.12

6 years ago

2.0.10

6 years ago

2.0.9

6 years ago

2.0.8

6 years ago

2.0.6

6 years ago

2.0.5

6 years ago

2.0.4

6 years ago

2.0.3

6 years ago

2.0.2

6 years ago

2.0.1

6 years ago

2.0.0

6 years ago

1.1.55

6 years ago

1.1.54

6 years ago

1.1.53

6 years ago

1.1.52

6 years ago

1.1.51

6 years ago

1.1.50

6 years ago

1.1.49

6 years ago

1.1.48

6 years ago

1.1.47

6 years ago

1.1.46

6 years ago

1.1.45

6 years ago

1.1.44

6 years ago

1.1.43

6 years ago

1.1.42

6 years ago

1.1.41

6 years ago

1.1.40

6 years ago

1.1.39

6 years ago

1.1.38

6 years ago

1.1.37

6 years ago

1.1.36

6 years ago

1.1.35

6 years ago

1.1.34

6 years ago

1.1.33

6 years ago

1.1.32

6 years ago

1.1.31

6 years ago

1.1.30

6 years ago

1.1.29

6 years ago

1.1.28

6 years ago

1.1.27

6 years ago

1.1.26

6 years ago

1.1.25

6 years ago

1.1.23

6 years ago

1.1.22

6 years ago

1.1.21

6 years ago

1.1.20

6 years ago

1.1.19

6 years ago

1.1.18

6 years ago

1.1.17

6 years ago

1.1.16

6 years ago

1.1.15

6 years ago

1.1.14

6 years ago

1.1.13

6 years ago

1.1.12

6 years ago

1.1.11

6 years ago

1.1.10

6 years ago

1.1.9

6 years ago

1.1.8

6 years ago

1.1.7

6 years ago

1.1.6

6 years ago

1.1.5

6 years ago

1.1.4

6 years ago

1.1.3

6 years ago

1.1.2

6 years ago

1.1.1

6 years ago

1.1.0

6 years ago

1.0.12

6 years ago

1.0.11

6 years ago

1.0.10

6 years ago

1.0.9

6 years ago

1.0.8

6 years ago

1.0.7

6 years ago

1.0.6

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago