1. Készítsen egy hello world nézetet

Az első lépés egy JavaScript megvalósítás létrehozása egy egyszerű komponenssel.

  1. Hozza létre a gallery_view.js, gallery_controller.js és gallery_controller.xml fájlokat a static/src könyvtárban.

  2. Valósítson meg egy egyszerű hello world komponenst a gallery_controller.js fájlban.

  3. A gallery_view.js fájlban importálja a vezérlőt, hozzon létre egy nézet objektumot, és regisztrálja azt a nézet regisztrációs táblában gallery néven.

    Example

    Íme egy példa arra, hogyan definiáljunk egy nézet objektumot:

    import { registry } from "@web/core/registry";
    import { MyController } from "./my_controller";
    
    export const myView = {
          type: "my_view",
          display_name: "MyView",
          icon: "oi oi-view-list",
          multiRecord: true,
          Controller: MyController,
    };
    
    registry.category("views").add("my_controller", myView);
    
  4. Adja hozzá a gallery-t a nézettípusok közé a contacts.action_contacts műveletben.

  5. Győződjön meg róla, hogy látható a hello world komponens, amikor átvált a galéria nézetre.

../../../_images/view_button.png ../../../_images/new_view.png

2. Használja a Layout komponenst

Eddig a galéria nézetünk nem hasonlít egy szabványos nézetre. Használjuk a Layout komponenst, hogy a szabványos funkciók elérhetők legyenek, mint más nézeteknél.

  1. Importálja a Layout komponenst, és adja hozzá a GalleryController components részéhez.

  2. Frissítse a sablont a Layout használatára. Szüksége van egy display tulajdonságra, amely megtalálható a props.display-ben.

../../../_images/layout.png

3. Az arch elemzése

Jelenleg a galéria nézetünk nem sokat csinál. Kezdjük azzal, hogy elolvassuk a nézet arch-jában található információkat.

Az arch elemzésének folyamata általában egy ArchParser-rel történik, amely minden nézethez specifikus. Egy általános XMLParser osztályból öröklődik.

Example

Íme egy példa arra, hogyan nézhet ki egy ArchParser:

export class MyCustomArchParser {
    parse(xmlDoc) {
       const myAttribute = xmlDoc.getAttribute("my_attribute")
       return {
           myAttribute,
       }
    }
}
  1. Hozza létre az ArchParser osztályt saját fájljában.

  2. Használja az image_field információk olvasására.

  3. Frissítse a gallery nézet kódját, hogy hozzáadja azt a vezérlő által fogadott tulajdonságokhoz.

Megjegyzés

Valószínűleg kissé túlzás így csinálni, mivel alapvetően csak egy attribútumot kell kiolvasnunk az arch-ból, de ez egy olyan tervezés, amelyet minden más odoo nézet is használ, mivel lehetővé teszi, hogy néhány előfeldolgozást kivonjunk a vezérlőből.

4. Töltsünk be néhány adatot

Most szerezzünk valós adatokat a szerverről. Ehhez az orm szolgáltatás webSearchRead függvényét kell használnunk.

Example

Itt van egy példa egy webSearchRead hívásra, amely egy modell rekordjait kéri le:

const { length, records } = this.orm.webSearchRead(this.resModel, domain, {
   specification: {
        [this.fieldToFetch]: {},
        [this.secondFieldToFetch]: {},
    },
    context: {
        bin_size: true,
    }
})
  1. Adjon hozzá egy loadImages(domain) {...} metódust a GalleryController-hez. Ennek végre kell hajtania egy webSearchRead hívást az orm szolgáltatásból, hogy lekérje a domainhez tartozó rekordokat, és használja a props-ban kapott imageField mezőt.

  2. Ha nem tartalmazza a bin_size-t a hívás kontextusában, akkor az image mezőt base64 kódolásban kapja meg. Ügyeljen arra, hogy a bin_size-t a kontextusba helyezze, hogy megkapja az image mező méretét. Az képet később fogjuk megjeleníteni.

  3. Módosítsa a setup kódot, hogy hívja meg ezt a metódust az onWillStart és onWillUpdateProps horgokban.

  4. Módosítsa a sablont, hogy megjelenítse az egyes képek azonosítóját és méretét a Layout komponens alapértelmezett slotjában.

Megjegyzés

A betöltési adatkódot a következő gyakorlatban egy megfelelő modellbe fogjuk áthelyezni.

../../../_images/gallery_data.png

5. Oldja meg a párhuzamossági problémát

Jelenleg a kódunk nem védett a párhuzamosság ellen. Ha valaki kétszer változtatja meg a domaint, akkor kétszer fogja meghívni a loadImages(domain) függvényt. Így két kérésünk van, amelyek különböző időpontokban érkezhetnek meg, különböző tényezőktől függően. Ha az első kérés válaszát a második kérés válasza után kapjuk meg, az inkonzisztens állapothoz vezet.

Az Odoo KeepLast primitívje megoldja ezt a problémát, kezeli a feladatok listáját, és csak az utolsó feladatot tartja aktívan.

  1. Importálja a KeepLast-t a @web/core/utils/concurrency fájlból.

  2. Példányosítson egy KeepLast objektumot a modellben.

  3. Adja hozzá a webSearchRead hívást a KeepLast-hoz, hogy csak az utolsó hívás legyen megoldva.

6. Kód átszervezése

A valós nézetek egy kicsit szervezettebbek. Lehet, hogy ez túlzás ebben a példában, de az a cél, hogy megtanuljuk, hogyan kell struktúrálni a kódot az Odoo-ban. Emellett ez jobban fog méreteződni a változó követelményekkel.

  1. Mozgassa az összes modellkódot a saját GalleryModel osztályába.

  2. Mozgassa az összes renderelési kódot egy GalleryRenderer komponensbe.

  3. Importálja a GalleryModel-t és a GalleryRenderer-t a GalleryController-be, hogy működjön.

7. Tegye a nézetet kiterjeszthetővé

A nézet kiterjesztéséhez importálhatja a galéria nézet objektumot, hogy saját ízlésére módosítsa azt. A probléma az, hogy jelenleg nem lehet egyedi modellt vagy renderelőt definiálni, mert ezek a vezérlőben vannak kódolva.

  1. Importálja a GalleryModel és GalleryRenderer elemeket a galéria nézet fájlba.

  2. Adjon hozzá egy Model és Renderer kulcsot a galéria nézet objektumhoz, és rendelje hozzá őket a GalleryModel és GalleryRenderer elemekhez. Adja át a Model és Renderer elemeket tulajdonságként a vezérlőnek.

  3. Távolítsa el a vezérlőben kódolt importálást, és szerezze be őket a tulajdonságokból.

  4. Használja a t-component elemet dinamikus alkomponensekhez.

Megjegyzés

Így lehet most kiterjeszteni a galéria nézetet a renderelő módosításával:

import { registry } from '@web/core/registry';
import { galleryView } from '@awesome_gallery/gallery_view';
import { GalleryRenderer } from '@awesome_gallery/gallery_renderer';

export class MyExtendedGalleryRenderer extends GalleryRenderer {
   static template = "my_module.MyExtendedGalleryRenderer";
   setup() {
      super.setup();
      console.log("my gallery renderer extension");
   }
}

registry.category("views").add("my_gallery", {
   ...galleryView,
   Renderer: MyExtendedGalleryRenderer,
});

8. Képek megjelenítése

Frissítse a renderelőt, hogy a képeket szép módon jelenítse meg, ha a mező be van állítva. Ha az image_field üres, akkor egy üres dobozt jelenítsen meg helyette.

Javaslat

Van egy vezérlő, amely lehetővé teszi, hogy képet kérjen le egy rekordból. Használhatja ezt a kódrészletet a link felépítéséhez:

import { url } from "@web/core/utils/urls";
const url = url("/web/image", {
   model: resModel,
   id: image_id,
   field: imageField,
});
../../../_images/tshirt_images.png

9. Váltás űrlap nézetre kattintáskor

Frissítse a renderelőt, hogy reagáljon egy képre kattintásra, és váltson űrlap nézetre. Használhatja az action service switchView függvényét.

10. Opcionális tooltip hozzáadása

Hasznos, ha van némi kiegészítő információ az egér fölé húzásakor.

  1. Frissítse a kódot, hogy lehetővé tegye egy opcionális kiegészítő attribútum hozzáadását az arch-hoz:

    <gallery image_field="some_field" tooltip_field="some_other_field"/>
    
  2. Egér fölé húzásakor jelenítse meg a tooltip mező tartalmát. Működnie kell, ha a mező karakter mező, szám mező vagy many2one mező. Ha egy HTML elemhez szeretne tooltipet hozzáadni, az elemen belül a data-tooltip attribútumba helyezheti a szöveget.

  3. Frissítse az ügyfél galéria nézet arch-ját, hogy az ügyfél legyen a tooltip mező.

../../../_images/image_tooltip.png

11. Lapozás hozzáadása

Adjunk hozzá egy lapozót a vezérlőpanelhez, és kezeljük az összes lapozást, mint egy normál Odoo nézetben.

../../../_images/pagination.png

12. Nézetek érvényesítése

Eddig egy szép és hasznos nézetünk van. De a valóságban előfordulhat, hogy a felhasználók helytelenül kódolják a Galéria nézetük arch-ját: jelenleg csak egy strukturálatlan XML darab.

Adjunk hozzá némi érvényesítést! Az Odoo-ban az XML dokumentumok leírhatók egy RN fájllal (Relax NG fájl), majd érvényesíthetők.

  1. Adjunk hozzá egy RNG fájlt, amely leírja a jelenlegi nyelvtant:

    • Egy kötelező attribútum: image_field.

    • Egy opcionális attribútum: tooltip_field.

  2. Adjunk hozzá némi kódot annak biztosítására, hogy minden nézetet érvényesítsenek ezzel az RNG fájllal.

  3. Miközben ezzel foglalkozunk, győződjünk meg arról, hogy az image_field és a tooltip_field a jelenlegi modell mezői.

Mivel egy RNG fájl érvényesítése nem triviális, itt van egy kódrészlet, amely segíthet:

# -*- coding: utf-8 -*-
import logging
import os

from lxml import etree

from odoo.loglevels import ustr
from odoo.tools import misc, view_validation

_logger = logging.getLogger(__name__)

_viewname_validator = None

@view_validation.validate('viewname')
def schema_viewname(arch, **kwargs):
      """ Check the gallery view against its schema

      :type arch: etree._Element
      """
      global _viewname_validator

      if _viewname_validator is None:
         with misc.file_open(os.path.join('modulename', 'rng', 'viewname.rng')) as f:
            _viewname_validator = etree.RelaxNG(etree.parse(f))

      if _viewname_validator.validate(arch):
         return True

      for error in _viewname_validator.error_log:
         _logger.error(ustr(error))
      return False

13. Kép feltöltése

A galéria nézetünk nem teszi lehetővé a felhasználók számára a képek feltöltését. Valósítsuk meg ezt.

  1. Adjon hozzá egy gombot minden képhez a FileUploader komponens használatával.

  2. A FileUploader komponens elfogadja az onUploaded tulajdonságot, amely akkor hívódik meg, amikor a felhasználó képet tölt fel. Győződjön meg róla, hogy a webSave-et hívja az orm szolgáltatásból az új kép feltöltéséhez.

  3. Lehet, hogy észrevette, hogy a kép feltöltődött, de a böngésző nem rendereli újra. Ennek oka, hogy a kép linkje nem változott, így a böngésző nem tölti újra őket. Tartalmazza a rekord write_date-jét a kép URL-jébe.

  4. Győződjön meg róla, hogy a feltöltés gombra kattintás nem váltja ki a switchView-t.

../../../_images/upload_image.png

14. Haladó tooltip sablon

Jelenleg csak egy tooltip mezőt tudunk megadni. De mi van akkor, ha szeretnénk egy konkrét sablont írni hozzá?

Example

Ez egy példa egy galéria arch nézetre, amelynek működnie kellene ezen gyakorlat után.

<record id="contacts_gallery_view" model="ir.ui.view">
   <field name="name">awesome_gallery.orders.gallery</field>
   <field name="model">res.partner</field>
   <field name="arch" type="xml">
      <gallery image_field="image_1920" tooltip_field="name">
         <field name="email"/> <!-- Specify to the model that email should be fetched -->
         <field name="name"/>  <!-- Specify to the model that name should be fetched -->
         <tooltip-template> <!-- Specify the owl template for the tooltip -->
            <p class="m-0">name: <field name="name"/></p> <!-- field is compiled into a t-esc-->
            <p class="m-0">e-mail: <field name="email"/></p>
         </tooltip-template>
      </gallery>
   </field>
</record>
  1. Cserélje le a res.partner galéria arch nézetet a awesome_gallery/views/views.xml fájlban a fenti példában található arch-ra. Ne aggódjon, ha nem felel meg az rng validációnak.

  2. Módosítsa a galéria rng validátort, hogy elfogadja az új arch struktúrát.

    Javaslat

    Használhatja ezt az rng kódrészletet a tooltip-template címke validálásához

    <rng:define name="tooltip-template">
       <rng:element name="tooltip-template">
             <rng:zeroOrMore>
                <rng:text/>
                <rng:ref name="any"/>
             </rng:zeroOrMore>
       </rng:element>
    </rng:define>
    
    <rng:define name="any">
       <rng:element>
             <rng:anyName/>
             <rng:zeroOrMore>
                <rng:choice>
                   <rng:attribute>
                         <rng:anyName/>
                   </rng:attribute>
                   <rng:text/>
                   <rng:ref name="any"/>
                </rng:choice>
             </rng:zeroOrMore>
       </rng:element>
    </rng:define>
    
  3. Az arch elemzőnek elemeznie kell a mezőket és a tooltip sablont. Importálja a visitXML-t a @web/core/utils/xml fájlból, és használja a mezőnevek és a tooltip sablon elemzésére.

  4. Győződjön meg róla, hogy a modell meghívja a webSearchRead-et az elemzett mezőnevek specifikációba való beillesztésével.

  5. The renderer (or any sub-component you created for it) should receive the parsed tooltip template. Manipulate this template to replace the <field> element into a <t t-esc="x"> element.

    Javaslat

    A sablon egy Element objektum, így úgy manipulálható, mint egy HTML elem.

  6. Regisztrálja a sablont az Owl-hoz az @odoo/owl xml függvényének köszönhetően.

  7. Használja a @web/core/tooltip/tooltip_hook useTooltip hook-ot az eszköztippek megjelenítéséhez. Ez a hook az Owl sablont és a sablon által igényelt változót veszi argumentumként.

../../../_images/advanced_tooltip.png