MontageJS Cookbook

A collection of useful recipes for MontageJS app development

Recipes

Display text from a property

HTML
<div data-montage-id="content" class="Content">
    <p data-montage-id="text"></p>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},

"textLabel": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "text" }
    },
    "bindings": {
        "value": { "<-": "@owner.myProperty" }
    }
}
JavaScript
exports.Content = Component.specialize({
    myProperty: { value: "This is a text property" }
});

Respond to a button press

HTML
<div data-montage-id="content" class="Content">
    <button data-montage-id="button">Push Me</button>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"myButton": {
    "prototype": "digit/ui/button.reel",
    "properties": {
        "element": { "#": "button" }
    },
    "listeners": [{
        "type": "action",
        "listener": { "@": "owner" }
    }]
}
JavaScript
exports.Content = Component.specialize({
    handleMyButtonAction: {
        value: function() { console.log("You pushed the button!"); }
    }
});
HTML
<div data-montage-id="content" class="Content">
    <a data-montage-id="link"></a>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"link": {
    "prototype": "matte/ui/anchor.reel",
    "properties": {
        "element": { "#": "link" },
        "textContent": "Click Me",
        "href": "http://montagejs.org"
    }
}

Use a converter to transform a bound value

HTML
<div data-montage-id="content" class="Content">
    <p data-montage-id="time"></p>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"converter": {
    "prototype": "montage/core/converter/date-converter",
    "properties": {
        "pattern": "ddd MMM dd hh:mm tt"
    }
},
"time": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "time" }
    },
    "bindings": {
        "value": {
            "<-": "@owner.currentDate",
            "converter": { "@": "converter" }
        }
    }
}
JavaScript
var Component = require("montage/ui/component").Component;

exports.Content = Component.specialize({
    currentDate: {
        get: function() { return new Date(); }
    }
});

Toggle an element’s CSS class

HTML
<div data-montage-id="content" class="Content">
    <div data-montage-id="checkbox"></div>
    <p data-montage-id="text"></p>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"checkbox": {
    "prototype": "digit/ui/checkbox.reel",
    "properties": {
        "element": { "#": "checkbox" }
    }
},
"textLabel": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "text" },
        "value": "This is a test"
    },
    "bindings": {
        "classList.has('selected')": {
            "<-": "@checkbox.checked"
        }
    }
}
CSS
.selected { background-color: red; }

Arbitrary HTML with Dynamic Element

HTML
<div data-montage-id="content" class="Content">
    <div data-montage-id="dynamic-html" class="div"></div>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"htmlContent": {
    "prototype": "matte/ui/dynamic-element.reel",
    "properties": {
        "element": { "#": "dynamic-html" },
        "allowedTagNames": [ "p", "a" ],
        "innerHTML": "<p>Test <a href='#'>Test 2</a></p>"
    }
}

Substitution

HTML
<div data-montage-id="content" class="Content">
    <span data-montage-id="checkbox"></span>
    <div data-montage-id="sub">
        <div data-arg="item1">
            <p>The box is checked!</p>
        </div>
        <div data-arg="item2">
            <p>The box is unchecked!</p>
        </div>
    </div>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"checkbox": {
    "prototype": "digit/ui/checkbox.reel",
    "properties": {
        "element": { "#": "checkbox" }
    }
},
"sub": {
    "prototype": "montage/ui/substitution.reel",
    "properties": {
        "element": { "#": "sub" }
    },
    "bindings": {
        "switchValue": { "<-": "@checkbox.checked ? 'item1' : 'item2'" }
    }
}

Repetition

HTML
<div data-montage-id="content" class="Content">
    <ul data-montage-id="items">
        <li data-montage-id="item"></li>
    </ul>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"items": {
    "prototype": "montage/ui/repetition.reel",
    "properties": {
        "element": { "#": "items" }
    },
    "bindings": {
        "content": { "<-": "@owner.myListProperty" }
    }
},
"item": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "item" }
    },
    "bindings": {
        "value": { "<-": "@items.objectAtCurrentIteration" }
    }
}
JavaScript
var Component = require("montage/ui/component").Component;

exports.Content = Component.specialize({
    myListProperty: {
        value: ["Item 1", "Item 2", "Item 3"]
    }
});

Add elements to a repetition

HTML
<div data-montage-id="content" class="Content">
    <ul data-montage-id="items">
        <li data-montage-id="item"></li>
    </ul>
    <button data-montage-id="button">Add Item</button>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"items": {
    "prototype": "montage/ui/repetition.reel",
    "properties": {
        "element": { "#": "items" }
    },
    "bindings": {
        "content": { "<-": "@owner.myListProperty" }
    }
},
"item": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "item" }
    },
    "bindings": {
        "value": { "<-": "@items.objectAtCurrentIteration" }
    }
},
"myButton": {
    "prototype": "digit/ui/button.reel",
    "properties": {
        "element": { "#": "button" }
    },
    "listeners": [{
        "type": "action",
        "listener": { "@": "owner" }
    }]
}
JavaScript
var Component = require("montage/ui/component").Component;

exports.Content = Component.specialize({
    handleMyButtonAction: {
        value: function() {
            this.myListProperty.push("New Item");
        }
    },
    myListProperty: {
        value: ["Item 1", "Item 2", "Item 3"]
    }
});

Sort and filter repetition contents

HTML
<div data-montage-id="content" class="Content">
    <ul data-montage-id="items">
        <li data-montage-id="item"></li>
    </ul>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"items": {
    "prototype": "montage/ui/repetition.reel",
    "properties": {
        "element": { "#": "items" }
    },
    "bindings": {
        "content": { "<-": "@owner.myListProperty.filter{shown}.sorted{order}" }
    }
},
"item": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "item" }
    },
    "bindings": {
        "value": { "<-": "@items.objectAtCurrentIteration.name" }
    }
}
JavaScript
exports.Content = Component.specialize({
    myListProperty: {
        value: [
            { name: "Item 1", shown: false, order: 3 },
            { name: "Item 2", shown: true, order: 4 },
            { name: "Item 3", shown: false, order: 2 },
            { name: "Item 4", shown: true, order: 1 },
            { name: "Item 5", shown: true, order: 0 }
        ]
    }
});

Allow user to select repetition item

HTML
<div data-montage-id="content" class="Content">
    <ul data-montage-id="items">
        <li data-montage-id="item"></li>
    </ul>
    <h1 data-montage-id="selected"></h1>
</div>
CSS
.selected { background-color: red; }
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"items": {
    "prototype": "montage/ui/repetition.reel",
    "properties": {
        "element": { "#": "items" },
        "isSelectionEnabled": true
    },
    "bindings": {
        "content": { "<-": "@owner.myListProperty" }
    }
},
"item": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "item" }
    },
    "bindings": {
        "value": { "<-": "@items.objectAtCurrentIteration" }
    }
},
"selected": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "selected" }
    },
    "bindings": {
        "value": { "<-": "@items.selection.0" }
    }
}
JavaScript
exports.Content = Component.specialize({
    myListProperty: {
        value: ["Item 1", "Item 2", "Item 3"]
    }
});

Trigger a function when repetition selection changes

HTML
<div data-montage-id="content" class="Content">
    <ul data-montage-id="items">
        <li data-montage-id="item"></li>
    </ul>
    <h1 data-montage-id="selected"></h1>
</div>
CSS
.selected { background-color: red; }
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    },
    "bindings": {
        "currentSelection": { "<-": "@items.selection.0" }
    }
},
"items": {
    "prototype": "montage/ui/repetition.reel",
    "properties": {
        "element": { "#": "items" },
        "isSelectionEnabled": true
    },
    "bindings": {
        "content": { "<-": "@owner.myListProperty" }
    }
},
"item": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "item" }
    },
    "bindings": {
        "value": { "<-": "@items.objectAtCurrentIteration" }
    }
},
"selected": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "selected" }
    },
    "bindings": {
        "value": { "<-": "@items.selection.0" }
    }
}
JavaScript
exports.Content = Component.specialize({
    currentSelection: {
        set: function(value) {
            console.log("Selection changed to: " + value);
        }
    },
    myListProperty: {
        value: ["Item 1", "Item 2", "Item 3"]
    }
});

Use a repetition and substitution to implement tab navigation

HTML
<div data-montage-id="content" class="Content">
    <div data-montage-id="rep" class="tabs">
        <div data-montage-id="rep-item" class="tab"></div>
    </div>
    <div data-montage-id="sub">
        <div data-arg="item1">
            <p>Contents of item 1 would go here</p>
        </div>
        <div data-arg="item2">
            <p>Contents of item 2 would go here</p>
        </div>
        <div data-arg="item3">
            <p>Contents of item 3 would go here</p>
        </div>
    </div>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"rep": {
    "prototype": "montage/ui/repetition.reel",
    "properties": {
        "element": { "#": "rep" },
        "isSelectionEnabled": true,
        "content": [
            { "name": "First Item", "value": "item1" },
            { "name": "Second Item", "value": "item2" },
            { "name": "Third Item", "value": "item3" }
        ]
    }
},
"repItem": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "rep-item" }
    },
    "bindings": {
        "value": { "<-": "@rep.objectAtCurrentIteration.name" }
    }
},
"sub": {
    "prototype": "montage/ui/substitution.reel",
    "properties": {
        "element": { "#": "sub" }
    },
    "bindings": {
        "switchValue": { "<-": "@rep.selection.0.value" }
    }
}
CSS
.tab {
    display: inline-block;
    background-color: #808080;
    border: 1px solid #000;
    padding: 10px;
}
.selected {
    background-color: #fff;
    border-bottom: 0;
}

Tree controller

HTML
<div data-montage-id="content" class="Content">
    <div data-montage-id="rep" class="tree">
        <p data-montage-id="rep-item" class="item"></p>
    </div>
</div>
Serialization
"owner": {
    "properties": {
        "element": { "#": "content" }
    }
},
"tree": {
    "prototype": "montage/core/tree-controller",
    "properties": {
        "initiallyExpanded": true,
        "content": {
            "name": "Root",
            "children": [
                { "name": "Parent 1", "children": [{ "name": "Child 1" }] },
                { "name": "Parent 2", "children": [{ "name": "Child 2" }] },
                { "name": "Parent 3", "children": [{ "name": "Child 3" }] }
            ]
        }
    }
},
"rep": {
    "prototype": "montage/ui/repetition.reel",
    "properties": {
        "element": { "#": "rep" },
        "isSelectionEnabled": true
    },
    "bindings": {
        "content": { "<-": "@tree.iterations" }
    }
},
"repItem": {
    "prototype": "montage/ui/text.reel",
    "properties": {
        "element": { "#": "rep-item" }
    },
    "bindings": {
        "value": { "<-": "@rep.objectAtCurrentIteration.content.name" },
        "classList.has('group-header')": {
            "<-": "@rep.objectAtCurrentIteration.depth == 1"
        }
    }
}
CSS
.group-header {
    font-weight: bold;
    color: red;
}