Getting MicroStrategy Data Into Your Control

MicroStrategy provides a very easy to use methodology for wiring controls in Flex to MicroStrategy Data.  They provide a model which represents the Grid that your Widget is ultimately tied to, and most of the out of the box controls can be wired to that widget by basically setting the modelKey=”ModelName”.  Like magic, the component will consume the data and populate itself without you having to write any code.  While this is a convenient trick to building mashups, I don’t think it’s the most common use case.  If I just needed to populate out of the box MicroStrategy controls, I’d just build that in MicroStrategy to begin with.  While there are some scenarios where you’d want to take that back to Flex (say you want to build a composite offline application or you want to integrate some custom graphics or behaviors), I think the majority of cases are that you’ll want to provide MicroStrategy data to your own custom graphics code or extend a 3rd party Widget.  Neither of those are going to know what a modelKey is let alone consume it.  Today I’ll take you through the steps of extracting the MicroStrategy data from the model and feeding it into your control.

A Brief Overview
The MicroStrategy SDK contains some high level documentation for how the flow of data works, but I’ll try to summarize it here.

Basically, MicroStrategy will automatically feed the underlying grid of data to your control in what it calls a Base Model.  If you’re building a Visualization that will sit on top of a Grid, then it’s the grid of data (not including report objects, only what’s displayed).  If you’re building a Widget to be used in a Document, then it will be the Grid you’re tying it to.  If you are building a Visualization that will be applied to a whole Document, then you could have multiple Base Models.

The Base Model is the entry into your control, but not what you’ll be referencing directly.  From here, you create Derived Models, which are the same idea as a Report Template compared to Report Objects.  A Derived Model will most commonly pull back everything from the Base Model, but you can create multiple Derived Models from a single Base Model with different template definitions.  For example, if you had some detail level data, but wanted to populate a drop down for Region, you can simply create a Derived Model with only Region on it, and MicroStrategy will handle the Distinct for you.  Now you just have to tie it to a MicroStrategy Drop Down, or consume the direct Region list yourself (I’m covering this second method in this post).

Wiring Models
There’s lots of documentation in the MicroStrategy SDK that talks about wiring models together, so I’ll just cover the basic usage here.

Static Derived Model Definition
You can define a Static Derived Model by simply adding this mxml:

<mstr:Model id="model1" baseModelKey="MyReport" templateDefn="*"/>

“model1” is your Derived Model built off of the Base Model “MyReport”.  The templateDefn is where you can only pull back specific columns, but a “*” is a shortcut for everything.

Note: This definition will only work if the underlying Base Model is called “MyReport”.  If your widget/visualization gets linked to a Report/Grid called something else, the linkage will fail.

Dynamic Derived Model Definition
If you’re building a widget for a single use case, you may not care that you have to specifically define the Base Model during it’s definition.  However, if you’d like to reuse this Widget in multiple places or by multiple developers who may not know what your Base Model was named, you can make this dynamic.

Instead of the mxml, use the following actionscript code:

(Controller.getInstance(appNameSpace)).createModel("model1");

You can place this as the very first code that fires after the applicationComplete() event, and it will create the “model1” based on whatever the Base Model is, regardless of name.

Getting the Data
And now for the main event.  Now that you have your Derived Model defined (using either method) and you’re ready to consume it, you need to first wait for the widget to populate it.  To do this, add the following code after the applicationComplete() event (and after your createModel() call if you’re using Dynamic creation):

(Controller.getInstance(appNameSpace)).addEventListener(ControllerEvent.VIEWER_MODEL_REQUESTS_COMPLETE, getData);

This will tell the widget to wait until the data is loaded and ready to be consumed.  If you try to access the data immediately after issuing the createModel() command, you’ll receive errors (and null objects).  The above code will execute the function “getData” once the data is ready to be consumed.

In your getData function, add the following code:

var controller:Controller = Controller.getInstance(this.getAppNameSpace());var reportData : IReportData = IReportData(controller.getModelById("model1"));

var rows : IReportRawDataRows = reportData.getRawData(false).getRows();

var dataRow : IReportRawDataRow;

var rdata:Array = new Array();

for(var d:int = 0; d<rows.getRowCount(); d++) {

dataRow = rows.getRowData(d);

rdata.push(dataRow.getCellAt(1).getDisplayValue());

}

Code Explanation
The Controller is the MicroStrategy traffic cop that is your resource for accessing the data, so the first piece of code is to get this widget’s controller.  Next, we fill the reportData from the Derived Model that we created earlier (using either the Static or Dynamic method) and then subsequently get the rows from the reportData.

My personal preference is to load an array with the data from the report so that I can then use it later when building my visualization.  If you have a simple control, you could skip the array and just do your core processing here.  I also create my own data structure per widget to store the data in which makes it very accessible later on.  Since this is a basic tutorial, I’ll just stick with loading an array with what is more than likely the DESC field of the first attribute.

We iterate through the rows variable and set the dataRow variable to each occurrence.  To get data out of the row, use the getCellAt() function, followed by either getDisplayValue() if you want to return a string, or getValue() if you want to return a number.

Conclusion
From this point, you’re in Flex Land and you’re free to do whatever you want with the data.  The MicroStrategy Visualization plugin will download the report data into Flex and store it as a local XML file.  This serves as a convenience during development and has no barring on the final widget.  Once deployed, that XML file is no longer used and the Base Model is linked directly to your underlying Grid.

Full Sample Code
Refer to the Setting up a Flex Environment for Building MicroStrategy Widgets post for details on how to setup your environment, then simply paste this full code into your .mxml file to run it.  You can then run it in Debug mode to see the output in the Console.

<?xml version="1.0" encoding="utf-8"?>
<mstr:MstrApplication xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="onComplete();" xmlns:mstr="http://web.microstrategy.com/visframe" xmlDataFile="xmlTestData.xml" layout="absolute">
<mx:Script>
 <![CDATA[
 import com.microstrategy.web.vf.controller.Controller;
 import com.microstrategy.web.vf.controller.ControllerEvent;         
 import com.microstrategy.web.vf.model.data.IReportRawDataRow;
 import com.microstrategy.web.vf.model.data.IReportRawDataRows;
 import com.microstrategy.web.vf.model.IReportData;

 private function onComplete():void {
  (Controller.getInstance(appNameSpace)).createModel("model1"); //create Derived Model dynamically
  (Controller.getInstance(appNameSpace)).addEventListener(ControllerEvent.VIEWER_MODEL_REQUESTS_COMPLETE, getData); //once the model is ready, get the data
  }

 private function getData(evt:Event):void {
  var controller:Controller = Controller.getInstance(this.getAppNameSpace()); //get this Widget's Controller      var reportData : IReportData = IReportData(controller.getModelById("model1")); //get the reportData
  var rows : IReportRawDataRows = reportData.getRawData(false).getRows(); //get the collection of rows
  var dataRow : IReportRawDataRow;
  var rdata:Array = new Array(); //this is where we'll store the processed data
  for(var d:int = 0; d<rows.getRowCount(); d++) { //iterate through the rows
   dataRow = rows.getRowData(d); //get the current row
   rdata.push(dataRow.getCellAt(1).getDisplayValue()); //push the 2nd column (this is zero based) into the array
   trace(rdata[d]);
  }
 }
]]>
</mx:Script>
</mstr:MstrApplication>

You may also like...