ZPT-JS tutorial - More about updating

Intro

We have already seen how to update a template using the update command. And we have also seen reactive dictionaries in action. But in some cases this is not enough.

Take a look at this template:

<ol>
    <li data-repeat="item items">
        <span data-content="item/name">an item name</span>:
        <span data-content="item/description">an item description</span>
    </li>
</ol>
                

The javascript code to invoke ZPT-JS:

"use strict";

var zpt = require( 'zpt' );

var dictionary = new zpt.ReactiveDictionary({
    items: [ 
        {
            name: 'John',
            description: 'The number 1'
        }, 
        {
            name: 'Peter',
            description: 'The number 2'
        },
        {
            name: 'Luke',
            description: 'The number 3'
        }
    ];
});

// Parse template
zpt.run({
    root: document.body,
    dictionary: dictionary
});
                

Now we want to update the list of items. We can set the items in the dictionary this way:

dictionary.items = [ 
        {
            name: 'John',
            description: 'The number 1'
        }, 
        {
            name: 'Peter',
            description: 'The number 2'
        },
        {
            name: 'Luke',
            description: 'The number 3'
        },
        {
            name: 'Mary',
            description: 'The number 4'
        }
    ];
);
                

That code makes ZPT-JS to update the data-repeat node. It removes the current content and rebuilds it all. Perhaps this is not important for you, but it can be.

Anyway this way is not very natural, it would be great if ZPT-JS would provide a way to update the items array and then rebuilds only the needed HTML.

Adding array items

Take a look at this:

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            id: 'items',
            action: 'createArray',
            index: '_last_',
            newElement: {
                name: 'Mary',
                description: 'The number 4'
            }
        }
    ]
});
                

Using dictionaryActions makes it easy to update the dictionary and the template. Some remarks about this:

Updating array items

Now we are going to update the second item (replace Peter by Mia):

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            id: 'items',
            action: 'updateArray',
            index: 1,
            newElement: {
                name: 'Mia',
                description: 'The number 5'
            }
        }
    ]
});
                

Another way would be:

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            id: 'items',
            action: 'updateArray',
            currentElement: {
                name: 'Peter'
            },
            newElement: {
                name: 'Mia',
                description: 'The number 5'
            }
        }
    ]
});
                

Using currentElement provides an alternative way of finding elements to update or delete. The element must match all the fields of the currentElement if it is an object; if it is a literal (numeric or string) it must be equal.

Deleting array items

Now we are going to delete the first item (delete John):

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            id: 'items',
            action: 'deleteArray',
            index: '_first_'
        }
    ]
});
                

We could use a 0 value as index.

Another way would be:

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            id: 'items',
            action: 'deleteArray',
            currentElement: {
                name: 'John'
            }
        }
    ]
});
                

Using searches to define complex expressions

Take a look at this template:

<ol>
    <li data-repeat="object objectList">
        <span data-content="object/id"></span>
        <ol>
            <li data-repeat="item object/items">
                <span data-content="item/name">an item name</span>:
                <span data-content="item/description">an item description</span>
            </li>
        </ol>
    </li>
</ol>
                

The javascript code to invoke ZPT-JS:

"use strict";

var zpt = require( 'zpt' );

var dictionary = new zpt.ReactiveDictionary({
    objectList: [ 
        {
            id: 'object1',
            items: [
                {
                    name: 'John',
                    description: 'The number 1'
                }, 
                {
                    name: 'Peter',
                    description: 'The number 2'
                },
                {
                    name: 'Luke',
                    description: 'The number 3'
                }
            ]
        },
        {
            id: 'object2',
            items: [
                {
                    name: 'Michael',
                    description: 'The number 4'
                }, 
                {
                    name: 'Chris',
                    description: 'The number 5'
                },
                {
                    name: 'Lars',
                    description: 'The number 6'
                }
            ]
        }
    ]
});

// Parse template
zpt.run({
    root: document.body,
    dictionary: dictionary
});
                

Now we want to add a new element to objectList:

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            id: 'objectList',
            action: 'createArray',
            index: '_last_',
            newElement: {
                id: 'object3',
                items: [
                    {
                        name: 'Mary',
                        description: 'The number 7'
                    }, 
                    {
                        name: 'Ann',
                        description: 'The number 8'
                    }
                ]
            }
        }
    ]
});
                

The resulting HTML looks like this:

1. object1
    John: The number 1
    Peter: The number 2
    Luke: The number 3
2. object2
    Michael: The number 4
    Chris: The number 5
    Lars: The number 6
3. object3
    Mary: The number 7
    Ann: The number 8  
                

Now we are going to insert a new item inside object3 (Selena, the number 9) to get something like this:

1. object1
    John: The number 1
    Peter: The number 2
    Luke: The number 3
2. object2
    Michael: The number 4
    Chris: The number 5
    Lars: The number 6
3. object3
    Selena: The number 9
    Mary: The number 7
    Ann: The number 8  
                

And the command to run:

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            search: [
                'objectList',
                {
                    id: 'object3'
                },
                'items'
            ],
            action: 'createArray',
            index: '_first_',
            newElement: {
                name: 'Selena',
                description: 'The number 9'
            }
        }
    ]
});
                

A search element is an array of elements that ZPT-JS combines to define a path to access the variable you want to modify. Each element can be one of these types:

In this example the path defined by the search is objectList[ id='object3' ].items.

The same search using an integer as a search item:

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            search: [
                'objectList',
                2,
                'items'
            ],
            action: 'createArray',
            index: '_first_',
            newElement: {
                name: 'Selena',
                description: 'The number 9'
            }
        }
    ]
});
                

In this example the path defined by the search is objectList[1].items.

The same search using _last_ as a search item:

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            search: [
                'objectList',
                '_last_',
                'items'
            ],
            action: 'createArray',
            index: '_first_',
            newElement: {
                name: 'Selena',
                description: 'The number 9'
            }
        }
    ]
});
                

Search elements can be used in any class of dictionaryActions, not only in createArray actions.

Updating object properties

Take a look at this template:

<div>
    <span data-content="object/name">an item name</span>:
    <span data-content="object/description">an item description</span>
</div>
                

Now we are going to update the name property (now the name is Dave):

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            search: [
                'object'
            ],
            action: 'updateObject',
            property: 'name',
            newElement: 'Dave'
        }
    ]
});
                

Deleting object properties

Using the previous template, now we are going to delete the name property:

zpt.run({
    command: 'update',
    dictionaryActions: [
        {
            search: [
                'object'
            ],
            action: 'deleteObject',
            property: 'name'
        }
    ]
});
                

The name property has been deleted from the object vaiable in the dictionary.

Using reactive dictionaries

An alternative way of working with dictionary actions is using a reactive dictionary:

"use strict";

var zpt = require( 'zpt' );

var dictionary = new zpt.ReactiveDictionary({
    items: [ 
        {
            id: 'object1',
            items: [
                {
                    name: 'John',
                    description: 'The number 1'
                }, 
                {
                    name: 'Peter',
                    description: 'The number 2'
                },
                {
                    name: 'Luke',
                    description: 'The number 3'
                }
            ]
        }
    ];
});

// Parse template
zpt.run({
    root: document.body,
    dictionary: dictionary
});
                

To run a dictionary action, you can do this:

dictionary._addActions([
    {
        id: 'items',
        action: 'createArray',
        index: '_last_',
        newElement: {
            id: 'object2',
            items: [
                {
                    name: 'Sophia',
                    description: 'The number 4'
                }, 
                {
                    name: 'Jane',
                    description: 'The number 5'
                },
                {
                    name: 'Drew',
                    description: 'The number 6'
                }
            ]
        }
    }
]);
                

Be careful, the update is done inmediately. For more details about reactive dictionaries, see reference page