当前位置: 首页 > news >正文

Odoo 自定义Widgets 基础教程(章节2)

大家好,

在上一章节的教程中,我们讲了Odoo Widget 【挂件】的基础。包括,基础方法和他们的用途。这一节,我们要做的事情,是学会如何应用这些方法到实际使用当中。

首先,我们都知道在编写odoo 的视图xml时,通过在字段中,添加 widget 标签属性即可渲染出相对应的视图。

例如: 时间挂件 ,可以将时间字段渲染成如图所示的效果。

<field name="myfield" widget="timedate"/>

image

那我们就来具体阐述一下,这个时间挂件所实现的机制和代码编写逻辑。

# 步骤一:
我们需要新建一个模块,命名它为timepicker。文件结构目录如下:【可以用scaffold先创建一个骨架,再进行修改】
image

# 步骤二:
修改 _manifest_.py,添加相关依赖。
image

# 步骤三:

我们来看看widget.js
同所有 widget 一样,第一步定义:

odoo.define('web_widget_timepicker', function (require) {
            "use strict";

 var core = require('web.core');
 //web.core是引用web包的core包
           
 var formats = require('web.formats'); 
 //引用web 包中的formats,odoo的js中预制了一部分formats,提供给大家使用

 var common = require('web.form_common');
//引用web 包中的common类,一些基础方法的引用

# 步骤四:定义widgets:

varTimeDateField = common.AbstractField.extend(common.ReinitializeFieldMixin, {

        //这里的ReinitializeFieldMixin 是最基础的挂件Mixin【其实就是类,js版本的类换汤不换药】

is_field_number: true,

//不做解释,一看就懂

template: "TimeDateField",

// 调用TimeDateField ,它被定义于 image

internal_format: 'float_time',

//不做解释,一看就懂

widget_class: 'o_form_field_time',

//此项,在模块中的/src/css里面定义
image

events: {

        'change input': 'store_dom_value', // store_dom_value 被定义在下方
    },   

//事件,是事件选择器(事件名称和由空间分隔的CSS选择器)映射到回调的方法上。回调既可以是控件中的方法名,也可以是函数。一般是指在发生事件的时候,会触发动作。
// 常见的事件还有 'click p.oe_some_class a': 'some_method',

init: function (field_manager, node) {

this._super(field_manager, node);

// field_manager是用来抓取用户输入值的方法,被定义在web.core里面。因为我们的挂件会修改此方法,将输入从原始的录入变为选填。

this.internal_set_value(0);

//如果,没有值,则设置为0

this.options = _.defaults(this.options, {
                step: 15,
                selectOnBlur: true,
                timeFormat: 'H:i',
                scrollDefault: 'now',
            });  },

// 一些基本设置,提交给jQuery用的,在initialize_content 中被调用

initialize_content: function() {
            if(!this.get("effective_readonly")) {
                this.$el.find('input').timepicker(this.options);
                this.setupFocus(this.$('input'));
            }
        },

// 初始化内容,对本实例中的el(元素)执行.timepicker方法,并带入options

is_syntax_valid: function() {
            if (!this.get("effective_readonly") && this.$("input").size() > 0) {
                try {
                    this.parse_value(this.$('input').val(), '');
                    return true;
                } catch(e) {
                    return false;
                }
            }
            return true;
        },
is_false: function() {
           return this.get('value') === '' || this._super();
       },

//检查,是否有填写错误

focus: function() {
            var input = this.$('input:first')[0];
            return input ? input.focus() : false;
        },

//焦点事件,只有当点击为焦点后才执行

set_dimensions: function (height, width) {
           this._super(height, width);
           this.$('input').css({
               height: height,
               width: width
           });
       },

//设置输入框的宽度和高度

store_dom_value: function () {
            if (!this.get('effective_readonly')) {
                this.internal_set_value(
                    this.parse_value(
                        this.$('input').val(), ''));
            }
        },

//保存用户在前端所选择的数据至数据库中

parse_value: function(val, def) {
            return formats.parse_value(val, {"widget": this.internal_format}, def);
        },

//解析填写进入的数据,在store_dom_value前会调用此方法,以免存的数据格式错误或者其他问题

format_value: function(val, def) {
            return formats.format_value(val, {"widget": this.internal_format}, def);
        },

//重新格式化内部出现的数据,在render_value 渲染数据前,需要先调用此方法,避免

render_value: function() {
  var show_value = this.format_value(this.get('value'), '');

   if (!this.get("effective_readonly")) {
                this.$input = this.$el.find('input');
                this.$input.val(show_value);
            } else {
                this.$(".o_form_time_content").text(show_value);
            }
        },
    });

//渲染最终数据

core.form_widget_registry.add('timepicker', TimeDateField);

// 将'timepicker' 注册到 widget_registry中(挂件注册表)

return {
      TimeDateField: TimeDateField,
  };

相关文章:

  • 线程、对称多处理和微内核(OS 笔记三)
  • js中写文档write和innerHTML的区别
  • React 16 Jest ES6 Class Mocks(使用ES6语法类的模拟) 实例二
  • 拉格朗日乘子
  • FE协同中流程无法提交
  • 《大道至简》读后感
  • mui集成微信H5支付(返回白屏问题已经解决)
  • JVM学习笔记二:内存结构规范
  • React Native中获取屏幕的宽高、分辨率
  • POI技术
  • 微信公众号之模板消息使用
  • Windows Unity ARKit发布到IOS相关设置及错误解决
  • Spring配置补充
  • 基于 HTML5 结合互联网+ 的 3D 隧道
  • Ligowave无线网桥15级手拉手链路设计及稳定性保障
  • python3.6+scrapy+mysql 爬虫实战
  • 2017 前端面试准备 - 收藏集 - 掘金
  • css的样式优先级
  • IDEA常用插件整理
  • JavaScript异步流程控制的前世今生
  • Joomla 2.x, 3.x useful code cheatsheet
  • Js基础知识(一) - 变量
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 利用jquery编写加法运算验证码
  • 普通函数和构造函数的区别
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • #QT(智能家居界面-界面切换)
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (arch)linux 转换文件编码格式
  • (C)一些题4
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (JS基础)String 类型
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (附源码)计算机毕业设计大学生兼职系统
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转)平衡树
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • :“Failed to access IIS metabase”解决方法
  • [ SNOI 2013 ] Quare
  • [ 云计算 | AWS 实践 ] 基于 Amazon S3 协议搭建个人云存储服务
  • [2018][note]用于超快偏振开关和动态光束分裂的all-optical有源THz超表——
  • [CTF]php is_numeric绕过
  • [DL]深度学习_Feature Pyramid Network
  • [HNCTF 2022 WEEK2]easy_include 文件包含遇上nginx
  • [JavaEE] 线程与进程的区别详解
  • [json]定义、读写
  • [LeetCode] 2.两数相加
  • [LeetCode]-225. 用队列实现栈