多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## Data组件基础02:规则、数据遍历查找 **一、Data组件的规则** Data组件提供了规则执行的机制,在data上可以定义:计算、只读、必填、约束等规则,规则都是以表达式的形式给出,表达式计算结果为true时只读、必填生效,约束表达式计算结果=true时数据有效 Data只读上下文包括: $model : 前端model对象 $data : data组件对象 表达式上下文包括: $model : 前端model对象 $data : data组件对象 $row : 计算的行对象 $rowID : 计算的行ID $col : 列名 注:对于整个data只有只读的规则,必填和约束规则只有数据进行修改后才会触发 [![rule](https://box.kancloud.cn/2015-09-23_560181fe09e7a.png)](https://box.kancloud.cn/2015-09-23_560181fe09e7a.png) <rule> <!-- 整个data只读 --> <readonly <expr >true</expr> </readonly> <!-- fString列必须有值 --> <col name="fString"> <required> <expr>true</expr> <message>请填写fString</message> </required> </col> <!-- fInteger必须大于50 --> <col name="fInteger"> <constraint> <expr>val('fInteger')&gt;50</expr> <message>Integer必须大于50</message> </constraint> </col> <!-- fDecimal只读并且是slaveData的fDecimal列合计 --> <col name="fDecimal"> <readonly> <expr>true</expr> </readonly> <calculate> <!-- 计算规则在data组件创建时就开始计算, 这时有可能使用到的data还没有创建 所以增加"$model.slaveData?..."的判断 --> <expr>$model.slaveData?$model.slaveData.sum('fDecimal',$row):0</expr> </calculate> </col> </rule> Data组件的约束规则其实是提供了扩展能力的(如:email等),有兴趣的可以研究一下“/UI2/system/components/justep/data/js/rules.js” 后续的进阶篇中会作介绍 **二、数据遍历和查找** Data组件数据遍历方式有两种,一种使用游标滚动方式,另一种使用Data.each()函数。 下面详细介绍这两种方式的差异和使用方式 游标滚动方式,这种方式由于刺激了当前行的变化,所有绑定当前行的数据感知组件都会进行变化渲染 相关API: Data.getFirstRow();——-获取第一行 Data.getLastRow();——–获取最后一行 Data.next();————–游标移动到下一行 Data.pre();—————游标移动到上一行 Data.first();————–游标移动到第一行 Data.last();—————游标移动到最后一行 Data.to(row);————-游标移动到指定行 全数据游标滚动数据遍历代码实例: var data = this.comp('fruitData'); var lRow = data.getLastRow(), row, names = []; data.first(); do { row = data.getCurrentRow(); names.push(data.val('fName')); data.next(); } while (lRow != row); alert(names); Data.each(callback)遍历,这种方式不刺激游标变化,不刺激感知组件更新,性能比游标方式高很多 Data.each(callback)函数参数callback是遍历的回调函数,执行时给定的this是行对象 callback = function(param){ param.data;//遍历的data对象 param.row;//遍历到的行对象 param.index;//行的索引 param.cancel;//是否结束遍历,当修改cancel为true时结束遍历 } 全数据each遍历代码实例: var data = this.comp('fruitData'); var names = []; data.each(function(param){ names.push(param.row.val('fName')); }); alert(names); Data组件上还提供了一个函数eachAll,这个函数主要用于遍历从Data所有数据,在主从情况下的从Data上使用each遍历数据行只能遍历到和当前主数据相关的从数据行,eachAll的使用和each一致这里就不再介绍了。 关于数据查找Data组件提供了find函数来支持 find函数参数: cols:列名列表 values:值列表 first: 是否只是返回第一条,即查找到第一条符合条件的数据就返回,默认值:false caseInsensitive: 匹配时忽略大小写,默认值:false partialKey: 模糊匹配,即数据中包含需要匹配字符就算匹配成功,默认值:false all: data所有数据查找,当是从Data时all==false只查找和主关联的行数据,默认值:false find函数根据cols和values匹配查找返回符合行数组,当没有匹配数据时返回[]数组,如:cols=[‘fName’],value=[‘苹果’]查找的就是Row.val(‘fName’)===’苹果’的行 数据查找代码实例: //查找fID中包含"E"或者"e"的第一条数据 var rows = this.comp('fruitData').find(['fID'],['e'],true,true,true); if(rows.length<=0) alert('没有符合条件数据'); else alert(rows[0].val('fName')); //查找fName="苹果",fWeight=100的数据 var rows = this.comp('fruitData').find(['fName','fWeight'],['苹果',100]); if(rows.length==0) alert('没有符合条件数据'); 当有其他数据查找需求时可以使用each函数实现 **三、聚合运算** Data组件上提供了常用的统计函数,count、sum、avg、min、max这些函数都是基于前端data数据的,没有加载到前端data中的数据不包括在计算中,注:返回的数值精度受js的number精度影响 这些函数使用都很简单,所有函数上都有一个filterCallback参数,可以传入过滤数据的回调方法,filterCallback需要返回boolean,为true时行有效,回调函数给出参数event,{‘data':data对象,row:行},当没有给出filterCallback参数时统计data的全部数据 前端统计函数代码实例: //统计mainData中记录数 var count = this.comp('mainData').count(); //统计mainData中fName姓“李”的记录数 var count = this.comp('mainData').count(function(ev){ var v = ev.data.getValue('fName',ev.row); return v.indexOf('李')==0; }); //统计mainData中年龄fAge合计 var sum = this.comp('mainData').sum('fAge'); //统计mainData中fName姓“李”的年龄fAge合计 var sum = this.comp('mainData').sum('fAge',function(ev){ var v = ev.data.getValue('fName',ev.row); return v.indexOf('李')==0; }); //统计mainData中年龄fAge平均值 var avg = this.comp('mainData').avg('fAge'); //统计mainData中fName姓“李”的年龄fAge平均值 var avg = this.comp('mainData').avg('fAge',function(ev){ var v = ev.data.getValue('fName',ev.row); return v.indexOf('李')==0; }); //统计mainData中年龄fAge最小值 var min = this.comp('mainData').min('fAge'); //统计mainData中fName姓“李”的年龄fAge最小值 var avg = this.comp('mainData').min('fAge',function(ev){ var v = ev.data.getValue('fName',ev.row); return v.indexOf('李')==0; }); //统计mainData中年龄fAge最大值 var min = this.comp('mainData').max('fAge'); //统计mainData中fName姓“李”的年龄fAge最大值 var avg = this.comp('mainData').max('fAge',function(ev){ var v = ev.data.getValue('fName',ev.row); return v.indexOf('李')==0; }); 除了前端的统计函数,Data组件也支持有后端提供统计结果,通过Data组件刷新时返回后端统计结果,统计值使用userdata方式返回(关于userdata将在第四节介绍) data组件提供Data.getAggregateValue(name)获取后端返回统计值,name为统计值定义的名称 案例展示(DataTables组件footer显示前后台统计结果,注意:案例中使用的是BizData) [![3](https://box.kancloud.cn/2015-09-23_560181fe69911.png)](https://box.kancloud.cn/2015-09-23_560181fe69911.png)[![count2](https://box.kancloud.cn/2015-09-23_560181feca6cf.png)](https://box.kancloud.cn/2015-09-23_560181feca6cf.png)[![sum1](https://box.kancloud.cn/2015-09-23_560181ff37a93.png)](https://box.kancloud.cn/2015-09-23_560181ff37a93.png) 运行效果: [![4](https://box.kancloud.cn/2015-09-23_560181ff94942.png)](https://box.kancloud.cn/2015-09-23_560181ff94942.png) **四、扩展数据** Data组件不光可以加载行列数据,同时也提供了加载扩展数据的能力,这就是data组件userdada扩展数据的机制。在data组件加载的数据上增加userdata数据, json数据格式如下: { "@type" : "table", "rows" : [...], "userdata" : { "DEMO_TABLE1Count" : 148 } } 同时提供了相关的API: Data.getUserData(name,row);—————-获取扩展数据,name为扩展数据的名称,row为指定的行,当没有指定row时为data的扩展数据 Data.setUserData(name,value,row);———-设置扩展数据 上面介绍的后端统计就是通过这个机制实现的