odoo and react
Tags: odoo
Published: 2023-12-22 10:42:02

below are the original articles related worth with react in Odoo
https://blog.bitbriks.com/create-react-module-in-odoo-as-standalone-app/
https://blog.bitbriks.com/make-api-request-in-odoo-without-jquery/

for back up purpose, I also post the contents of the articles but all credits go to the original author

-------

blog.bitbriks.com
Make api request in Odoo without jQuery
Vu Minh Tam
4–5 minutes
By Vu Minh Tam in odoo — Aug 3, 2019

Odoo is a powerful workhorse that comes with a ton of functionalities built-in. That sometimes comes at a cost of bloated code with more functionalities than needed. For example, the common javascript bundle web.assets_common.js is pretty large (about 1MB), including anything from jQuery, Bootstrap to QWeb. If our aim is to create an independent front-end client with a UI framework of choice, say React, why bother including all that. So in this post, we will be trying to create a very thin api client to Odoo’s backend.

Complete code sample for this example can be found here.
Creating a simple Rpc object

Constructing a Rpc object to simulate behavior of Odoo’s web client request is pretty straight forward. We make use of the new Javascript’s Fetch Api for simplicity.

class Rpc {

    _buildQuery(options) {
        // refer to Odoo's addons/web/static/src/core/js/rpc.js
    }

    query(params, options) {
        let query = this._buildQuery(params),
            id = Math.floor(Math.random() * 1000 * 1000 * 1000),
            data = {
                jsonrpc: "2.0",
                method: 'call',
                params: query.params,
                id: id
            },
            payload = {
                method: 'POST',
                credentials: 'same-origin',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(data, date_to_utc)
            };
        payload = Object.assign(Object.assign({}, options), payload);
        return new Promise((resolve, reject) => {
            fetch(query.route, payload).then(res => res.json()).then(jsonRes => {
                if (jsonRes.error) {
                    reject(jsonRes.error);
                }
                else {
                    resolve(jsonRes.result);
                }
            }).catch(reject);

        });
    }
}

Using it in a sample React based Odoo module

In previous example on creating a React based Todo Odoo module, newly created item is just kept ephermerally. Nothing is saved once the user leaves the page. We can make use of our service call to save item to server and fetch them on page load.

class TodoApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { items: [], text: '' };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.rpc = new Rpc();
    this.model = 'todo.todo';
    this.context = {lang:"en_US",tz:"Europe/Brussels",uid:2};
    this.fetch();
    
  }

  fetch() {
    var params = {
        model: this.model,
        context: this.context,
        method: 'search_read',
        fields: ['id', 'name']
    };

    this.rpc.query(params)
      .then(res => {        
        let items = [];
        for (let i = 0; i < res.length; i ++) {
          items.push({id: res[i].id, text: res[i].name});
        }

        this.setState(state => ({
          items: items,
          text: ''
        }));
      })
      .catch(e => {
        console.error(e);
      });
  }
  ...
}

We end up with a much smaller js bundle. Granted that our is simpler than the main Odoo’s web client, which requires much more to be packed in its Javascript bundle. But that is exactly the reason why we should slim it down when building our own custom app.

-----------------


blog.bitbriks.com
Create React module in Odoo - standalone Todo app
Vu Minh Tam
5–6 minutes

Odoo provides an extensible framework to create custom modules. For most customization needs, a module extends the pre-dominant form structure of Odoo by defining form and table fields. But there is case the UI need to deviate radically, for example, the point_of_sale module.

Modules like point_of_sale create a standalone single page app that plug into Odoo's backend. Basically it is like any other React app, except that the app authenticates and fetches data via Odoo's api. Let us illustrate the process by walking through implementing a Todo app, the classical FE getting started guide. The steps are:

    First, create a controller endpoint to serve the todo app
    Second, implement the React UI

Create a controller endpoint

Like point_of_sale, our Todo app resides in a separate endpoint from Odoo's common admin interface, which allows us to implement a new UI from a blank slate.

Let's create a simple controller with a single get method. And all it does is return a simple html template, which then bundles all javascript needed to bootstrap the todo app.

# -*- coding: utf-8 -*-
from odoo import http
from odoo.http import request
import json

class Todo(http.Controller):
    @http.route('/todo/todo/', auth='public')
    def index(self, **kw):
        context = {
            'session_info': json.dumps(request.env['ir.http'].session_info())
        }
        # todo.index is the xml template that contains
        # main html content 
        return request.render('todo.index', qcontext=context)

todo.index is the template that contains main html document.

<template id="index" name="todo index">&lt;!DOCTYPE html&gt;
    <html>
        <head>
	        <title>Custom React Todo</title>
	        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
	        <meta http-equiv="content-type" content="text/html, charset=utf-8" />               
	    </head>
	    <body>
           	<div class="o_main_content" id="todos-example"/>
            <script type="text/javascript">
                var odoo = <t t-out="json.dumps({
                    'debug': debug,
                    })"/>;
                // Prevent the menu_service to load anything. In an ideal world, POS assets would only contain
                // what is genuinely necessary, and not the whole backend.
                odoo.loadMenusPromise = Promise.resolve();
            </script>
            <t t-call-assets="web.assets_common" t-css="false" />
            <script src="https://unpkg.com/react@18/umd/react.development.js" ></script>
            <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" ></script>                   
            <t t-call-assets="todo.assets"/>
        </body>
    </html>
</template>

With the endpoint setup, you can access your new app at http://localhost:8069/todo/todo/, just that it is empty for now. The next step is to setup the interface.
Implement the React interface

We have a html template now. As with any other React app, next step is to loading the main javascript file that contains React code. Assuming that you know React well, creating a Todo app is straightforward.

With Odoo, we will need to put all our javascripts and css into an asset bundle, and tell Odoo to inject it into html. In the template above, it is done with the line <t t-call-assets="todo.assets"/>. It tells Odoo QWeb renderer that it should inject the javascript bundle todo.assets at that line in the output html.

To create the bundle, with Odoo 16, declare it in the __manifest__.py file

{
   'assets': {
        'todo.assets': [
            'todo/static/src/index.js',
            'todo/static/src/components/*.js',
            'todo/static/src/index.css',
            'todo/static/src/components/*.css'
        ]
    }
}

One thing to , Odoo's javascript module is declared using its own odoo.define syntax. If you want to write your javascript in standard ES6 import style, add the magic comment at the top of your file.

/* @odoo-module */

import React from 'react';
import ReactDOM from 'react-dom/client';

A problem remains, as React app is often implemented in JSX, which Odoo's bundler does not understand yet. It is possible to manually transpile Jsx to javascript first and include js file in the template bundle instead. What a slow and unpleasant process it would be.

So, next step, we attempt to override Odoo asset bundler’s with our own and call Babel transpiler before bundling.
Run Babel transpiler in Odoo's javascript bundling

Since you are interested in making Odoo React app, Babel must be in your regular toolkit. Babel is used to transpile jsx syntax to plain old javascript.  

Basically, we need to tell Odoo to run Babel transpiler before bundling javascript files together. Todo that, extend the base QWeb class to override the default AssetsBundle and JavascriptAsset. You can find more detailed instruction on how to run Babel transpiler on Odoo's asset here.

Now starts Odoo and navigate to the endpoint we created earlier to see the result.
What's next

Now that we are able to create a React-based Todo app, you may want to consider:

    Save todo item in Odoo's backend
    What if you want the interface to be part of Odoo usual admin page.