400-888-0545
首页 > 关于我们 > 技术文摘
开源OA办公:使用Promise处理表单异步
发布时间:

      原有表单默认值只能通过同步方法的返回值,在一些需要网络请求才能获取值的情况下(如获取人员组织数据、数据字典等情况),同步请求造成阻塞,降低了页面的响应速度。本文介绍这种情况下的异步处理方式。(本文适用前端脚本)

表单组件的默认值可以返回一个Promise,来实现异步。(5.3及后续版本支持)

可使用异步返回的组件和属性

组件

脚本

文本(Label)

值 (脚本)

文本字段(Textfield)

默认值

数字字段(Number)

默认值

人员组织(Org)

默认值脚本

职务脚本

日期(Calendar)

默认值

多行文本(Textarea)

默认值

下拉框(Select)

默认值

可选值脚本

单选框

默认值

可选值脚本

多选框

默认值

可选值脚本

数据网格

默认值

异步返回服务器时间

表单上创建日期选择组件,并在默认值脚本中使用如下代码:

//true表示异步,此时返回一个Promise
return Date.getFromServer(true);


异步获取组织数据

      脚本中可以通过this.org对象获取组织数据。在以前的版本中,this.org中的方法都是同步的,现在可以使用异步方式获取组织数据。


例一:在表单中创建一个人员组织组件,如要获取创建人所在的第二层组织作为默认值,可在默认值脚本中添加如下代码:

//最后一个参数true表示异步,返回一个Promise
return this.org.getUnitByIdentity(this.workContext.getWork().creatorIdentityDn, 2, true);

例二:假设要获取创建身份所在组织的所有身份数量,作为一个数字字段的值,可以在数字字段的默认值脚本中使用如下代码:

//先获取了创建身份所在的直接组织,再获取此组织的所有身份成员,返回成员的数量,作为数字字段的值。
return this.org.getUnitByIdentity(this.workContext.getWork().creatorIdentityDn, null, function (unit) {
    return this.org.listIdentityWithUnit(unit, false, function (ids) {
        return ids.length;
    });
}.bind(this));

异步获取数据字典

在以前的版本中,this.Dict对象的get方法是同步的,现在可以使用异步方式使用get方法。

例:假设以一个数据字典中的数据作为表单中数据网格的默认值,可以按如下方式进行:

1、创建数据字典如下图:

在表单中设计一个数据网格:

在数据网格默认数据中添加以下脚本:

var dict = new this.Dict("test");
//异步使用数据字典的get方法时返回Promise
return dict.get("tools", true);

通过平台 Actions对象调用服务

通过脚本this.Actions调用平台服务,异步时默认返回Promise,可以作为表单元素的默认值。

例:假设要获取所有内容管理栏目名称作为下拉框的可选列表,可在下拉框可选值脚本中使用以下代码:

return this.Actions.load("x_cms_assemble_control").CategoryInfoAction.listAllCategoryInfo(function(json){
	return json.data.map(function(d){ return d.appName; });
});

通过原生javascript或其他框架发起的异步请求

例一:通过原生js发起异步请求。本例中,发起http请求获取index.html内容,将内容作为一个多行文本的值。可以在多行文本的默认值脚本中使用以下代码:

//返回一个Promise
return new Promise(function(resolve, reject){
  var oReq = new XMLHttpRequest();

  //绑定load事件
	oReq.addEventListener("load", function(){
  	resolve(oReq.responseText);
  });
  
	oReq.open("GET", "index.html");
  oReq.send();
});


例二:通过Jquery发起异步请求,功能和例一相同

//确保jquery已经引入
//返回一个Promise
return new Promise(function(resolve, reject){
  $.get("index.html", function (data) {
    resolve(data);
  });
});

脚本中的其他注意事项

表单组件的getValue方法

1、组件的getValue方法异步处理时会返回一个Promise实例(同步时或异步处理已经完成,返回组件的实际值),通过promise.then(function(value){});方法进行后续处理,或直接通过Promise.resolve(module.getValue()).then(function(value){});来处理。

例:假设表单的人员组件org使用异步函数作为默认值,在表单中的数字组件要使用org组件值的数量作为默认值,可在数字组件的默认值脚本中使用以下代码:

var v = this.form.get("org").getValue();
if (v.then){
    return v.then(function(value){ return value.length; });
}else{
    return v;
}

//或者
var v = this.form.get("org").getValue();
return Promise.resolve(v).then(function(value){
    return value.length;
})

this.data.xxx的getter和setter

通过this.data.xxx赋值时,可通过赋值一个Promise对象,通过this.data.xxx获取业务数据时,可能获取到Promise对象(异步请求正在执行中)。请看下面的代码:

//创建一个Promise对象
var p = new Promise(function(resolve, reject){
  	//载入Jquery
    o2.load("jquery", function(){
      	//防止jquery冲突
        jQuery.noConflict();
				
        var done = function (data) {
            resolve(data); //返回响应的内容
        };
				//发起get请求
        jQuery.get("index.html", done);
    });
});


//将业务数据textarea赋值为promise
this.data.textarea_2 = p;

//此时获取到的值是promise
console.log(this.data.textarea_2);

p.then(function(){
  //此时获取的是textarea中最终存储的值(本例中是index.html的内容)
	console.log(this.data.textarea_2);
}.bind(this));

组件的getData方法

通过组件的getData方法获取的是组件的当前显示值,如果给组件赋值一个Promise对象,在异步执行完成之前,getData获取到的是组件当前的显示值。请看以下代码:

//获取到文本组件
var field = this.form.get("textfield");

this.data.textfield = "oa";
console.log(field.getData());	//输出 oa

//异步获取创建人所在第二层组织,返回Promise对象
var p = this.org.getUnitByIdentity(this.workContext.getWork().creatorIdentityDn, 2, function(unit){
	return unit.name;
});
//给textfield赋值
this.data.textfield = p;

//此时由于异步请求没有执行完毕,getData方法获取到的是原来的值
console.log(field.getData());	//输出 oa

p.then(function(){
  //此时由于异步请求已经执行完毕,getData方法获取到的是组织的名称
	console.log(field.getData());	//输出 组织名称
});