サービス

サービスは、機能を提供するコードの長い部分です。 これらはコンポーネント(useService``と共に)または他のサービスによってインポートすることができます。また、依存関係のセットを宣言することもできます。 その意味で、サービスは基本的に DI :dfn:`依存注入` システムです。 例えば、``notification サービスは通知を表示する方法を提供します。 または、 rpc サービスは、Odoo サーバーへのリクエストを実行するための適切な方法です。

以下の例では、5秒ごとに通知を表示するシンプルなサービスを登録します。

import { registry } from "@web/core/registry";

const myService = {
    dependencies: ["notification"],
    start(env, { notification }) {
        let counter = 1;
        setInterval(() => {
            notification.add(`Tick Tock ${counter++}`);
        }, 5000);
    }
};

registry.category("services").add("myService", myService);

起動時に、Webクライアントは`services`レジストリにあるすべてのサービスを開始します。 レジストリで使用される名前はサービスの名前です。

注釈

コンポーネントではないほとんどのコードは、サービス内で*パッケージ化*されるべきです。特に、副作用がある場合は特に。 これはテスト目的に非常に便利です。テストはアクティブなサービスを選択できます。 つまりテストされるコードに邪魔される望ましくない副作用が

サービスの定義

サービスは以下のインターフェイスを実装する必要があります。

dependencies

任意の文字列リスト。このサービスが必要とするすべての依存関係(他のサービス)のリストです。

start(env, deps)
引数
  • env (Environment()) -- アプリケーションの環境

  • deps (Object()) -- 要求された依存関係のすべて

戻り値

value of service or Promise<value of service>

これはサービスのメイン定義です。値またはpromiseのいずれかを返すことができます。 その場合、サービス・ローダーは単にサービスの値である値に解決するpromiseを待つだけです。

一部のサービスは値をエクスポートしません。他のコードから直接呼び出す必要がなくても作業を行うことができます。 その場合、値は env.servicesnull に設定されます。

async

任意の値。与えられた場合は、 true または文字列のリストにする必要があります。

一部のサービスでは、非同期APIを提供する必要があります。 例えば、 rpc サービスは非同期関数であるか、 orm サービスは Odoo サーバーを呼び出す関数のセットを提供します。

この場合、非同期関数呼び出しの終了前にサービスを使用するコンポーネントが破棄される可能性があります。 ほとんどの場合、非同期関数呼び出しは無視する必要があります。 それ以外の場合は、元のコンポーネントがアクティブになっていないため、非常に危険な可能性があります。 async フラグは、コンポーネントが破棄された場合、コンポーネントからのすべての非同期呼び出しを保留状態のままにするようにサービス作成者に通知します。

サービスの使用

他のサービスに依存し、dependencies を適切に宣言したサービスは、start メソッドの第二引数で対応するサービスへの参照を受け取るだけです。

useService フックは、コンポーネントでサービスを使用するための適切な方法です。 これは単にサービス値への参照を返し、後でコンポーネントによって使用することができます。例えば:

import { rpc } from "@web/core/network/rpc";

class MyComponent extends Component {
  setup() {
    onWillStart(async () => {
      const result = await rpc(...);
    })
  }
}

参照リスト

技術名

簡単な説明

cookie

Cookie の読み取りまたは変更

effect

グラフィカルエフェクトを表示

http

低レベルのhttpコールを実行する

notification

通知を表示

router

ブラウザのURLを管理する

rpc

サーバーへのリクエストの送信

scroller

アンカー要素のクリックを処理する

title

ウィンドウのタイトルを読んだり変更したりします

user

は、現在のユーザーに関連する情報を提供します。

概要

  • 技術名: cookie

  • 依存関係: なし

クッキーを操作する方法を提供します。例えば:

cookieService.setCookie("hello", "odoo");

API

current

それぞれのクッキーとその値を表すオブジェクト (または空文字列)

setCookie(name[, value, ttl])
引数
  • name (string()) -- 設定すべきクッキーの名前

  • value (any()) -- 任意です。与えられた場合、クッキーはその値に設定されます。

  • ttl (number()) -- 任意です。クッキーが削除されるまでの秒数(デフォルト=1年)

`name`を`ttl`の最大年齢で値`value`に設定します。

deleteCookie(name)
引数
  • name (string()) -- クッキーの名前

Cookie の name を削除します。

エフェクトサービス

概要

  • 技術名: effect

  • 依存関係: なし

エフェクトとは、ページの上部に一時的に表示されるグラフィカル要素であり、通常、何か面白いことが起こったというフィードバックをユーザーに提供します。

良い例としては、虹の男性です:

レインボーマン効果

これを表示する方法は次のとおりです。

const effectService = useService("effect");
effectService.add({
  type: "rainbow_man", // can be omitted, default type is already "rainbow_man"
  message: "Boom! Team record for the past 30 days.",
});

警告

フック`useEffect`はエフェクトサービスとは関係ありません。

API

effectService.add(options)
引数
  • options (object()) -- を選択します。

効果を表示する

オプションは次の方法で定義されます:

interface EffectOptions {
  // The name of the desired effect
  type?: string;
  [paramName: string]: any;
}

利用可能なエフェクト

現在、唯一の効果は虹の男です。

RainbowMan
effectService.add({ type: "rainbow_man" });

名前(name)

説明

params.Component

owl.Component?

RainbowMan内部でインスタンス化するコンポーネントクラス(メッセージを置き換えます)。

params.props

object?={}

params.Component が与えられた場合、props はこの引数で渡すことができます。

params.message

string?="Well Done!"

メッセージはレインボーマンが保持している通知です。

ユーザーに対してエフェクトが無効になっている場合、レインボーマンは表示されず、単純な通知がフォールバックとして表示されます。

もしエフェクトが有効になっていて、params.Component が指定されている場合、 params.message は使用されません。

メッセージは単純な文字列またはhtmlを表す文字列です(DOM内でインタラクションが必要な場合はparams.Component を使用することを好みます)。

params.messageIsHtml

boolean?=false

メッセージが html を表す場合は true に設定します。このメッセージは DOM に正しく挿入されます。

params.img_url

string?=/web/static/img/smile.svg

虹の中に表示される画像のURL。

params.fadeout

("slow"|"medium"|"fast"|"no")?="medium"

レインボーマンの遅延が消えます。

`"速い"`はすぐにレインボーマンが消えます。

medium""slow" は消える前に少し待機します(params.message が長い場合に使用できます)。

`"いいえ"は、ユーザーが虹の外のどこかをクリックするまで、虹の男性を画面に表示します。

効果を追加する方法

エフェクトは effects というレジストリに保存されます。名前と関数を指定することで、新しいエフェクトを追加できます。

const effectRegistry = registry.category("effects");
effectRegistry.add("rainbow_man", rainbowManEffectFunction);

関数はこの API に従う必要があります:

<newEffectFunction>(env, params)
引数
  • env (Env()) -- サービスによって受け取られた環境

  • params (object()) -- サービスの add 関数から受け取ったパラメータ。

戻り値

({Component, props} | void) コンポーネントとそのプロパティは何もありません。

この関数はコンポーネントを作成して返さなければなりません。このコンポーネントはエフェクトコンポーネントコンテナ内にマウントされます。

例えば、ページを見てセピアを追加する効果を追加したいとしましょう。

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

class SepiaEffect extends Component {
  static template = xml`
    <div style="
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        pointer-events: none;
        background: rgba(124,87,0, 0.4);
    "></div>
  `;
}

export function sepiaEffectProvider(env, params = {}) {
    return {
        Component: SepiaEffect,
    };
}

const effectRegistry = registry.category("effects");
effectRegistry.add("sepia", sepiaEffectProvider);

そして、あなたが望む場所にそれを呼び出すと、結果が表示されます。 ここでは、たとえばどこにでも表示させるために webclient.js で呼び出されます。

const effectService = useService("effect");
effectService.add({ type: "sepia" });
セピアのオドウ

Http サービス

概要

  • 技術名: http

  • 依存関係: なし

クライアントとodoのサーバー間のほとんどのやり取りは`RPCs`(XMLHTTPRequest)ですが、リクエストに対するより低いレベルの制御が必要な場合があります。

このサービスは、getpost http requests を送信する方法を提供します。

API

async get(route[, readMethod = "json"])
引数
  • route (string()) -- リクエストを送信するURL

  • readMethod (string()) -- レスポンスコンテンツの種類。"text", "json", "formData", "blob", "arrayBuffer" にできます。

戻り値

readMethod 引数で定義されているフォーマットのリクエストの結果。

Get リクエストを送信します。

async post(route[, params = {}, readMethod = "json"])
引数
  • route (string()) -- リクエストを送信するURL

  • params (object()) -- リクエストのフォームデータ部分に設定するキー値データ

  • readMethod (string()) -- レスポンスコンテンツの種類。"text", "json", "formData", "blob", "arrayBuffer" にできます。

戻り値

readMethod 引数で定義されているフォーマットのリクエストの結果。

ポストリクエストを送信します。

const httpService = useService("http");
const data = await httpService.get("https://something.com/posts/1");
// ...
await httpService.post("https://something.com/posts/1", { title: "new title", content: "new content" });

通知サービス

概要

  • 技術名: notification

  • 依存関係: なし

notification サービスは画面に通知を表示することができます。

const notificationService = useService("notification");
notificationService.add("I'm a very simple notification");

API

add(message[, options])
引数
  • message (string()) -- 表示する通知メッセージ

  • options (object()) -- 通知のオプション

戻り値

通知を閉じる機能

通知を表示

オプションは次の方法で定義されます:

名前(name)

説明

title

文字列

通知にタイトルを追加

タイプ

warning | dang | success | info

種類に応じて背景色を変更します

sticky

boolean

解除されるまで通知を維持するかどうか

className

文字列

通知に追加される追加のCSSクラス

onClose

関数

通知が終了したときに実行されるコールバック:

ボタン

ボタン[] (下記参照)

通知に表示するボタンのリスト

autocloseDelay

数値

通知が自動的に閉じられるまでの時間 (ミリ秒)

ボタンは以下により定義されます:

名前(name)

説明

名前

文字列

ボタンのテキスト

onClick

関数

ボタンをクリックしたときに実行するコールバックコード

primary

boolean

ボタンをプライマリボタンとしてスタイル付けするかどうか

販売取引が手数料のページのいくつかの種類を移動するボタンで行われたときの通知。

// in setup
this.notificationService = useService("notification");
this.actionService = useService("action");

// later
this.notificationService.add("You closed a deal!", {
  title: "Congrats",
  type: "success",
  buttons: [
      {
          name: "See your Commission",
          onClick: () => {
              this.actionService.doAction("commission_action");
          },
      },
  ],
});
通知の例

1秒後に閉じる通知:

const notificationService = useService("notification");
const close = notificationService.add("I will be quickly closed");
setTimeout(close, 1000);

ルーターサービス

概要

  • 技術名: router

  • 依存関係: なし

`router`サービスは3つの機能を提供します。

  • 現在のルートに関する情報は

  • アプリケーションがURLを更新する方法は

  • すべてのハッシュ変更を聞いてアプリケーションの残りの部分に通知します

API

current

現在のルートは current キーでアクセスできます。以下の情報を持つオブジェクトです:

  • pathname (string): 現在の場所のパス (ほとんどの場合 /web )

  • search (object): 各検索キーワード (クエリ文字列) をURLから値にマッピングする辞書。 値が明示的に指定されていない場合、空の文字列が値です

  • hash (object): 上記と同じですが、ハッシュに記述されている値です。

例:

// url = /web?debug=assets#action=123&owl&menu_id=174
const { pathname, search, hash } = env.services.router.current;
console.log(pathname); //   /web
console.log(search); //   { debug="assets" }
console.log(hash); //   { action:123, owl: "", menu_id: 174 }

URL の更新は pushState メソッドで行われます。

pushState(hash: object[, replace?: boolean])
引数
  • hash (Object()) -- オブジェクトはあるキーからある値へのマッピングを含んでいます

  • replace (boolean()) -- true の場合、url は置き換えられます。そうでなければ、 hash のキーと値のペアのみが更新されます。

`hash`オブジェクトの各キーと値のペアでURLを更新します。 値が空文字列に設定されている場合、キーは対応する値なしでURLに追加されます。

true の場合、 replace 引数は、url ハッシュが完全に置き換えられるべきであることをルータに伝えます(そのため、hash オブジェクトには存在しない値は削除されます)。

このメソッドの呼び出しはページをリロードしません。 また、hashchange イベントや main busROUTE_CHANGE もトリガーしません。 これは、このメソッドが url のみを更新することを意図しているからです。 このメソッドを呼び出すコードは、画面が同様に更新されていることを確認する責任があります。

例:

// url = /web#action_id=123
routerService.pushState({ menu_id: 321 });
// url is now /web#action_id=123&menu_id=321
routerService.pushState({ yipyip: "" }, replace: true);
// url is now /web#yipyip

最後に、redirect メソッドは指定された url にブラウザーをリダイレクトします。

redirect(url[, wait])
引数
  • url (string()) -- a valid url

  • wait (boolean()) -- true の場合、サーバーの準備が完了するのを待ってからリダイレクトします

ブラウザーを url にリダイレクトします。このメソッドはページを再読み込みします。 wait 引数はめったに使用されません。サーバーが短期間利用できない場合があります。 通常アドオンのアップデートやインストール操作の直後です

注釈

ルーターサービスは、現在のルートが変更されたときに、 :ref:の メインバス <frontend/framework/bus> 上で ROUTE_CHANGE イベントを発行します。

RPCサービス

概要

  • 技術名: rpc

  • 依存関係: なし

rpc`サービスは、サーバーにリクエストを送信する単一の非同期関数を提供します。 コントローラを呼び出すのはとても簡単です。route (ルート)は最初の引数で、必要に応じて第2引数として ``params` オブジェクトを与えることができます。

import { rpc } from "@web/core/network/rpc";

 // somewhere else, in an async function:
 const result = await rpc("/my/route", { some: "value" });

注釈

rpc サービスは低レベルのサービスとみなされることに注意してください。Odoo コントローラとの相互作用にのみ使用する必要があります。 (最も重要なユースケースである)モデルを扱うには、代わりに orm サービスを使用してください。

API

rpc(route, params, settings)
引数
  • route (string()) -- リクエスト対象のルート

  • params (Object()) -- (オプション) サーバーに送信されるパラメータ

  • settings (Object()) -- (オプション) リクエストの設定 (下記参照)

settings オブジェクトには以下が含まれます:

  • xhrXMLHTTPRequest オブジェクトでなければなりません。その場合、rpc メソッドは新しいオブジェクトを作成する代わりに使用します。 これは、 XMLHTTPRequest API の高度な機能にアクセスするときに便利です。

  • silent (boolean) もし true に設定されている場合、Webクライアントは保留中のrpcがあるというフィードバックを提供しません。

rpc サービスは XMLHTTPRequest オブジェクトを使用してサーバーと通信し、application/json コンテンツ型で動作するように構成されています。 そのため、リクエストの内容は明らかにJSONシリアライズ可能である必要があります。このサービスで行われる各リクエストは``POST`` httpメソッドを使用します。

サーバーエラーは実際にはHTTPコード200で応答を返しますが、rpc サービスはエラーとして扱います。

エラー処理

rpc は主に 2 つの理由で失敗する可能性があります:

  • どちらかのodoサーバがエラーを返します(これを``server`` エラーと呼びます)。 その場合、http リクエストは error キーを含むレスポンスオブジェクトを含む http コード 200 BUT で返されます。

  • あるいは他の種類のネットワークエラーがあります

rpc が失敗した場合:

  • rpcを表すプロミスが拒否されたので 呼び出しコードが壊れてしまいます

  • メインアプリケーション・バス上で RPC_ERROR イベントがトリガーされます。イベント・ペイロードにはエラーの原因の説明が含まれています:

    サーバーエラーの場合(サーバーコードは例外を投げました)。 その場合、ペイロードは次のキーを持つオブジェクトになります。

    • type = 'server'

    • message(string)

    • code(number)

    • name(string) (オプション、エラーサービスでエラーを処理する際に適切なダイアログを検索するために使用)

    • subType(string) (オプション、ダイアログタイトルを決定するためによく使用されます)

    • data(object) (debug の中に様々なキーを含むことができる任意のオブジェクト: コールスタックを使用したメインデバッグ情報)

    If it is a network error, then the error description is simply an object {type: 'network'}. When a network error occurs, a notification is displayed and the server is regularly contacted until it responds. The notification is closed as soon as the server responds.

スクローラーサービス

概要

  • 技術名: scroller

  • 依存関係: なし

ユーザーがウェブクライアント内のアンカーをクリックするたびに、このサービスは自動的にターゲット(適切な場合)にスクロールします。

このサービスは、click をドキュメント上に取得するためのイベントリスナーを追加します。 サービスは href 属性に含まれるセレクターがアンカーと Odoo アクションを区別するために有効であるかどうかをチェックします。 . <a href="#target_element"></a>). そうでない場合は何も行いません。

メインアプリケーション・バス上で SCROLLER:ANCHOR_LINK_CLICKED イベントがトリガーされます。 このイベントには、element matching と id を参照として含むカスタムイベントが含まれています。 他の部分がアンカー自身からの相対的な振る舞いを処理できるようにすることができます。 元のイベントも予防する必要があるかもしれませんので、与えられます。 イベントが防止されない場合、ユーザーインターフェイスはターゲット要素までスクロールします。

API

上で説明した anchor-link-clicked カスタムイベントには、次の値が含まれています。

名前(name)

説明

element

HTMLElement | null

href が対象とするアンカー要素

id

string

href に含まれる id

originalEv

Event

元のクリックイベント

注釈

scrollerサービスは、 メインバス 上で SCROLLER:ANCHOR_LINK_CLICK_CLICKED イベントを発行します。 スクロールサービスのデフォルトの動作を避けるために リスナーから自分の動作を正しく実装できるように、リスナーに与えられたイベントに preventDefault() を使用する必要があります。

タイトルサービス

概要

  • 技術名: title

  • 依存関係: なし

title サービスは、ドキュメントのタイトルを読んだり変更したりできるシンプルなAPIを提供します。 例えば、現在のドキュメントのタイトルが「Odoo」の場合、次のコマンドを使用して「Odoo 15 - Apple」に変更できます。

// in some component setup method
const titleService = useService("title");

titleService.setParts({ odoo: "Odoo 15", fruit: "Apple" });

API

title サービスは以下のインターフェイスを操作します。

interface Parts {
    [key: string]: string | null;
}

各キーは、タイトルの一部の識別を表します。 そして、それぞれの値は表示される文字列、もしくは削除された場合は nullです。

API は次の通りです:

current

これは現在のタイトルを表す文字列です。value_1 - ... - value_n 各`value_i` は (null ではない) 値です (getParts 関数によって返されます)

getParts()
戻り値

タイトルサービスによって維持されている現在の Parts オブジェクトのパーツ

setParts(parts)
引数
  • parts (Parts()) -- 必要な変更を表すオブジェクト

setParts メソッドでは、タイトルの複数の部分を追加/置き換え/削除できます。 パーツ(値)を削除するには、関連するキーの値を null に設定します。

1つは他のパートに影響を与えることなく、1つのパートしか変更できないことに注意してください。例えば、タイトルが次のパートで構成されている場合:

{ odoo: "Odoo", action: "Import" }

current の値は Odoo - Import で、

setParts({
  action: null,
});

タイトルを Odoo に変更します。

ユーザーサービス

概要

  • 技術名: user

  • 依存関係: rpc

`user`サービスは、データの束と接続されたユーザーに関するいくつかのヘルパー関数を提供します。

API

名前(name)

説明

context

Object

user context

db

Object

データベースに関する情報

home_action_id

(number | false)

ユーザのホームとして使用されるアクションの Id

isAdmin

boolean

ユーザーが管理者であるかどうか(グループ base.group_erp_manager またはスーパーユーザー)

isSystem

boolean

ユーザーがシステムグループ (base.group_system) の一部であるかどうか

lang

string

使用言語

name

string

ユーザーの名前

partnerId

number

ユーザーのパートナーインスタンスの Id

tz

string

利用者のタイムゾーン

userId

number

利用者ID

userName

string

ユーザーの代替ニックネーム:

updateContext(update)
引数
  • update (object()) -- コンテキストを更新するオブジェクト

user context を指定したオブジェクトで更新します。

userService.updateContext({ isFriend: true })
removeFromContext(key)
引数
  • key (string()) -- 対象となる属性の鍵

:ref:`user context<frontend/framework/user_context> ` から与えられたキーで値を削除します

userService.removeFromContext("isFriend")
hasGroup(group)
引数
  • group (string()) -- 検索するグループの xml_id

戻り値

`Promise<boolean>`はグループ内のユーザーです

ユーザーがグループの一部であるかどうかをチェックします。

const isInSalesGroup = await userService.hasGroup("sale.group_sales")