Using the Repetition Component
The Repetition component is used to produce a repeating group of elements based on an array of values. All elements nested inside of the Repetition element will repeat in each iteration. The content inside of a repetition is managed by a controller. You can set the Repetition component’s content property manually with a standard array for a simple repetition. You can also expand the component’s capabilities by assigning a RangeController component to its contentController property.
You can use the Repetition component as a building block to repeat any number of user interface components. (The Mod List component, for example, uses the Repetition component to support selection management.) All elements nested inside of the Repetition element will repeat in each iteration of the repetition. You can use the bindable iteration.object property to point to the current list item.
A Simple Repetition
The following example shows a simple Repetition (items) that produces three text items. Each iteration is associated with a corresponding item in a source collection, which is populated through the Repetition component’s content property.
<div data-mod-id="content" class="Content">
<ul data-mod-id="items">
<li data-mod-id="item"></li>
</ul>
</div>
"owner": {
"values": {
"element": { "#": "content" }
}
},
"items": {
"prototype": "mod/ui/repetition.mod",
"values": {
"element": { "#": "items" },
"content": { "<-": "@owner.myListProperty" }
}
},
"item": {
"prototype": "mod/ui/text.mod",
"values": {
"element": { "#": "item" },
"value": { "<-": "@items:iteration.object.quote" },
"classList.has('highlight')": { "<-": "@items:iteration.object.important" }
}
}
.highlight {
font-weight: bold;
}
var Component = require("mod/ui/component").Component;
exports.Content = Component.specialize({
myListProperty: {
value: [{
"quote": "If music be the food of love, play on.",
"important": false
}, {
"quote": "O Romeo, Romeo! wherefore art thou Romeo?",
"important": true
}, {
"quote": "All that glitters is not gold.",
"important": false
}, {
"quote": "I am amazed and know not what to say.",
"important": false
}]
}
});
Preview:
View in Mfiddle: http://montagejs.github.io/mfiddle/#!/7882151
Using a RangeController with a Repetition
In this example:
- The Repetition component’s
contentControllerproperty is set to be aRangeControllerfor managing some content. - The
Textcomponent is a child of the Repetition and derives itsvalueproperty from itsiteration.objectproperty. - Clicking the Change Content button replaces the managed content with new random content.
<div data-mod-id="component">
<button data-mod-id="button"></button>
<ul data-mod-id="repetition">
<li data-mod-id="value"></li>
</ul>
</div>
"owner": {
"values": {
"element": {"#": "component"}
}
},
"repetition": {
"prototype": "mod/ui/repetition.mod",
"values": {
"element": {"#": "repetition"},
"contentController": {"@": "rangeController"}
}
},
"rangeController": {
"prototype": "mod/core/range-controller"
},
"value": {
"prototype": "mod/ui/text.mod",
"values": {
"element": {"#": "value"},
"value": {"<-": "@repetition:iteration.object.quote"}
}
},
"changeButton": {
"prototype": "digit/ui/button.mod",
"values": {
"element": {"#": "button"},
"label": "Change Content"
},
"listeners": [
{
"type": "action",
"listener": {"@": "owner"}
}
]
}
var Component = require("mod/ui/component").Component;
exports.Owner = Component.specialize({
constructor: {
value: function Owner() {
this.content = [{
"quote": "If music be the food of love, play on.",
"important": false
}, {
"quote": "O Romeo, Romeo! wherefore art thou Romeo?",
"important": true
}, {
"quote": "All that glitters is not gold.",
"important": false
}, {
"quote": "I am amazed and know not what to say.",
"important": false
}];
}
},
templateDidLoad: {
value: function () {
this.templateObjects.rangeController.content = this.content;
}
},
handleChangeButtonAction: {
value: function (evt) {
var randomContentIndex = Math.floor(Math.random() * this.content.length);
this.templateObjects.rangeController.add(this.content[randomContentIndex]);
}
}
});
Preview:
View in Mfiddle: http://montagejs.github.io/mfiddle/#!/7883458
Sorting and Filtering the Items in a Repetition
To sort and filter items in a repetition you can use use FRB expressions on the RangeController.
- Adding or removing items from the source collection automatically updates the returned items.
- When the value of the
filterPathisfalse, the item will not be included in the repetition. - Using
sortPathreturns the items in sequential order, sorted by the value of thepropertywhen the path is a single property.
You can also use complex expressions inside of sort and filter operations. For example, when the repetition’s content has an index property that is a sequence of integers, you can filter out the odd numbers like this: !(index%2).
<div data-mod-id="component">
<button data-mod-id="filterButton"></button>
<button data-mod-id="sortButton"></button>
<ul data-mod-id="repetition">
<li data-mod-id="quote"></li>
</ul>
</div>
"owner": {
"values": {
"element": {"#": "component"}
}
},
"repetition": {
"prototype": "mod/ui/repetition.mod",
"values": {
"element": {"#": "repetition"},
"contentController": {"@": "rangeController"}
}
},
"rangeController": {
"prototype": "mod/core/range-controller"
},
"quote": {
"prototype": "mod/ui/text.mod",
"values": {
"element": {"#": "quote"},
"value": {"<-": "@repetition:iteration.object.quote"}
}
},
"filterButton": {
"prototype": "digit/ui/button.mod",
"values": {
"element": {"#": "filterButton"},
"label": "Filter"
},
"listeners": [
{
"type": "action",
"listener": {"@": "owner"}
}
]
},
"sortButton": {
"prototype": "digit/ui/button.mod",
"values": {
"element": {"#": "sortButton"},
"label": "Sort"
},
"listeners": [
{
"type": "action",
"listener": {"@": "owner"}
}
]
}
var Component = require("mod/ui/component").Component;
exports.Owner = Component.specialize({
constructor: {
value: function Owner() {
this.content = [{
"quote": "If music be the food of love, play on.",
"important": false
}, {
"quote": "O Romeo, Romeo! wherefore art thou Romeo?",
"important": true
}, {
"quote": "All that glitters is not gold.",
"important": false
}, {
"quote": "I am amazed and know not what to say.",
"important": false
}];
}
},
templateDidLoad: {
value: function () {
this.templateObjects.rangeController.content = this.content;
}
},
handleFilterButtonAction: {
value: function () {
var rangeController = this.templateObjects.rangeController;
rangeController.filterPath = rangeController.filterPath ? "" : "important";
}
},
handleSortButtonAction: {
value: function () {
var rangeController = this.templateObjects.rangeController;
rangeController.sortPath = rangeController.sortPath ? "" : "quote" ;
}
}
});
Preview:
View in Mfiddle: http://montagejs.github.io/mfiddle/#!/7884201
Allowing Users to Select Repetition Items
To allow users to select an item in a repetition:
- Set the Repetition component’s
isSelectionEnabledproperty totrue. - The
selectedCSS rule is automatically applied to the selected item.
Note that users could select multiple items.
<div data-mod-id="component">
<div data-mod-id="repetition">
<p data-mod-id="value"></p>
</div>
<select data-mod-id="select"></select>
<p data-mod-id="log"></p>
</div>
"owner": {
"values": {
"element": {"#": "component"}
}
},
"repetition": {
"prototype": "mod/ui/repetition.mod",
"values": {
"element": {"#": "repetition"},
"isSelectionEnabled": true,
"contentController": {"@": "rangeController"}
}
},
"rangeController": {
"prototype": "mod/core/range-controller",
"values": {
"selection": []
}
},
"value": {
"prototype": "mod/ui/text.mod",
"values": {
"element": {"#": "value"},
"value": {"<-": "@repetition:iteration.object.quote"}
}
},
"select": {
"prototype": "digit/ui/select.mod",
"values": {
"element": {"#": "select"},
"contentController": {"@": "rangeController"},
"labelPropertyName": "quote"
}
},
"log": {
"prototype": "mod/ui/text.mod",
"values": {
"element": {"#": "log"},
"value": {"<-": "@owner.message"}
}
}
.selected {
color:red;
}
var Component = require("mod/ui/component").Component;
exports.Owner = Component.specialize({
constructor: {
value: function Owner() {
this.content = [{
"quote": "If music be the food of love, play on.",
"important": false
}, {
"quote": "O Romeo, Romeo! wherefore art thou Romeo?",
"important": true
}, {
"quote": "All that glitters is not gold.",
"important": false
}, {
"quote": "I am amazed and know not what to say.",
"important": false
}];
}
},
templateDidLoad: {
value: function () {
this.templateObjects.rangeController.content = this.content;
//Observe the selection for changes
this.templateObjects.rangeController.addRangeAtPathChangeListener(
"selection", this, "handleSelectionChange");
}
},
handleSelectionChange: {
value: function (plus, minus) {
this.message = "Selection changed from: "
+ (minus[0] ? minus[0].quote : "nothing")
+ " -> "
+ (plus[0] ? plus[0].quote : "nothing");
}
}
});
Preview:
View in Mfiddle: http://montagejs.github.io/mfiddle/#!/7884716