| 免费下载:IBM® Cognos® Express V9.5 或者 Cognos® 8 Business Intelligence Developer Edition V8.4 试用版 |
|---|
| 下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。 |
本文档将介绍实现自动级联值提示而不用刷新页面的技术。
本技术已经在 IBM Cognos 8.2、IBM Cognos 8.4.0、IBM Cognos 8.4.1 和 IBM Cognos 10.1 Report Studio 版本中进行测试。本技术已经通用 JavaScript 实现。
本技术在 Internet Explorer 5.0 及以上版本中运行正常。在 Firefox 中不可用。
报表应用程序通常需要使用提示值级联,以限制数据范围并降低报表输出中获取不到数据的机率。本地的 IBM Cognos 函数提供了 ‘单选值提示’ 或 ‘多选值提示的重新提示按钮’ 的自动级联功能,该功能在每次选择提示时,都会刷新整个提示选择页。因此,如果提示的数目很多,那么这种整个页面刷新的方法就会非常耗时,而且会令终端用户反感。
- 在需要级联的提示页中加上选定的值提示。在本示例中,添加了Product Line、Product Type 和 Product Name 提示。Product Type 根据 Product Line 级联,Product Name 根据 Product Line 和 Product Type 级联。每个提示框都有自己的查询。
带有 Product Line、Product Type 和 Product Name 的 Report Studio 提示页
- 为每个提示命名。在本示例中,Prompt Names 以 “PN_” 开始。给每个提示赋予惟一的名称,这对于使用 JavaScript 访问这些提示是至关重要的。将 Product Line 提示命名为 PN_ProductLine,将 Product Type 命名为 PN_ProductType,并将 Product Name 命名为 PN_Product。在 Value Prompt 属性中的 Miscellaneous → Name 下输入名称。
- 创建一个新的查询,该查询要包含所有提示查询条目的连接值。在本示例中,已创建了一个 Q_Prompt 查询,该查询包含了一个名为 “Concat String” 的新数据项表达式 (Data Item Expression),该表达式会将三个提示值连接成字符串。请确保在连接字符串时,每个值之间使用的是不同的标识符。
表达式如下所示:'!'|| [gosales_goretailers].[Products].[Product line] || '~'|| [gosales_goretailers].[Products].[Product type] || '#' || [gosales_goretailers].[Products].[Product name] || '^'
数据项表达式窗口
注意:如果使用和显示的值不同,那么应使用显示值进行连接。 - 在提示页面,在提示后插入一个 HTML 项,在本例中将它称为 ‘fW Script’,然后插入以下代码:
<script> var fW = (typeof getFormWarpRequest == "function" ?getFormWarpRequest() : document.forms["formWarpRequest"]); if ( !fW || fW == undefined) { fW = ( formWarpRequest_THIS_ ?formWarpRequest_THIS_ : formWarpRequest_NS_ );} </script> - 在提示页中,在第一个 HTML 项后再插入一个 HTML 项。将它称为 ‘GetAllPromptNames’,然后插入以下代码:
<script> //------------------------------------get All Prompt Names---------------------- function getAllPromptNames() { var aPromptNames = new Array(); for (var i in window) { if ( (""+i).match(/^listBox/) ) { var sName = i.replace( /^listBox/, "" ); aPromptNames.push (sName); } else if ( (""+i).match(/^radioList/) ){ var sName = i; aPromptNames.push (sName); } else if ( (""+i).match(/^checkBoxList/) ){ var sName = i; aPromptNames.push (sName); } } return aPromptNames; //-----------------------------------to avoid Memory Leak---- i=null; sName=null } //------------------------------------get All Prompt Names---------------------- // hiding select All/deselect All for(j=0;j<document.links.length;j++) { y=document.links[j]; if (y.id.indexOf("SELECT") != -1) document.getElementById(y.id).style.display='None'; } </script>
- 在提示页,在之前插入的 HTML 项之后插入第三段 HTML 项,然后插入以下代码:
<script> String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g,""); } fW._oLstChoicesPN_ProductLine.onchange = function () {cascadePrompts("ProductLine","ProductType,Product")}; fW._oLstChoicesPN_ProductType.onchange = function () {cascadePrompts("ProductType","Product")}; //Check if the prompts being cascaded are present // on page or removed as per report requirement function validatePrompts(removearr) { promptsonpage=getAllPromptNames(); var flag ; newarr = new Array(); var i=0; for(var j =0 ; j < removearr.length ; j++ ) { flag = false; for (var jj =0 ; jj < promptsonpage.length ; jj++ ){ if(("PN_"+removearr[j])==promptsonpage[jj]) { flag=true; break; } } if(flag==true ) { newarr[i]=removearr[j]; i++; } } return newarr; } //calls all the functions required for cascadeing // prompt:Listprompt on which has the values to filter the child prompts //remove:Child prompts on which the cascading is supposed to be performed function cascadePrompts(prompt,remove){ removearr = new Array(); removearr = remove.split(","); newarray=validatePrompts(removearr); emptyList(newarray); createList(prompt,newarray); } //Empty child prompts before you insert new filtered values function emptyList(arr){ for (var jj =0 ; jj < arr.length ; jj++ ){ fW["_oLstChoicesPN_"+arr[jj]].selectedIndex = -1; fW["_oLstChoicesPN_"+arr[jj]].length = 0; } //------------------to avoid memory leak----- arr=null; } //creates the filter array function createList(prompt,newarr) { var len2 = fW["_oLstChoicesPN_"+prompt].length; arrfilter = new Array(); var idx = 0; for (var j = 0 ; j < len2; j++){ if (fW["_oLstChoicesPN_"+prompt][j].selected == true){ arrfilter[idx] = fW["_oLstChoicesPN_"+prompt][j].value; idx++; } } for (var jj =0 ; jj < newarr.length ; jj++ ) { createListFilter(prompt,newarr[jj],arrfilter); } //------------------to avoid memory leak----- arrfilter=null; newarr = null; } function createParentFilter(prompt) { var len2 = fW["_oLstChoicesPN_" + prompt].length; var filter = new Array(); var idx = 0; for (var j = 0 ; j < len2; j++){ if (fW["_oLstChoicesPN_"+prompt][j].selected == true){ filter[idx] = fW["_oLstChoicesPN_"+ prompt][j].value; idx++; } } return filter; } function checkParentFilter(string,fltr,flg) { for(var k=0;k<fltr.length;k++) { if(fltr[k]!="All" && flg){ if(string.match(fltr[k])) { return true; } } else { return flg;} }if(fltr.length==0) {return true;} flg=false; return flg; } function createListFilter(filterlevel,filtervalues,filter){ var parFiltersStr= "ProductLine,ProductType"; parentarr = new Array(); parentarr = parFiltersStr.split(","); newParentArr = validatePrompts(parentarr); parentFilterStr=newParentArr.join(); ProductLinefilter= new Array(); if(parentFilterStr.match("ProductLine")){ ProductLinefilter=createParentFilter("ProductLine"); } else{ ProductLinefilter[0]="All" } //-------------------------Product Line filters--- ProductTypefilter = new Array(); if(parentFilterStr.match("ProductType")){ ProductTypefilter =createParentFilter("ProductType"); } else{ ProductTypefilter[0]="All" } //-------------------------Product Type filters--- var fd; var sd; var td; var frd; var tdidx = 0; var fdidx = 0; var sdidx; var frdidx; arr = new Array (); if (filterlevel == "ProductLine"){ fd = "!"; sd = "~"; } if (filterlevel == "ProductType"){ fd = "~"; sd = "#"; } if (filterlevel == "Product"){ fd = "#"; sd = "^"; } // ----------------------------------filter Values------------------------------ if (filtervalues == "ProductLine"){ td = "!"; frd = "~"; } if (filtervalues == "ProductType"){ td = "~"; frd = "#"; } if (filtervalues == "Product"){ td = "#"; frd = "^"; } var len = fW._oLstChoicesPN_ConcatString.length; for (var idx= 0 ; idx < filter.length ; idx++){ for(var i = 0 ; i < len ; i++){ var string2 = fW._oLstChoicesPN_ConcatString[i].value; fdidx = string2.indexOf(fd); sdidx = string2.indexOf(sd); tdidx = string2.indexOf(td); frdidx = string2.indexOf(frd); var string3 = string2.substring(fdidx+1,sdidx); if (filter[idx] != "All"){ if ( string3.trim() == filter[idx].trim() ){ var flag=true; flag=checkParentFilter(string2,ProductLinefilter,flag); flag=checkParentFilter(string2,ProductTypefilter,flag); if(flag) { arr[i] = string2.substring(tdidx+1,frdidx); } } } else { var flag=true; flag=checkParentFilter(string2,ProductLinefilter,flag); flag=checkParentFilter(string2,ProductTypefilter,flag); if(flag) { arr[i] = string2.substring(tdidx+1,frdidx); } } } } arr = uniqueVal(arr); filtervalues = "_oLstChoicesPN_"+filtervalues; for (var j=0 ; j < arr.length ; j++){ if (arr[j] != undefined && arr[j] !=null && arr[j] != ""){ var elOptNew = document.createElement('option'); elOptNew.text = arr[j]; elOptNew.value = arr[j]; fW[filtervalues].add(elOptNew); } } //------------------to avoid memory leak----- arr=null; regionfilter=null; countryfilter=null; filter=null; string2=null; } function uniqueVal(oldarr){ oldarr.sort();j=0; newarr= new Array() for(var i=0;i<oldarr.length;i++){ newarr[j]=oldarr[i];j++; if((i>0)&&(oldarr[i]==oldarr[i-1])){ newarr.pop();j-- } } return newarr; } </script>
在代码样例中,该 HTML 项被称为 ‘Cascading Prompts’。这段代码包含了不刷新页面自动实现提示值级联的逻辑。
Report Studio Prompt 页面:其中在 Product Line、Product Type 和 Product Name 提示下方显示脚本对象
- 现在转到报表页面的第一页并创建一个显示订单方法和生产成本的柱形图。创建三个对 Product Line、Product Type 和 Product Name 进行过滤的过滤项。例如:
- [Sales (query)].[Product].[Product line] in ?P_ProductLine?
- [Sales (query)].[Product].[Product line] in ?P_ProductLine?
- [Sales (query)].[Product].[Product name] in ?P_Product?
- 保存报表。
- 在 ‘Cascading Prompts’ HTML 项代码中,需要为新的提示添加 ‘onchange’ 事件,并需要为该提示传递子提示的名称。
- 需要为提示的每个层次修改 parFiltersStr 变量。同样还需要创建新的数组。
- 还需要对隐藏提示使用哪个级联功能的查询(当前示例中使用的是 Q_Prompt)进行修改。还需要在查询中添加一列,并加上分隔符。还需要按照查询中定义的分隔符修改/添加 if 条件句中的过滤级和过滤值。
- 还需要添加检查父提示值的情形,如代码 “flag=checkParentFilter(string2,ProductLinefilter,flag);” 所示。
以下是关于本技术如何节省时间的示例。一家公司采用 Cognos 8.4.0 生成 200 多张运营报表,该方法支撑了全球 700 多个活跃用户。通过使用 Cognos 8 开箱即用的功能,‘找不到数据’ 的情况出现得越来越多,由于要多次重新运行报表以获得更多数据,或等待提示重新检索数据显示给用户,从而影响了用户生产力。
通过本文的方法,平均每个用户每张报表节省了一分钟的执行时间。因此,如果每个用户每天运行报表 5 次(700*5)(用户数*执行报表节约的时间),那么每天会提高 3500 分钟生产力。
这只是个示例,具体的结果取决于报表数、返回的数据量和用户数,等等。
学习
- 通过 developerWorks Information Management 专区:在这里可以学到更多关于 Information Management 的知识。还可以找到技术文档、how-to 文章、培训、下载、产品信息等。
- 通过 Information Management 专区 Cognos BI 专题,了解更多有关 Cognos BI 专题的产品和技术资源。
- 通过 多媒体课堂:体验魅力 Cognos BI 10 系列,了解最新 Cognos BI 10 的最新特性和相关技术,并介绍了 Cognos 商业智能报表开发的技术细节。
- 随时关注 developerWorks 技术活动 和 网络广播。
获得产品和技术
- 在线试用 IBM Cognos BI 试用版软件,了解 IBM Cognos BI 商业智能解决方案的最新版本新功能。
- 下载 IBM Cognos Express V9 试用版软件,了解 IBM 专为中型企业定制的集成商业智能和计划解决方案。
讨论
- 参与 developerWorks
博客 并加入 developerWorks 中文社区,developerWorks 社区是一个面向全球 IT 专业人员,可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。