【odoo】 Customize a field

# Customize a field

https://www.odoo.com/documentation/16.0/developer/howtos/javascript_field.html

## ソースコードの配置

独自ウィジェットのソースコード等を `./static/src/` フォルダ内に配置します。
odooフレームワークは、 `__manifest__.py` ファイルに従って、実行に必要なファイルを読み込みます。

```:配置
v [<custom_modlue>]
    > [models]
    > [security]
    v [static]
        v [src]
            v [js]
                - <custom_widget>.js
            v [scss]
                - <custom_widget>.scss
            v [xml]
                - <custom_widget>.xml
   > [views]
   - __init__.py
   - __manifest__.py
   - README.md
```

:::note info
【ウィジェット別に分ける】
標準ウィジェットのソースコードは、次のフォルダにあります。

`/opt/odoo/odoo/addons/web/static/src/views/fields/`
https://github.com/odoo/odoo/tree/16.0/addons/web/static/src/views/fields

このフォルダを参照すると、拡張子ではなく、ウィジェット別に分けるのが良いようです。

:::

## Subclass an existing field component

`BooleanField` クラスを継承し、 `LateOrderBooleanField` クラスを派生させます。

```js:./static/src/js/late_order_boolean_field.js
/** @odoo-module */

import { registry } from "@web/core/registry";
import { BooleanField } from "@web/views/fields/boolean/boolean_field";
import { Component, xml } from "@odoo/owl";

class LateOrderBooleanField extends BooleanField {}
```

`web.BooleanField` テンプレートを継承した `my_module.LateOrderBooleanField` テンプレートを定義します。

```xml:./static/src/xml/late_order_boolean_field.xml
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
    <t t-name="jsfield.LateOrderBooleanField" t-inherit="web.BooleanField" owl="1">
        <xpath expr="//CheckBox" position="after">
              <span t-if="props.value" class="text-danger"> Late! </span>
        </xpath>
    </t>
</templates>
```

`LateOrderBooleanField` クラスのテンプレートを明示的に指定し、 `late_boolean` ウィジェットとして odooフレームワークに登録します。

```js:./static/src/js/late_order_boolean_field.js
/** @odoo-module */
:
:

LateOrderBooleanField.template = "jsfield.LateOrderBooleanField";
registry.category("fields").add("late_boolean", LateOrderBooleanField);
```

`__manifest__.py` ファイルで、`late_order_boolean_field.js/xml` ファイルを読み込むように指定します。

```py:__manifest__.py
    :
    :

    'assets': {
        'web.assets_backend': {
            '/fields/static/src/js/late_order_boolean_field.js',
            '/fields/static/src/xml/late_order_boolean_field.xml',
        },
    },

    :
    :
```

odooモジュールのビューで、作成した `late_boolean` ウィジェットを指定できます。

```xml:someview.xml
    :
    <field name="late_order" widget="late_boolean"/>
    :
```


## Create a new field component

`Component` クラスを継承し、テキストを赤色で表示するフィールドを作成します。
`props` に `standardFieldProps` を割り当てることにより、標準的なフィールドとして機能します。

:::note warn
**onChangeイベントハンドラ**
公式の[サンプルソースコード](https://www.odoo.com/documentation/16.0/developer/howtos/javascript_field.html#id4)を一部変更しています。
`t-on-change="onChange"`

:::


```js:./static/src/js/my_text_field.js
/** @odoo-module */

import { standardFieldProps } from "@web/views/fields/standard_field_props";
import { Component, xml } from "@odoo/owl";
import { registry } from "@web/core/registry";

export class MyTextField extends Component {

    onChange(e) {
        this.props.update(e.target.value);
    }
}

MyTextField.template = xml`
    <input t-att-id="props.id" class="text-danger" t-att-value="props.value" t-on-change="onChange" />
`;
MyTextField.props = {
    ...standardFieldProps,
};
MyTextField.supportedTypes = ["char"];

```

`my_text_field` ウィジェットとして odooフレームワークに登録します。

```js:./static/src/js/my_text_field.js
/** @odoo-module */
:
:

registry.category("fields").add("my_text_field", MyTextField);

```

`__manifest__.py` ファイルで、`my_text_field.js` ファイルを読み込むように指定します。

```py:__manifest__.py
    :
    :

    'assets': {
        'web.assets_backend': {
            '/jsfield/static/src/js/late_order_boolean_field.js',
            '/jsfield/static/src/xml/late_order_boolean_field.xml',
            '/jsfield/static/src/js/my_text_field.js',
        },
    },

    :
    :
```

odooモジュールのビューで、作成した `my_text_field` ウィジェットを指定できます。

```xml:someview.xml
    :
    <field name="my_text" widget="my_text_field"/>
    :
```

:::note warn
ListやFormのViewでも`class`を追加可能

実際のところ、赤色で表示するだけであれば、ListやFormのView(ir.ui.view)で、`class` を追加するだけで実現します。

```
   <field name="somefield" class="text-danger"/>
```

既存の `class` に `text-danger` が追加されます。

:::

# odooサンプルプロジェクト

https://github.com/jp-96/odoo-howtos-javascript-field


# 参考

https://www.cybrosys.com/odoo/odoo-books/odoo-16-development/odoo-web-library/

**標準ウィジェット**

https://www.cybrosys.com/blog/field-types-and-widgets-in-odoo-16

https://www.cybrosys.com/blog/how-to-effectively-create-a-field-widget-in-odoo-15

[→ ダウンロード: progress_bar_widget (v15.0)](https://apps.odoo.com/apps/modules/15.0/progress_bar_widget/)

https://www.cybrosys.com/blog/how-to-create-a-field-widget-in-the-odoo-16

[→ ダウンロード: Multiple Date Picker Widget (v16.0)](https://apps.odoo.com/apps/modules/16.0/multiple_datepicker_widget/)

https://www.cybrosys.com/blog/how-to-extend-field-widget-in-odoo-16

# ビデオ

Create a Field Widget in Odoo

https://www.youtube.com/watch?v=Pv9YbnEb2Lw

https://github.com/alferjay/odoo-owl-tutorial/tree/field_widgets