[FIX] web: useChildRef: handle conditional children
The useChildRef (used with the useForwardRefToParent hook) allows to retrieve, from a parent component, a t-ref from a child. Consider the following scenario: - have a parent calling useChildRef - have a conditional (with t-if) child calling useForwardRefToParent - in the initial rendering, the child is displayed -> ref.el points to the correct html element - re-render s.t. the child is no longer displayed -> ref.el is null, because the referenced element doesn't exist - re-render s.t. the child is displayed again Before this commit, at this point, ref.el will always be null, even though the corresponding element comes back into the DOM. This commit fixes the issue by correctly updating the ref, each time the useForwardRefToParent hook is called. closes odoo/odoo#100937 X-original-commit: 78d39c79993d1d63c189164f8104e5a3c90f2efd Signed-off-by: Géry Debongnie <ged@odoo.com> Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -216,7 +216,9 @@ export function useService(serviceName) {
|
||||
*/
|
||||
export function useChildRef() {
|
||||
let defined = false;
|
||||
return function ref(value) {
|
||||
let value;
|
||||
return function ref(v) {
|
||||
value = v;
|
||||
if (defined) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { uiService } from "@web/core/ui/ui_service";
|
||||
import { useAutofocus, useBus, useListener, useService } from "@web/core/utils/hooks";
|
||||
import { useAutofocus, useBus, useChildRef, useForwardRefToParent, useListener, useService } from "@web/core/utils/hooks";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { makeTestEnv } from "@web/../tests/helpers/mock_env";
|
||||
import {
|
||||
@@ -423,5 +423,68 @@ QUnit.module("utils", () => {
|
||||
assert.rejects(comp.functionService.call("boundThis"), "Component is destroyed");
|
||||
assert.strictEqual(nbCalls, 8);
|
||||
});
|
||||
|
||||
QUnit.module("useChildRef / useForwardRefToParent");
|
||||
|
||||
QUnit.test("simple usecase", async function (assert) {
|
||||
let childRef;
|
||||
let parentRef;
|
||||
class Child extends Component {
|
||||
setup() {
|
||||
childRef = useForwardRefToParent("someRef");
|
||||
}
|
||||
}
|
||||
Child.template = xml`<span t-ref="someRef" class="my_span">Hello</span>`;
|
||||
class Parent extends Component {
|
||||
setup() {
|
||||
this.someRef = useChildRef();
|
||||
parentRef = this.someRef;
|
||||
}
|
||||
}
|
||||
Parent.template = xml`<div><Child someRef="someRef"/></div>`;
|
||||
Parent.components = { Child };
|
||||
|
||||
const env = await makeTestEnv();
|
||||
const target = getFixture();
|
||||
|
||||
await mount(Parent, target, { env });
|
||||
assert.strictEqual(childRef.el, target.querySelector(".my_span"));
|
||||
assert.strictEqual(parentRef.el, target.querySelector(".my_span"));
|
||||
});
|
||||
|
||||
QUnit.test("useForwardRefToParent in a conditional child", async function (assert) {
|
||||
class Child extends Component {
|
||||
setup() {
|
||||
useForwardRefToParent("someRef");
|
||||
}
|
||||
}
|
||||
Child.template = xml`<span t-ref="someRef" class="my_span">Hello</span>`;
|
||||
class Parent extends Component {
|
||||
setup() {
|
||||
this.someRef = useChildRef();
|
||||
this.state = useState({ hasChild: true });
|
||||
}
|
||||
}
|
||||
Parent.template = xml`<div><Child t-if="state.hasChild" someRef="someRef"/></div>`;
|
||||
Parent.components = { Child };
|
||||
|
||||
const env = await makeTestEnv();
|
||||
const target = getFixture();
|
||||
|
||||
const parent = await mount(Parent, target, { env });
|
||||
assert.containsOnce(target, ".my_span");
|
||||
assert.strictEqual(parent.someRef.el, target.querySelector(".my_span"));
|
||||
|
||||
parent.state.hasChild = false;
|
||||
await nextTick();
|
||||
|
||||
assert.containsNone(target, ".my_span");
|
||||
assert.strictEqual(parent.someRef.el, null);
|
||||
|
||||
parent.state.hasChild = true;
|
||||
await nextTick();
|
||||
assert.containsOnce(target, ".my_span");
|
||||
assert.strictEqual(parent.someRef.el, target.querySelector(".my_span"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user