Ignite UI Pivot Grid is a WEB client (HTML5/jQuery/jQuery.UI based ) implementation of the very successful Infragistics Pivot Grid (xamPivotGrid) , well known from XAML platforms like WPF and Silverlight. Pivot Grid is a component that provides the same functionalities like Pivot Table and developers could embed this control in their applications and get pivot table functionalities out of the box.
Introduction
A pivot table is a program tool that allows you to reorganize and summarize selected columns and rows of data in a spreadsheet or database table to obtain a desired report. A pivot table doesn't actually change the spreadsheet or database itself.
The term pivot table is a generic phrase used by multiple vendors. In the United States, Microsoft Corporation has trademarked the specific form PivotTable. Pivot tables can be seen as a simplification of the more complete and complex OLAP concepts.
On-Line Analytical Processing (OLAP) is a category of software technology that enables analysts, managers and executives to gain insight into data through fast, consistent, interactive access to a wide variety of possible views of information that has been transformed from raw data to reflect the real dimensionality of the enterprise as understood by the user.
OLAP functionality is characterized by dynamic, multi-dimensional analysis of consolidated enterprise data supporting end user analytical and navigational activities including:
- calculations and modeling applied across dimensions, through hierarchies and/or across members
- trend analysis over sequential time periods
- slicing subsets for on-screen viewing
- drill-down to deeper levels of consolidation
- reach-through to underlying detail data
- rotation to new dimensional comparisons in the viewing area
Microsoft SQL Server Analysis Services (SSAS) delivers online analytical processing (OLAP) and data mining functionality for business intelligence applications. Analysis Services supports OLAP by letting you design, create, and manage multidimensional structures that contain data aggregated from other data sources, such as relational databases.
XMLA
XML for Analysis (XMLA) is a SOAP-based XML protocol, designed specifically for universal data access to any standard multidimensional data source that can be accessed over an HTTP connection. Analysis Services uses XMLA as its only protocol when communicating with client applications.
As a developer, you can use XMLA to integrate a client application with Analysis Services. Developers can use XMLA to integrate a client application with Analysis Services, without any dependencies on the .NET Framework or COM interfaces. Applications require XMLA and an HTTP connection to Analysis Services.
In this study we will not talk about how to set XMLA http access for SQL Server Analytics Services (SASS).
You could learn how to set up an SQL server that provides analysis services and XMLA HTTP Access from the great article “How to set up XMLA HTTP Access for SQL Server Analysis Service 2008 and access the Adventure Works 2008 from an Infragistics PivotGrid application”.
XMLA and Ignite UI Pivot Grid
Pivot Grid to use XMLA via Infragistics Data Source (igDataSource) using serverUrl option
There are two main options:
- Direct XMLA provider via SQL Server HTTP Access
- Remote XMLA provider (using XMLA via controller / WEB service)
Often requirements could be to use a different format to transfer data between WEB service and WEB client (for example JSON, which is very popular last years)
In this study we will demonstrate direct and remote XMLA access and also how can implement service with a different format (JSON)
Sample Demo
Sample demo is an ASP.Net MVC 4 project, generated with Visual Studio 2012
We have 2 projects in the solution:
1. WEB client – ASP.Net MVC 4
2. ASMX service (used for JSON serialization of the XMLA data)
In the WEB client (ASP.Net MVC 4 ) application there are :
3. PivotGridController (contains controllers implementations for all views (direct and remote XMLA, remote JSON)
4. Views :
- DirectXmla (Direct XMLA implementation)
- Index (Remote JSON via XMLA )
- RemoteXmlaProvider (Remote XMLA implementation)
5. OlabWebService (ASMX service, used for JSON serialization )
6. WEB config (you need to allow Cross-origin resource sharing for ASMX service)
Demo project structure
Web Service
Landing page layout
From the landing page there are added three links that calls controllers / respectively return views for the each case that the sample covers:
- Remote JSON provider
- Remote XMLA provider
- Direct XMLA
Direct XMLA Access
The Controller (In this case controller just returns a view)
1:public ActionResult DirectXmla()
2: {
3:return View();
4: }
Data source definition.
Here the Url points to the address for SQL Server HTTP Access for OLAP
1: dataSource = new $.ig.OlapXmlaDataSource({
2: serverUrl: 'http://sampledata.infragistics.com/olap/msmdpump.dll',
3: catalog: 'Adventure Works DW Standard Edition',
4: cube: 'Adventure Works',
5: rows: '[Date].[Calendar]',
6: columns: '[Product].[Product Categories]',
7: measures: '[Measures].[Internet Order Count]'
8: });
Ignite UI PivotGrid definition – direct XMLA (igPivotGrid just uses data source – there are no specific settings)
1: $directGrid.igPivotGrid({
2: dataSource: dataSource,
3: width: "915px",
4: height: "450px",
5: hideFiltersDropArea: true,
6: disableColumnsDropArea: true,
7: disableRowsDropArea: true,
8: disableMeasuresDropArea: true,
9: tupleMemberExpanding: function (evt, ui) {
10: toggleTupleMember(true, $directGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
11: },
12: tupleMemberCollapsing: function (evt, ui) {
13: toggleTupleMember(false, $directGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
14: }
15: });
Direct XMLA View (Razor)
Below you could see the whole view code.
1:
2: @{
3: Layout = null;
4: }
5:<!DOCTYPEhtml>
6:
7:<html>
8:<head>
9:<title></title>
10:
11:<!-- Ignite UI Required Combined CSS Files -->
12:<linkhref="@Url.Content("~/igniteui/css/themes/infragistics/infragistics.theme.css")"rel="stylesheet"/>
13:<linkhref="@Url.Content("~/igniteui/css/structure/infragistics.css")"rel="stylesheet"/>
14:
15: @Scripts.Render("~/bundles/jquery")
16: @Scripts.Render("~/bundles/jqueryui")
17:
18:<!-- Ignite UI Required Combined JavaScript Files -->
19:<scriptsrc="@Url.Content("~/igniteui/js/infragistics.core.js")"></script> 1:
2:<script src="@Url.Content("~/igniteui/js/infragistics.lob.js")">
1:</script>
2:
3:</head>
4:<body>
5:
6:<script type="text/javascript">
7: $.support.cors = true;
8: $(function () {
9:var dataSource,
10: remoteDataSource,
11: remoteSize = { u: 0, d: 0 },
12: directSize = { u: 0, d: 0 },
13: $directGrid = $("#directPivotGrid"),
14://$remoteGrid = $("#remotePivotGrid"),
15: toggleTupleMember = function (expand, pivotGrid, axisName, tupleIndex, memberIndex) {
16:var friendlyAxisName = axisName == "Axis0" ? "columnAxis" : "rowAxis";
17:if (expand) {
18: pivotGrid.igPivotGrid("expandTupleMember", friendlyAxisName, tupleIndex, memberIndex, true);
19: }
20:else {
21: pivotGrid.igPivotGrid("collapseTupleMember", friendlyAxisName, tupleIndex, memberIndex, true);
22: }
23: };
24:
25:
26: $(document).ajaxComplete(function (event, request, settings) {
27:if (settings.url.match("http://localhost:14889/OlapWebService.asmx/GetAdventureWorks")) {
28: remoteSize.u += settings.data.length;
29: remoteSize.d += request.responseText.length;
30: $("#transferSize").text("Uploaded: " + (remoteSize.u / 1024).toFixed(2) + " KB, Downloaded: " + (remoteSize.d / 1024).toFixed(2) + " KB").show();
31: }
32:elseif (settings.url.match("(.*/)?remote-xmla-provider-endpoint(.*)")) {
33: remoteSize.u += settings.data.length;
34: remoteSize.d += request.responseText.length;
35: $("#transferSize").text("Uploaded: " + (remoteSize.u / 1024).toFixed(2) + " KB, Downloaded: " + (remoteSize.d / 1024).toFixed(2) + " KB").show();
36: }
37:elseif (settings.url === "http://sampledata.infragistics.com/olap/msmdpump.dll") {
38: directSize.u += settings.data.length;
39: directSize.d += request.responseText.length;
40: $("#transferSize").text("Uploaded: " + (directSize.u / 1024).toFixed(2) + " KB, Downloaded: " + (directSize.d / 1024).toFixed(2) + " KB").show();
41: }
42: });
43:
44:
45:
46: dataSource = new $.ig.OlapXmlaDataSource({
47: serverUrl: 'http://sampledata.infragistics.com/olap/msmdpump.dll',
48: catalog: 'Adventure Works DW Standard Edition',
49: cube: 'Adventure Works',
50: rows: '[Date].[Calendar]',
51: columns: '[Product].[Product Categories]',
52: measures: '[Measures].[Internet Order Count]'
53: });
54:
55:
56: $directGrid.igPivotGrid({
57: dataSource: dataSource,
58: width: "915px",
59: height: "450px",
60: hideFiltersDropArea: true,
61: disableColumnsDropArea: true,
62: disableRowsDropArea: true,
63: disableMeasuresDropArea: true,
64: tupleMemberExpanding: function (evt, ui) {
65: toggleTupleMember(true, $directGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
66: },
67: tupleMemberCollapsing: function (evt, ui) {
68: toggleTupleMember(false, $directGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
69: }
70: });
71: });
72:
</script>
20:
21:<h5>Direct XMLA Access</h5>
22:<h5id="transferSize">Uploaded: 0KB, Downloaded: 0 KB</h5>
23:
24:
25:<divid="directPivotGrid"></div>
26:</body>
27:</html>
Remote XMLA Provider
Controller implementation. In this case you need to add a specific attribute “remote-xmla-provider-endpoint” for your action in the controller. XmlaDataSourceModel is a class implemented in Ignite UI .Net libraries and you need to use it as a context for your view. To initialize the model you need to add a server Url for OLAP HTTP access.
1: [XmlaDataSourceAction]
2: [ActionName("remote-xmla-provider-endpoint")]
3:public ActionResult RemoteXmlaProviderEndpoint()
4: {
5:return View(new XmlaDataSourceModel { ServerUrl = "http://sampledata.infragistics.com/olap/msmdpump.dll" });
6: }
Remote DataSource. In this case for serverUrl you need to use the action in the MVC controller: '@Url.Action("remote-xmla-provider-endpoint")'
1: remoteDataSource = new $.ig.OlapXmlaDataSource({
2: isRemote: true,
3: serverUrl: '@Url.Action("remote-xmla-provider-endpoint")',
4: catalog: 'Adventure Works DW Standard Edition',
5: cube: 'Adventure Works',
6: rows: '[Date].[Calendar]',
7: columns: '[Product].[Product Categories]',
8: measures: '[Measures].[Internet Order Count]'
9: });
Pivot Grid implementation (there is nothing specific – all differences are in igDataSource).
1: $remoteGrid.igPivotGrid({
2: dataSource: remoteDataSource,
3: width: "915px",
4: height: "450px",
5: hideFiltersDropArea: true,
6: disableColumnsDropArea: true,
7: disableRowsDropArea: true,
8: disableMeasuresDropArea: true,
9: tupleMemberExpanding: function (evt, ui) {
10: toggleTupleMember(true, $remoteGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
11: },
12: tupleMemberCollapsing: function (evt, ui) {
13: toggleTupleMember(false, $remoteGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
14: }
15: });
Remote XMLA View (Razor)
You could see the code of the whole view below.
1: @{
2: Layout = null;
3: }
4:<!DOCTYPEhtml>
5:
6:<html>
7:<head>
8:<title></title>
9:
10:<!-- Ignite UI Required Combined CSS Files -->
11:<linkhref="@Url.Content("~/igniteui/css/themes/infragistics/infragistics.theme.css")"rel="stylesheet"/>
12:<linkhref="@Url.Content("~/igniteui/css/structure/infragistics.css")"rel="stylesheet"/>
13:
14: @Scripts.Render("~/bundles/jquery")
15: @Scripts.Render("~/bundles/jqueryui")
16:
17:<!-- Ignite UI Required Combined JavaScript Files -->
18:<scriptsrc="@Url.Content("~/igniteui/js/infragistics.core.js")"></script> 1:
2:<script src="@Url.Content("~/igniteui/js/infragistics.lob.js")">
1:</script>
2:
3:</head>
4:<body>
5:
6:<script type="text/javascript">
7: $.support.cors = true;
8: $(function () {
9:var dataSource,
10: remoteDataSource,
11: remoteSize = { u: 0, d: 0 },
12: directSize = { u: 0, d: 0 },
13: $remoteGrid = $("#remotePivotGrid"),
14: toggleTupleMember = function (expand, pivotGrid, axisName, tupleIndex, memberIndex) {
15:var friendlyAxisName = axisName == "Axis0" ? "columnAxis" : "rowAxis";
16:if (expand) {
17: pivotGrid.igPivotGrid("expandTupleMember", friendlyAxisName, tupleIndex, memberIndex, true);
18: }
19:else {
20: pivotGrid.igPivotGrid("collapseTupleMember", friendlyAxisName, tupleIndex, memberIndex, true);
21: }
22: };
23:
24:
25: $(document).ajaxComplete(function (event, request, settings) {
26:if (settings.url.match("http://localhost:14889/OlapWebService.asmx/GetAdventureWorks")) {
27: remoteSize.u += settings.data.length;
28: remoteSize.d += request.responseText.length;
29: $("#transferSize").text("Uploaded: " + (remoteSize.u / 1024).toFixed(2) + " KB, Downloaded: " + (remoteSize.d / 1024).toFixed(2) + " KB").show();
30: }
31:elseif (settings.url.match("(.*/)?remote-xmla-provider-endpoint(.*)")) {
32: remoteSize.u += settings.data.length;
33: remoteSize.d += request.responseText.length;
34: $("#transferSize").text("Uploaded: " + (remoteSize.u / 1024).toFixed(2) + " KB, Downloaded: " + (remoteSize.d / 1024).toFixed(2) + " KB").show();
35: }
36:elseif (settings.url === "http://sampledata.infragistics.com/olap/msmdpump.dll") {
37: directSize.u += settings.data.length;
38: directSize.d += request.responseText.length;
39: $("#transferSize").text("Uploaded: " + (directSize.u / 1024).toFixed(2) + " KB, Downloaded: " + (directSize.d / 1024).toFixed(2) + " KB").show();
40: }
41: });
42:
43:
44: remoteDataSource = new $.ig.OlapXmlaDataSource({
45: isRemote: true,
46: serverUrl: '@Url.Action("remote-xmla-provider-endpoint")',
47: catalog: 'Adventure Works DW Standard Edition',
48: cube: 'Adventure Works',
49: rows: '[Date].[Calendar]',
50: columns: '[Product].[Product Categories]',
51: measures: '[Measures].[Internet Order Count]'
52: });
53:
54: $remoteGrid.igPivotGrid({
55: dataSource: remoteDataSource,
56: width: "915px",
57: height: "450px",
58: hideFiltersDropArea: true,
59: disableColumnsDropArea: true,
60: disableRowsDropArea: true,
61: disableMeasuresDropArea: true,
62: tupleMemberExpanding: function (evt, ui) {
63: toggleTupleMember(true, $remoteGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
64: },
65: tupleMemberCollapsing: function (evt, ui) {
66: toggleTupleMember(false, $remoteGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
67: }
68: });
69: });
70:
</script>
19:
20:<h5>Remote XMLA Access</h5>
21:<h5id="transferSize">Uploaded: 0KB, Downloaded: 0 KB</h5>
22:
23:
24:<divid="remotePivotGrid"></div>
25:</body>
26:</html>
Remote JSON (using WEB service *.asmx)
The Controller
When you have own serialization controller just returns the view
1:public ActionResult Index()
2: {
3:return View();
4: }
Remote JSON WEB service (ASMX service)
In your implementation you need to create XmlaDataSourceModel and XmlaDataSourceManager that should be used to create a query.
Result is serialized as JSON – You can use for the your web method an attribute [ScriptMethod(ResponseFormat = ResponseFormat.Json)].
1:/// <summary>
2:/// Summary description for OlapWebService
3:/// </summary>
4: [ScriptService]
5: [WebService(Namespace = "http://tempuri.org/")]
6: [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
7: [System.ComponentModel.ToolboxItem(false)]
8:publicclass OlapWebService : System.Web.Services.WebService
9: {
10:
11: [WebMethod]
12: [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
13:publicstring GetAdventureWorks()
14: {
15:conststring serverUrl = "http://sampledata.infragistics.com/olap/msmdpump.dll";
16:
17: var model = new XmlaDataSourceModel { ServerUrl = serverUrl };
18: var mng = new XmlaDataSourceManager();
19:string result = mng.DoQuery(model, this.Context.Request);
20:
21:return result;
22: }
23: }
- Remote JSON view implementation
Remote Data Source using JSON (you need to use for serverUrl the Url of the your web method in the asmx service)
1: remoteDataSource = new $.ig.OlapXmlaDataSource({
2: isRemote: true,
3: serverUrl: 'http://localhost:14889/OlapWebService.asmx/GetAdventureWorks',
4: catalog: 'Adventure Works DW Standard Edition',
5: cube: 'Adventure Works',
6: rows: '[Date].[Calendar]',
7: columns: '[Product].[Product Categories]',
8: measures: '[Measures].[Internet Order Count]'
9: });
Ignite UI Pivot Grid implementation (it is the same like in Direct XAML and Remote XMLA implementations)
1: $remoteGrid.igPivotGrid({
2: dataSource: remoteDataSource,
3: width: "915px",
4: height: "450px",
5: hideFiltersDropArea: true,
6: disableColumnsDropArea: true,
7: disableRowsDropArea: true,
8: disableMeasuresDropArea: true,
9: tupleMemberExpanding: function (evt, ui) {
10: toggleTupleMember(true, $remoteGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
11: },
12: tupleMemberCollapsing: function (evt, ui) {
13: toggleTupleMember(false, $remoteGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
14: }
15: });
The whole Remote JSON View (Razor)
The whole view is available here:
1: @{
2: Layout = null;
3: }
4:<!DOCTYPEhtml>
5:
6:<html>
7:<head>
8:<title></title>
9:
10:<!-- Ignite UI Required Combined CSS Files -->
11:<linkhref="@Url.Content("~/igniteui/css/themes/infragistics/infragistics.theme.css")"rel="stylesheet"/>
12:<linkhref="@Url.Content("~/igniteui/css/structure/infragistics.css")"rel="stylesheet"/>
13:
14: @Scripts.Render("~/bundles/jquery")
15: @Scripts.Render("~/bundles/jqueryui")
16:
17:<!-- Ignite UI Required Combined JavaScript Files -->
18:<scriptsrc="@Url.Content("~/igniteui/js/infragistics.core.js")"></script> 1:
2:<script src="@Url.Content("~/igniteui/js/infragistics.lob.js")">
1:</script>
2:
3:</head>
4:<body>
5:
6:<script type="text/javascript">
7: $.support.cors = true;
8: $(function () {
9:var dataSource,
10: remoteDataSource,
11: remoteSize = { u: 0, d: 0 },
12: directSize = { u: 0, d: 0 },
13: $directGrid = $("#directPivotGrid"),
14: $remoteGrid = $("#remotePivotGrid"),
15: toggleTupleMember = function (expand, pivotGrid, axisName, tupleIndex, memberIndex) {
16:var friendlyAxisName = axisName == "Axis0" ? "columnAxis" : "rowAxis";
17:if (expand) {
18: pivotGrid.igPivotGrid("expandTupleMember", friendlyAxisName, tupleIndex, memberIndex, true);
19: }
20:else {
21: pivotGrid.igPivotGrid("collapseTupleMember", friendlyAxisName, tupleIndex, memberIndex, true);
22: }
23: };
24:
25:
26: $(document).ajaxComplete(function (event, request, settings) {
27:if (settings.url.match("http://localhost:14889/OlapWebService.asmx/GetAdventureWorks")) {
28: remoteSize.u += settings.data.length;
29: remoteSize.d += request.responseText.length;
30: $("#transferSize").text("Uploaded: " + (remoteSize.u / 1024).toFixed(2) + " KB, Downloaded: " + (remoteSize.d / 1024).toFixed(2) + " KB").show();
31: }
32:elseif (settings.url.match("(.*/)?remote-xmla-provider-endpoint(.*)")) {
33: remoteSize.u += settings.data.length;
34: remoteSize.d += request.responseText.length;
35: $("#transferSize").text("Uploaded: " + (remoteSize.u / 1024).toFixed(2) + " KB, Downloaded: " + (remoteSize.d / 1024).toFixed(2) + " KB").show();
36: }
37:elseif (settings.url === "http://sampledata.infragistics.com/olap/msmdpump.dll") {
38: directSize.u += settings.data.length;
39: directSize.d += request.responseText.length;
40: $("#transferSize").text("Uploaded: " + (directSize.u / 1024).toFixed(2) + " KB, Downloaded: " + (directSize.d / 1024).toFixed(2) + " KB").show();
41: }
42: });
43:
44:
45: remoteDataSource = new $.ig.OlapXmlaDataSource({
46: isRemote: true,
47: serverUrl: 'http://localhost:14889/OlapWebService.asmx/GetAdventureWorks',
48: catalog: 'Adventure Works DW Standard Edition',
49: cube: 'Adventure Works',
50: rows: '[Date].[Calendar]',
51: columns: '[Product].[Product Categories]',
52: measures: '[Measures].[Internet Order Count]'
53: });
54:
55: $remoteGrid.igPivotGrid({
56: dataSource: remoteDataSource,
57: width: "915px",
58: height: "450px",
59: hideFiltersDropArea: true,
60: disableColumnsDropArea: true,
61: disableRowsDropArea: true,
62: disableMeasuresDropArea: true,
63: tupleMemberExpanding: function (evt, ui) {
64: toggleTupleMember(true, $remoteGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
65: },
66: tupleMemberCollapsing: function (evt, ui) {
67: toggleTupleMember(false, $remoteGrid, ui.axisName, ui.tupleIndex, ui.memberIndex);
68: }
69: });
70: });
71:
</script>
19:
20:<h5>Remote JSON Access</h5>
21:<h5id="transferSize">Uploaded: 0KB, Downloaded: 0 KB</h5>
22:
23:
24:<divid="remotePivotGrid"></div>
25:</body>
26:</html>
WEB config file
You need to add the lines below to your WEB.config file (you need to allow Cross-origin resource sharing for ASMX service). IE now 10 doesn’t require this settings but you need to add it for other browsers.
1:<system.webServer>
2: ....
3:<httpProtocol>
4:<customHeaders>
5:<addname="Access-Control-Allow-Origin"value="*"/>
6:<addname="Access-Control-Allow-Headers"value="Origin, X-Requested-With, Content-Type, Accept"/>
7:</customHeaders>
8:</httpProtocol>
9:</system.webServer>
Running Pivot using JSON via WEB service
Remote JSON implementation (this is the first option)
Select Remote XMLA link to open the view with Remote XMLA implementation. In this case you will see that the data traffic from the remote WEB server to your client is more than 5 times more larger.
Select Direct XMLA link to redirect to Direct XMLA view. In this case you will see the pivot grid with the same data
Conclusions:
Infragistics Ignite UI supports XAML out of the box via Data Source (igDataSource) option “serverUrl”
You could use remote and direct XMLA providers. It is easy to implement own WEB service where to serialize data to JSON and Data Source could use this format.
Remote access leads to less data transfer and it will be better to use this approach (doesn’t matter which format you are using: XMLA or JSON)
Sample source code with all referenced scripts and libraries you could download here:
You are probably thinking, how do I get my hands on Ignite UI Pivot Grid? It’s easy.
Click on this image to get a fully support trial version of Infragistics Ignite UI controls:
To view all the samples and code for HTML, MVC & ASP.NET, click here: .
http://www.infragistics.com/products/jquery/samples
Follow news from Infragistics for more information about new Infragistics products.
As always, you can follow us on Twitter @mihailmateev and @Infragistics and stay in touch on Facebook, Google+andLinkedIn!