mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fe176f13a5 |
@@ -107,7 +107,7 @@ is necessary, since Owl needs to react to a change in state.
|
|||||||
### `useRef`
|
### `useRef`
|
||||||
|
|
||||||
The `useRef` hook is useful when we need a way to interact with some inside part
|
The `useRef` hook is useful when we need a way to interact with some inside part
|
||||||
of a component, rendered by Owl. It only work on a html element tagged by the
|
of a component, rendered by Owl. It only work on a HTML element tagged by the
|
||||||
`t-ref` directive:
|
`t-ref` directive:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
@@ -227,12 +227,12 @@ function useSomething() {
|
|||||||
|
|
||||||
This hook will run a callback when a component is mounted and patched, and
|
This hook will run a callback when a component is mounted and patched, and
|
||||||
will run a cleanup function before patching and before unmounting the
|
will run a cleanup function before patching and before unmounting the
|
||||||
the component (only if some dependencies have changed).
|
component (only if some dependencies have changed).
|
||||||
|
|
||||||
It has almost the same API as the React `useEffect` hook, except that the dependencies
|
It has almost the same API as the React `useEffect` hook, except that the dependencies
|
||||||
are defined by a function instead of just the dependencies.
|
are defined by a function instead of just the dependencies.
|
||||||
|
|
||||||
The `useEffect` hook takes two function: the effect function and the dependency
|
The `useEffect` hook takes two functions: the effect function and the dependency
|
||||||
function. The effect function perform some task and return (optionally) a cleanup
|
function. The effect function perform some task and return (optionally) a cleanup
|
||||||
function. The dependency function returns a list of dependencies, these dependencies
|
function. The dependency function returns a list of dependencies, these dependencies
|
||||||
are passed as parameters in the effect function . If any of these
|
are passed as parameters in the effect function . If any of these
|
||||||
|
|||||||
@@ -320,28 +320,6 @@ class ComponentB extends owl.Component {
|
|||||||
|
|
||||||
Note: the props validation code is done by using the [validate utility function](utils.md#validate).
|
Note: the props validation code is done by using the [validate utility function](utils.md#validate).
|
||||||
|
|
||||||
### `slots` prop
|
|
||||||
|
|
||||||
If a component that uses [slots](slots.md) also lists or validates its props, then
|
|
||||||
you will have to explicitely allow the `slots` prop (with an `Object` type), or
|
|
||||||
allow extra props using the `*` notation mentioned above. This is because slots
|
|
||||||
are provided to a component [as props](slots.md#slots-and-props).
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```js
|
|
||||||
class MyComponent extends Component {
|
|
||||||
static props = [someProp, slots?];
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyComponentWithValidation extends Component {
|
|
||||||
static props = {
|
|
||||||
someProp: {type: Number, optional: true},
|
|
||||||
slots : {type: Object, optional: true},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Good Practices
|
## Good Practices
|
||||||
|
|
||||||
A `props` object is a collection of values that come from the parent. As such,
|
A `props` object is a collection of values that come from the parent. As such,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { OwlError } from "../common/owl_error";
|
import { OwlError } from "../common/owl_error";
|
||||||
import { ComponentNode, getCurrent } from "./component_node";
|
|
||||||
export type Callback = () => void;
|
export type Callback = () => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,52 +81,10 @@ export function validateTarget(target: HTMLElement | ShadowRoot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class EventBus extends EventTarget {
|
export class EventBus extends EventTarget {
|
||||||
constructor(events?: string[]) {
|
|
||||||
if (events) {
|
|
||||||
let node: ComponentNode | null = null;
|
|
||||||
try {
|
|
||||||
node = getCurrent();
|
|
||||||
} catch {}
|
|
||||||
if (node?.app?.dev) {
|
|
||||||
return new DebugEventBus(events);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
trigger(name: string, payload?: any) {
|
trigger(name: string, payload?: any) {
|
||||||
this.dispatchEvent(new CustomEvent(name, { detail: payload }));
|
this.dispatchEvent(new CustomEvent(name, { detail: payload }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class DebugEventBus extends EventBus {
|
|
||||||
private events: Set<string>;
|
|
||||||
constructor(events: string[]) {
|
|
||||||
super();
|
|
||||||
this.events = new Set(events);
|
|
||||||
}
|
|
||||||
addEventListener(
|
|
||||||
type: string,
|
|
||||||
listener: EventListenerOrEventListenerObject | null,
|
|
||||||
options?: boolean | AddEventListenerOptions
|
|
||||||
): void {
|
|
||||||
if (!this.events.has(type)) {
|
|
||||||
throw new OwlError(`EventBus: subscribing to unknown event '${type}'`);
|
|
||||||
}
|
|
||||||
super.addEventListener(type, listener, options);
|
|
||||||
}
|
|
||||||
trigger(name: string, payload?: any) {
|
|
||||||
if (!this.events.has(name)) {
|
|
||||||
throw new OwlError(`EventBus: triggering unknown event '${name}'`);
|
|
||||||
}
|
|
||||||
super.trigger(name, payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatchEvent(event: Event): boolean {
|
|
||||||
if (!this.events.has(event.type)) {
|
|
||||||
throw new OwlError(`EventBus: dispatching unknown event '${event.type}'`);
|
|
||||||
}
|
|
||||||
return super.dispatchEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function whenReady(fn?: any): Promise<void> {
|
export function whenReady(fn?: any): Promise<void> {
|
||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
|
|||||||
+1
-63
@@ -1,7 +1,5 @@
|
|||||||
import { batched, EventBus, htmlEscape, markup } from "../src/runtime/utils";
|
import { batched, EventBus, htmlEscape, markup } from "../src/runtime/utils";
|
||||||
import { makeTestFixture, nextMicroTick } from "./helpers";
|
import { nextMicroTick } from "./helpers";
|
||||||
import { getCurrent } from "../src/runtime/component_node";
|
|
||||||
import { Component, mount, xml } from "../src";
|
|
||||||
|
|
||||||
describe("event bus behaviour", () => {
|
describe("event bus behaviour", () => {
|
||||||
test("can subscribe and be notified", () => {
|
test("can subscribe and be notified", () => {
|
||||||
@@ -35,66 +33,6 @@ describe("event bus behaviour", () => {
|
|||||||
bus.addEventListener("event", (ev: any) => expect(ev.detail).toBe("hello world"));
|
bus.addEventListener("event", (ev: any) => expect(ev.detail).toBe("hello world"));
|
||||||
bus.trigger("event", "hello world");
|
bus.trigger("event", "hello world");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("events are not validated if the bus is created outside of dev mode", async () => {
|
|
||||||
let bus_empty: EventBus | null = null;
|
|
||||||
class Root extends Component {
|
|
||||||
static template = xml`<div/>`;
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
getCurrent(); // checks that we're in a component context
|
|
||||||
|
|
||||||
bus_empty = new EventBus([]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await mount(Root, makeTestFixture());
|
|
||||||
|
|
||||||
bus_empty!.addEventListener("a", () => {});
|
|
||||||
bus_empty!.trigger("a");
|
|
||||||
bus_empty!.dispatchEvent(new CustomEvent("a"));
|
|
||||||
});
|
|
||||||
test("events are validated if the bus is created in dev mode & events are provided", async () => {
|
|
||||||
let bus: EventBus | null = null;
|
|
||||||
let bus_empty: EventBus | null = null;
|
|
||||||
let bbus_no_validation: EventBus | null = null;
|
|
||||||
class Root extends Component {
|
|
||||||
static template = xml`<div/>`;
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
getCurrent(); // checks that we're in a component context
|
|
||||||
|
|
||||||
bus = new EventBus(["a", "b"]);
|
|
||||||
bus_empty = new EventBus([]);
|
|
||||||
bbus_no_validation = new EventBus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await mount(Root, makeTestFixture(), { test: true });
|
|
||||||
|
|
||||||
bbus_no_validation!.addEventListener("c", () => {});
|
|
||||||
bbus_no_validation!.trigger("c");
|
|
||||||
bbus_no_validation!.dispatchEvent(new CustomEvent("c"));
|
|
||||||
|
|
||||||
bus!.addEventListener("a", () => {});
|
|
||||||
bus!.trigger("a");
|
|
||||||
bus!.dispatchEvent(new CustomEvent("a"));
|
|
||||||
|
|
||||||
expect(() => bus!.addEventListener("c", () => {})).toThrow(
|
|
||||||
"EventBus: subscribing to unknown event 'c'"
|
|
||||||
);
|
|
||||||
expect(() => bus!.trigger("c")).toThrow("EventBus: triggering unknown event 'c'");
|
|
||||||
expect(() => bus!.dispatchEvent(new CustomEvent("c"))).toThrow(
|
|
||||||
"EventBus: dispatching unknown event 'c'"
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(() => bus_empty!.addEventListener("a", () => {})).toThrow(
|
|
||||||
"EventBus: subscribing to unknown event 'a'"
|
|
||||||
);
|
|
||||||
expect(() => bus_empty!.trigger("a")).toThrow("EventBus: triggering unknown event 'a'");
|
|
||||||
expect(() => bus_empty!.dispatchEvent(new CustomEvent("a"))).toThrow(
|
|
||||||
"EventBus: dispatching unknown event 'a'"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("batched", () => {
|
describe("batched", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user