Repeater - guiled/LRE GitHub Wiki

Repeaters

Introduction

Repeater management in Let's Role can be tricky and I found that the available features were not sufficient. When I tried to handle them I found a lot of edge cases that made me definitely decide to build LRE.

In LRE 7, repeaters have many more methods to handle and many custom events to help you do what you want.

Vocabulary

  • entry : this is how LRE calls a repeater line. In Let's Role it is called repeater element
  • entryId : this is the index of every component inside a repeater. It is in fact the id of the entry in the repeater.

Specific methods

provider

repeater.provider(): DataProvider

This method will return a DataProvider whose data are sync on the repeater value. As soon as the repeater has changed the returned DataProvider will be refreshed.

You can then use it with the DataProvider methods.

each

each(column: string, callback: (component: Component, data: Object, entryId: string): undefined each(callback: (entry: Object, data: Object, entryId: string) => void): undefined

repeater.each() is an easy way to run some code on each entry.

If you specify a string as first parameter, this method helps you to loop on each component that has its id equal to the string.

If the first parameter is a function, you will have access to each entry.

Both codes below are equivalent :

repeater.each("name", function (componentName, entryData, entryId) {
    log("Repeater index : " + entryId + " has the name '" + componentName.value() + "'");
});

repeater.each(function (entry, entryData, entryId) {
    const name = entry.find("name");
    log("Repeater index : " + entryId + " has the name '" + name.value() + "'");
});

map

repeater.map(callback: (data: Object, key: string)): Object

This method transforms each data of the repeater value using the given function.

// repeater data is like {1: {type: "axe", damage: "2d6"}, 2: {type: "knife", damage: "1d6"}}
const output = repeater.map(function (entryData, entryId) {
    return entryData.type + " " + entryData.damage;
});
// output is like {1: "axe 2d6", 2: "knife 1d6"} 

setSorter

repeater.setSorter(cmp: Component | Group | string, column: string): void

If you want to use a repeater like a table, and put some labels as Column title that can sort the repeater ascending or descending, you can use repeater.setSorter(). The sorting method is a simple comparison between component values.

Examples :

repeater.setSorter(sheet.get("titleItemType"), "type"); // click on the title "Type" will sort by name
repeater.setSorter("iconHouse", "chkHouse"); // click on the icon house will sort by a checkbox

readOnly

repeater.readOnly(readonly: boolean = true): void

This simple method is an easy way to remove the "Add" and "Edit" buttons in the repeater. It accepts a boolean as parameter (which can be a dynamic value, like a checkbox component).

Example :

sheet.get("repeater").readOnly(sheet.get("checkboxReadonly"));

add / remove

repeater.add(data: Object, entryId?: string): void repeater.remove(entryId: string): Object

LRE provides to easy methods to add or remove an entry by code.

Specific events

⚠️ Important recommendation ⚠️

Let's role provides no information about the newly created edit view when you click on "Add" if this "Editable View" does NOT contain at least one Choice.

In this case the events init and initwrite can not be triggered. As soon as one "Editable view" 's component value is changed, the entry is available and you might consider it is too late to initiate it.

👉🏻 I encourage you to always have at least one choice in the "Editable views" you need to initiate.

If you don't need Choice in your "Editable view", I suggest to add one anyway (with correct table and label properties), and hide it using the class d-none in the Classes component property.

entrychange

repeater.on("entrychange", function (
    repeaterComponent,
    entryComponent,
    entryId,
    newEntryData,
    oldEntryData) {

});

This event is trigger as soon as an entry have his data changed. It there are no changes this event is not triggered.

save

repeater.on("save", function (
    repeaterComponent, 
    entryComponent,
    entryId,
    newEntryData,
    oldEntryData) {

});

This event is triggered when you click on the "Done" button when finishing creating/editing an entry. oldEntryData is equal to {} (empty object) if it is a new entry.

initread

repeater.on("initread", function (
    repeaterComponent,
    entryComponent,
    entryId,
    newEntryData,
    oldEntryData) {

});

initread is triggered as soon as you add this event handler to the repeater (ie. at the sheet init), and as soon as you change the entry data, or create a new entry. oldEntryData is equal to {} (empty object) if it is a new entry or at the event creation.

This event is very useful in order to set event handlers (like click) on component in the repeater "Readable view" from the init of the sheet and even after changing things in the repeater.

It is also more optimized as it will be triggered only when the entry data is effectively changed, which can prevent some useless computations and cascading changes in the sheet.

initedit

repeater.on("initedit", function (
    repeaterComponent,
    entryComponent,
    entryId,
    entryData) {

});

This event is triggered when the "Editable view" is displayed (when you click on the "Add" button or the "Edit" button).

See here to understand that this event can be NOT triggered because of a Let's Role specificity.

init

repeater.on("init", function (
    repeaterComponent,
    entryComponent,
    entryId,
    entryData) {

});

This event is triggered the first time the "Editable view" is displayed for an entry.

See here to understand that this event can be NOT triggered because of a Let's Role specificity.

edit

repeater.on("edit", function (
    repeaterComponent,
    entryComponent,
    entryId,
    entryData) {

});

This event is triggered when you click on the "Edit" button in an entry.

delete

repeater.on("delete", function (
    repeaterComponent,
    entryId,
    oldEntryData) {

});

This event is triggered when you click on the "Delete" button in an entry.

Note that the function doesn't receive the entryComponent (as it is deleted).

new

repeater.on("new", function (
    repeaterComponent,
    entryComponent,
    entryId,
    newEntryData,
    oldEntryData) {

});

This event is triggered after you click on the "Done" button for a new entry. It is not triggered for modified entries. oldEntryData is always equal to {} (empty object).

dataChange

repeater.on("dataChange", function (repeaterComponent) {

});

This event is triggered as soon as at least one entry was modified after clicking on "Done" or "Delete" buttons (deleted entry, new entry, entry with modified data).