1. Dessinez l'écran
Le template XML décrit ce que le composant affiche. La directive t-on-click="sayHello" relie le clic à la méthode JavaScript écrite à l'étape précédente.
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="training_hello.HelloWorld">
<div class="o_action p-4">
<h1>Hello Odoo</h1>
<p>Votre premier module est bien ouvert.</p>
<button type="button"
class="btn btn-primary"
t-on-click="sayHello">
Well, hello Odoo
</button>
</div>
</t>
</templates>Le nom training_hello.HelloWorld doit être strictement identique à la valeur de static template dans le fichier JavaScript.
2. Rendez l'application accessible depuis l'accueil
Pour que Hello Odoo apparaisse parmi les applications, Odoo doit savoir quel nom afficher et quel écran ouvrir lorsqu'on clique dessus.
Dans le fichier suivant, le bloc record crée une client action qui ouvre notre écran. Le bloc menuitem ajoute Hello Odoo au menu des applications et relie le clic à cette action.
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="training_hello_action" model="ir.actions.client">
<field name="name">Hello Odoo</field>
<field name="tag">training_hello.hello_world</field>
</record>
<menuitem id="training_hello_menu_root"
name="Hello Odoo"
action="training_hello_action"
sequence="10"/>
</odoo>Ne cherchez pas à mémoriser tous les attributs. Pour cet écran, retenez simplement ce qui se passe quand vous cliquez sur Hello Odoo :
- Le menu porte le libellé visible
name="Hello Odoo". Son attributaction="training_hello_action"désigne l'action à lancer. L'idde l'action fournit donc le handle stable de ce binding : gardez-le tel quel pendant l'exercice. model="ir.actions.client"choisit le type client action : il affiche un composant dans le client web, au lieu d'ouvrir la liste ou le formulaire d'un modèle métier. C'est le bon choix pour notre écran Owl.- Le
tagtraining_hello.hello_worldest le binding décisif : le client web recherche exactement cette clé dansregistry.category("actions"), où le composant JavaScript a été enregistré. La casse et les deux côtés doivent correspondre. - Le composant charge ensuite le template
training_hello.HelloWorld, puis le bouton reliet-on-click="sayHello"à la méthode JavaScriptsayHello().
Le type client action n'est qu'une famille parmi d'autres : ir.actions.act_window ouvre des vues sur un modèle, ir.actions.act_url ouvre une URL, ir.actions.server exécute une logique côté serveur et ir.actions.report produit un rapport. Consultez la liste officielle des actions Odoo 19 ; la référence « Client actions » décrit précisément le lien entre le menu, le tag et le registry JavaScript.
hello_world_menus.xml est-il imposé ?Non. Odoo n'exige pas de nom précis pour ce fichier. Nous utilisons un nom en minuscules, avec des mots séparés par des underscores, qui décrit clairement son contenu. Vous pourriez par exemple le renommer menus.xml ou hello_menus.xml.
En revanche, le chemin déclaré dans __manifest__.py doit correspondre exactement au nouveau nom. Si le fichier devient views/menus.xml, remplacez aussi views/hello_world_menus.xml par views/menus.xml dans la propriété data, puis mettez le module à niveau.
Le nom du fichier sert surtout aux développeurs. Pour Odoo, ce sont les identifiants définis à l'intérieur — comme training_hello_action et training_hello_menu_root — qui donnent leur identité durable aux enregistrements.
3. Complétez le manifeste
Les trois nouveaux fichiers existent. Avant de copier le manifeste complet, vérifiez précisément ce qui change par rapport à __manifest__.py minimal de la section 1 :
summary: remplacezUn premier module minimal pour OdooparUn premier écran interactif dans Odoopour décrire le nouveau résultat.depends: remplacez["base"]par["web"]; le module utilise le client web, ses services et son registry, etwebdépend déjà debase.data: remplacez[]par["views/hello_world_menus.xml"]pour demander à Odoo de charger l'action et le menu dans la base.assets: ajoutez le bundleweb.assets_backendavectraining_hello/static/src/hello_world/hello_world.jsettraining_hello/static/src/hello_world/hello_world.xml; ces deux fichiers pourront alors être chargés par le client web.applicationetinstallable: conservezTruepour les deux ;application=Trueclasse le module dans Apps et lemenuitemracine crée l'entrée de l'app switcher/accueil, tandis queinstallable=Trueautorise son installation.- Les autres champs : gardez
name,version,category,authoretlicensetels quels pour cet exercice.
Vous pouvez ensuite remplacer le contenu par cette version complète :
{
"name": "Hello Odoo",
"summary": "Un premier écran interactif dans Odoo",
"version": "19.0.1.0.0",
"category": "Training",
"author": "Formation Odoo",
"license": "LGPL-3",
"depends": ["web"],
"data": [
"views/hello_world_menus.xml",
],
"assets": {
"web.assets_backend": [
"training_hello/static/src/hello_world/hello_world.js",
"training_hello/static/src/hello_world/hello_world.xml",
],
},
"application": True,
"installable": True,
}web remplace base dans depends : le client web dépend déjà de base, et notre composant utilise directement ses services. web.assets_backend est le bundle chargé dans l'interface interne des utilisateurs connectés ; il ne signifie pas « réservé aux administrateurs ».
Dans data, views/hello_world_menus.xml est relatif au dossier du module. Dans assets, chaque chemin commence par training_hello, car un bundle réunit des fichiers provenant de plusieurs modules.
4. Vérifiez que les noms correspondent
- Le manifeste charge les deux fichiers d'assets et
views/hello_world_menus.xml. - Dans l'action,
training_hello.hello_worldest exactement le nom sous lequel le composant est enregistré en JavaScript. - Dans le composant,
training_hello.HelloWorldest exactement le nom donné au template XML.
L'entrée Hello Odoo lance l'action, l'action retrouve le composant, le composant affiche le template et le bouton appelle sayHello().