Orbito - Dokumentacja modułówOrbito - Dokumentacja modułów
Wprowadzenie
Pierwsze kroki
API
Komunikacja
Widoki
Wdrożenie
Społeczność
For AI agents
Wprowadzenie
Pierwsze kroki
API
Komunikacja
Widoki
Wdrożenie
Społeczność
For AI agents
  • OrbitoViewEngine

    • Wprowadzenie
    • BaseView – Klasa bazowa
    • Zmienne (VarStore)
    • Listy i notacja .$
    • Szablony Handlebars
    • Akcje (ActionHandler)
    • Tabele danych
    • Edycja danych
    • Kontrolki wartości
    • Warianty stylistyczne
    • Komponenty i sloty
    • Pliki, kamera i schemat z serwera
  • Widoki

    • AvatarView
    • BadgeView
    • ButtonView
    • CameraView
    • CardView
    • CheckboxGroupView
    • CheckboxView
    • ComponentView
    • CssBoxView
    • DataTableView
    • DropdownView
    • DynamicListView
    • DynamicView
    • FilePickerView
    • FilePreviewView
    • FlexView
    • GridView
    • HtmlView
    • InlineEditView
    • InputView
    • ListView
    • ModalView
    • PopoverView
    • RadioGroupView
    • RowView
    • SelectView
    • SliderView
    • SlotView
    • StepperView
    • TabsView
    • TextInputView
    • TextView

Listy i notacja .$

Źródło: ListView.js, DynamicListView.js, DataTableView.js, BaseView.js

Wiele widoków renderuje kolekcje danych — listę produktów, tabelę zamówień, powtarzalne karty. Zamiast definiować każdy element osobno, podajesz jeden szablon (template), a silnik powiela go dla każdego elementu kolekcji.

Najważniejsze pytanie brzmi: jak wewnątrz szablonu odwołać się do bieżącego elementu listy? Służy do tego notacja .$ — i to jej poświęcona jest ta sekcja.

W skrócie

type: listvar
varPath: ordersTable          # skąd brać dane
template:                     # szablon powielany dla każdego elementu
  type: text
  content: "{{ ordersTable.$._id }}"   # $ = indeks bieżącego elementu

Symbol $ w wyrażeniu ordersTable.$._id jest podczas renderowania zamieniany na indeks aktualnie renderowanego elementu. Dla pierwszego elementu listy silnik podstawi ordersTable.0._id, dla drugiego ordersTable.1._id itd.


Widoki listowe

W silniku dostępne są trzy widoki, które działają w oparciu o szablon powielany dla każdego elementu kolekcji:

TypWidokSkąd pobiera dane
listvarListViewzmienna z VarStore (varPath) — strony, globalna lub dane innego widoku
listDynamicListViewmetoda API modułu
datatableDataTableViewmetoda API (z paginacją, sortowaniem, wyszukiwaniem) — szablon definiujesz w columns[].content

Każdy z nich przyjmuje szablon pojedynczego elementu. To właśnie wewnątrz tego szablonu używasz notacji .$.


Jak działa .$

Gdy widok listowy renderuje element o indeksie n, oznacza go wewnętrznie metadanymi $index = n. Podczas parsowania szablonu (Handlebars) silnik znajduje każde wystąpienie .$ i podmienia je na ten indeks:

{{ ordersTable.$.name }}     →   {{ ordersTable.2.name }}      (dla 3. elementu)
{{ ordersTable.$._id }}      →   {{ ordersTable.2._id }}
{{ ordersTable.$.customer.name }}  →  {{ ordersTable.2.customer.name }}

Dzięki temu ordersTable.$ zawsze wskazuje na bieżący element kolekcji ordersTable, a kropki za nim odczytują dowolnie zagnieżdżone pola tego elementu.

Dlaczego viewId.$, a nie samo pole? Notacja celowo zawiera ID widoku źródłowego (ordersTable). Dzięki temu w szablonie możesz odwołać się zarówno do bieżącego elementu (ordersTable.$), jak i do zmiennych strony ($page.<klucz>), globalnych ($global.<klucz>) czy danych innych widoków — wszystko w jednym wyrażeniu.

Samo $ → goły indeks

Jeśli użyjesz {{ $ }} (samego dolara, bez ścieżki), zostanie on zamieniony na liczbę — sam indeks bieżącego elementu. Przydaje się to do budowania dynamicznych identyfikatorów, np. przy przeładowaniu konkretnego elementu listy:

onClick:
  - action: reload
    target: productsCellList.{{ $ }}   # np. productsCellList.2

Listy zagnieżdżone — rozwiązywanie od prawej do lewej

Gdy listy są zagnieżdżone (lista w liście), w jednym wyrażeniu może pojawić się kilka $. Silnik rozwiązuje je od prawej do lewej: najpierw bierze indeks najbliższego elementu (bieżący widok), potem wspina się po rodzicach drzewa widoków, szukając kolejnego indeksu.

{{ companies.$.emails.$ }}
              │          └─ indeks bieżącego elementu (np. lista e-maili)
              └──────────── indeks elementu z listy nadrzędnej (firma)

Jeśli silnik nie znajdzie już indeksu wyżej w hierarchii, pozostawia $ bez zmian (kolejne .$ nie są rozwijane).


Notacja .$ poza treścią

.$ działa wszędzie tam, gdzie silnik parsuje szablon — nie tylko w polu content. Możesz jej używać m.in. w warunkach renderIf oraz w wartościach akcji (np. setVar), co pozwala budować w pełni reaktywne, zależne od wiersza zachowania.

W renderIf $ jest rozwijane nie tylko w wartości warunku, ale również w jego kluczu (ścieżce sprawdzanego pola). Dzięki temu warunek może odczytać dane dokładnie tego elementu listy, który jest aktualnie renderowany:

type: html
renderIf:
  ordersTable.$.products:     # ← $ w kluczu = indeks bieżącego wiersza
    $size:
      $gt: 3
content: <span class="products-toggle">▾ wyświetl pozostałe</span>

Warunkowe renderowanie zależne od bieżącego wiersza ($ w wartości):

type: html
renderIf:
  $page.expandedOrder: '{{ ordersTable.$._id }}'   # pokaż tylko dla rozwiniętego zamówienia
content: <span class="products-toggle">▴ zwiń</span>

Zapis ID bieżącego elementu do zmiennej strony:

type: text
content: Szczegóły
onClick:
  - action: setPageVar
    key: currentOrder
    value: '{{ ordersTable.$._id }}'

Pełny przykład: lista produktów wewnątrz tabeli zamówień

Poniższy fragment (z realnego widoku) pokazuje listę listvar osadzoną w komórce tabeli. Zewnętrzny widok (ordersTable) dostarcza zamówienie, a wewnętrzna lista iteruje po jego produktach — stąd dwa różne ID w notacji .$:

type: datatable
id: ordersTable
columns:
  - header: Produkty
    content:
      - type: listvar
        id: productsCellList.$
        varPath: ordersTable.$.products      # produkty bieżącego zamówienia
        emptyMessage: Brak produktów
        template:
          type: html
          content: |-
            <div>
              <span>{{ productsCellList.$.qty }}×</span>
              <span>{{ ordersTable.$.products.$.name }}</span>
            </div>

Tu ordersTable.$ to bieżący wiersz tabeli, a productsCellList.$ to bieżąca pozycja wewnątrz tej listy produktów. Wyrażenie ordersTable.$.products.$.name korzysta z rozwiązywania od prawej do lewej: prawe $ to indeks produktu, lewe — indeks zamówienia.


Edytowalna lista pozycji

Kolekcję trzymaną w zmiennej można edytować w miejscu — bez zapisu do API po każdej zmianie. Wiersz opisuje kontrolki, a akcje arrayPush / arrayRemove / arraySet zapisują stan pod indeksem bieżącego wiersza ({{ $ }}):

type: flex
onLoad:
  action: setVar
  scope: view
  key: docItems
  value:
    - { name: 'Usługa', qty: 1, price: 100 }
childs:
  - type: listvar
    id: docItemsList
    varPath: docItems
    template:
      type: flex
      childs:
        - type: input
          id: docQty.$            # id z `.$` — inaczej wiersze dzielą jeden klucz
          inputType: number
          value: '{{ docItems.$.qty }}'
          debounce: 200
          onChange:
            action: arraySet       # zapis cichy: lista się nie przebudowuje
            scope: view
            key: docItems
            index: '{{ $ }}'
            field: qty
            valueFrom: $value
        - type: text
          content: '{{ money (mul docItems.$.qty docItems.$.price) }}'   # przeliczy się samo
        - type: button
          label: Usuń
          onClick:
            action: arrayRemove
            scope: view
            key: docItems
            index: '{{ $ }}'
  - type: button
    label: Dodaj pozycję
    onClick:
      action: arrayPush
      scope: view
      key: docItems
      value: { name: '', qty: 1, price: 0 }
  - type: text
    content: 'Razem: {{ money (sum docItems "price") }}'

Reguły, o których łatwo zapomnieć:

  • id kontrolki w wierszu musi mieć .$ — bez tego wszystkie wiersze zapisują wartość pod tym samym kluczem.
  • Kilka odwołań .$ w jednym wyrażeniu ({{ mul docItems.$.qty docItems.$.price }}) dotyczy tego samego wiersza. Zapis od prawej do lewej opisuje zagnieżdżenie tylko w obrębie jednej ścieżki (orders.$.products.$.name).
  • Nie używaj renderIf ani variantIf zależnych od edytowanej kolekcji w wierszu — przebudowują zawartość i zabierają fokus inputowi. Do wyglądu wiersza użyj classIf.

Powiązane: Zmienne (VarStore) · Szablony Handlebars · ListView · DataTableView

Ostatnio zaktualizowano:: 16.09.2026, 10:04
Contributors: Wiktor Koźmiński, Claude Fable 5.1
Prev
Zmienne (VarStore)
Next
Szablony Handlebars