如何将RPC响应数据在继承模板中正确展示?
问题:Odoo中RPC获取用户数据后模板无法渲染显示
我尝试通过RPC获取当前用户数据并在列表视图按钮模板中展示,JS代码能在控制台输出预期数据,但模板里的widget.user始终为空。
我的实现代码
JS部分:
var session = require('web.session'); var rpc = require('web.rpc'); var ListController = require('web.ListController'); ListController.include({ renderButtons: function($node) { this._super.apply(this, arguments); rpc.query({ model: 'res.users', method: 'search_read', args: [ [['id','=',session.uid]], ['id','name','login'], ], }).then(res => { this.user = res[0]; console.log(this); // 曾尝试把_super移到这里,结果出现随机错误 }); }, });
XML模板部分:
<?xml version="1.0" encoding="UTF-8"?> <template xml:space="preserve"> <t t-extend="ListView.buttons"> <t t-jquery="button.o_list_button_add" t-operation="replace"> <button class="btn btn-primary o_list_button_add" type="button">Create</button> <span t-esc="widget.user"/> </t> </t> </template>
问题原因
- RPC请求是异步操作,
renderButtons执行完_super就直接渲染模板了,此时this.user还未被赋值,所以模板里拿不到数据。 - 不能把
_super移到then回调里,因为_super是负责渲染初始按钮DOM的核心逻辑,延迟调用会破坏视图初始化流程,导致各种未知错误。
解决方法
方法1:重新渲染按钮区域(推荐)
在获取到用户数据后,重新调用renderButtons更新DOM,同时要先保存初始的$node:
var session = require('web.session'); var rpc = require('web.rpc'); var ListController = require('web.ListController'); ListController.include({ renderButtons: function($node) { // 保存节点引用,用于后续重新渲染 this.buttonNode = $node; this._super.apply(this, arguments); // 初始化user避免模板报错 if (!this.user) { rpc.query({ model: 'res.users', method: 'search_read', args: [ [['id','=',session.uid]], ['id','name','login'], ], }).then(res => { this.user = res[0]; // 重新渲染按钮,此时user已经有值 this.renderButtons(this.buttonNode); }); } }, });
模板可以优化为处理未加载状态:
<?xml version="1.0" encoding="UTF-8"?> <template xml:space="preserve"> <t t-extend="ListView.buttons"> <t t-jquery="button.o_list_button_add" t-operation="replace"> <button class="btn btn-primary o_list_button_add" type="button">Create</button> <span t-if="widget.user" t-esc="widget.user.name"/> <span t-else>Loading...</span> </t> </t> </template>
方法2:直接更新DOM元素(更高效)
如果不想重新渲染整个按钮区域,可以在获取数据后直接找到对应元素修改内容:
var session = require('web.session'); var rpc = require('web.rpc'); var ListController = require('web.ListController'); ListController.include({ renderButtons: function($node) { this._super.apply(this, arguments); rpc.query({ model: 'res.users', method: 'search_read', args: [ [['id','=',session.uid]], ['id','name','login'], ], }).then(res => { this.user = res[0]; // 直接找到模板里的span元素赋值 this.$('.o_list_button_add').next('span').text(this.user.name); }); }, });
这种方式不需要重新渲染,性能更好,适合只更新局部内容的场景。
内容的提问来源于stack exchange,提问作者holydragon
相关产品推荐
相关产品推荐

