diff --git a/addons/web/static/src/core/network/rpc_service.js b/addons/web/static/src/core/network/rpc_service.js index f898c75dc8d..e85c4f2ae70 100644 --- a/addons/web/static/src/core/network/rpc_service.js +++ b/addons/web/static/src/core/network/rpc_service.js @@ -99,11 +99,20 @@ export function jsonrpc(env, rpcId, url, params, settings = {}) { request.setRequestHeader("Content-Type", "application/json"); request.send(JSON.stringify(data)); }); - promise.abort = function () { + /** + * @param {Boolean} rejectError Returns an error if true. Allows you to cancel + * ignored rpc's in order to unblock the ui and not display an error. + */ + promise.abort = function (rejectError = true) { if (request.abort) { request.abort(); } - rejectFn(new ConnectionAbortedError("XmlHttpRequestError abort")); + if (!settings.silent) { + bus.trigger("RPC:RESPONSE", data.id); + } + if (rejectError) { + rejectFn(new ConnectionAbortedError("XmlHttpRequestError abort")); + } }; return promise; } diff --git a/addons/web/static/src/core/utils/hooks.js b/addons/web/static/src/core/utils/hooks.js index 078bc4caf62..548581aa056 100644 --- a/addons/web/static/src/core/utils/hooks.js +++ b/addons/web/static/src/core/utils/hooks.js @@ -164,14 +164,20 @@ export function useListener(eventName, querySelector, handler, options = {}) { // ----------------------------------------------------------------------------- // useService // ----------------------------------------------------------------------------- - function _protectMethod(component, fn) { - return async function (...args) { + return function (...args) { if (status(component) === "destroyed") { - throw new Error("Component is destroyed"); + return Promise.reject(new Error("Component is destroyed")); } - const result = await fn.call(this, ...args); - return status(component) === "destroyed" ? new Promise(() => {}) : result; + + const prom = Promise.resolve(fn.call(this, ...args)); + const protectedProm = prom.then((result) => + status(component) === "destroyed" ? new Promise(() => {}) : result + ); + return Object.assign(protectedProm, { + abort: prom.abort, + cancel: prom.cancel, + }); }; } diff --git a/addons/web/static/src/views/fields/relational_utils.js b/addons/web/static/src/views/fields/relational_utils.js index 8376039509b..fc89730b97e 100644 --- a/addons/web/static/src/views/fields/relational_utils.js +++ b/addons/web/static/src/views/fields/relational_utils.js @@ -213,13 +213,17 @@ export class Many2XAutocomplete extends Component { } async loadOptionsSource(request) { - const records = await this.orm.call(this.props.resModel, "name_search", [], { + if (this.lastProm) { + this.lastProm.abort(false); + } + this.lastProm = this.orm.call(this.props.resModel, "name_search", [], { name: request, operator: "ilike", args: this.props.getDomain(), limit: this.props.searchLimit + 1, context: this.props.context, }); + const records = await this.lastProm; const options = records.map((result) => ({ value: result[0], diff --git a/addons/web/static/tests/core/network/rpc_service_tests.js b/addons/web/static/tests/core/network/rpc_service_tests.js index 364f35790aa..19152acfd15 100644 --- a/addons/web/static/tests/core/network/rpc_service_tests.js +++ b/addons/web/static/tests/core/network/rpc_service_tests.js @@ -247,10 +247,17 @@ QUnit.test("check connection aborted", async (assert) => { const MockXHR = makeMockXHR({}, () => {}, def); patchWithCleanup(browser, { XMLHttpRequest: MockXHR }, { pure: true }); const env = await makeTestEnv({ serviceRegistry }); + env.bus.addEventListener("RPC:REQUEST", () => { + assert.step("RPC:REQUEST"); + }); + env.bus.addEventListener("RPC:RESPONSE", () => { + assert.step("RPC:RESPONSE"); + }); const connection = env.services.rpc(); connection.abort(); assert.rejects(connection, ConnectionAbortedError); + assert.verifySteps(["RPC:REQUEST", "RPC:RESPONSE"]); }); QUnit.test( diff --git a/addons/web/static/tests/helpers/mock_services.js b/addons/web/static/tests/helpers/mock_services.js index ad5f6923161..e3a890f55e8 100644 --- a/addons/web/static/tests/helpers/mock_services.js +++ b/addons/web/static/tests/helpers/mock_services.js @@ -69,8 +69,11 @@ export function makeFakeRPCService(mockRPC) { .then(resolve) .catch(reject); }); - rpcProm.abort = () => - rejectFn(new ConnectionAbortedError("XmlHttpRequestError abort")); + rpcProm.abort = (rejectError = true) => { + if (rejectError) { + rejectFn(new ConnectionAbortedError("XmlHttpRequestError abort")); + } + }; return rpcProm; }; },