Dashboard Reports with LightSwitch, WebAPI and ServerApplicationContext– Part Deux (Steve Lasker)

Dashboard Reports with LightSwitch, WebAPI and ServerApplicationContext– Part Deux (Steve Lasker)

Rate This
  • Comments 9

Overview

With a little homage to Hot Shots Part Deux we’ll drill in a bit deeper utilizing the ServerApplicationContext for creating Dashboard reports. Part 1 is here: Create Dashboard Reports with LightSwitch, WebAPI and ServerApplicationContext

LightSwitch Productivity/Extendability disclaimer: As with Part 1, this isn’t the normal point & click RAD productivity you’ve likely become used to with LightSwitch. This is more of an advanced scenario, showing the extension points we’ve enabled to extend the out of the box features.

In Part 2 I’ll cover:

  • Adding a second set of charts that enable drilling into monthly data to see a weekly slice of data based on the click events of the chart
  • Adding date controls to select the date range of the report
  • Interactively making selections in the screen, changing the data displayed
  • Calling Stored Procedures from WebAPI

Let’s get started…

Create the AmazingPie Restaurant Point of Sale (POS) database

As with part one, we’ll utilize the AmazingPie POS Sample database. However, this code also assumes you’ve already completed Part 1.

Adding the new Report

We’ll start by adding a WebAPI, allowing us to query based on a time period of Monthly or Weekly.

1. As in Part 1, we’ll need to switch from the logical view to file view so we can interact directly with files.

2. Within the Reports folder, add the new Web API controller

If you’ve followed the previous step, Visual Studio will remember the last few template types you’ve added, and you’ll see a shortcut in your menu:

image

This will provide an abbreviated prompt. Name our controller SeatedGuestsController

image

3. Remove all the template Get, Put, Post, Delete methods to make way for our new Report methods.

4. Add the Extension Methods for query operators

Note: this is an important step. Without these extension methods, the LINQ query operators will not be available on the DataWorkspace, and SqlFunctions will require the full namespace


VB
Option Infer On Imports System.Net Imports System.Web.Http
Imports Microsoft.LightSwitch Imports LightSwitchApplication Imports System.Configuration Imports System.Data Imports System.Data.SqlClient Imports
System.Data.Objects.SqlClient
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Microsoft.LightSwitch;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.Data.Objects.SqlClient;

5. Add the following Method to expose our WebAPI Method

The get will capture the period, and we’ll call sub methods for each specific report


VB
Public Class SeatedGuestsController Inherits ApiController Public Function GetValue(period As String, id As String,
beginDate
As DateTime, endDate As DateTime)
Dim retVal As Object = Nothing If period.ToLower() = "monthly" Then retVal = GetMonthlyReport(id, beginDate, endDate) ElseIf period.ToLower() = "weekly" Then retVal = GetWeeklyReport(id, beginDate, endDate) End If Return retVal End Function Public Function GetMonthlyReport(location_Id As String,
beginDate
As DateTime,
endDate
As DateTime) As Object Return Nothing End Function Public Function GetWeeklyReport(location_Id As String,
beginDate
As DateTime,
endDate
As DateTime) As Object Return Nothing End Function End Class
C#
public object Get(string period, string id, DateTime beginDate, DateTime endDate) {
    object retVal = null;
    if (period.ToLower() == "monthly") {
        retVal = GetMonthlyReport(id, beginDate, endDate);
    } else if (period.ToLower() == "weekly"){
        retVal = GetWeeklyReport(id, beginDate, endDate);
    }
    return retVal;
}

private object GetMonthlyReport(string location_Id, DateTime beginDate, DateTime endDate) {
    return null;
}
private object GetWeeklyReport(string location_Id, DateTime beginDate, DateTime endDate) {
    return null;
}

6. Add the GetMonthlyReport LINQ Query    

From Part 1, you’ll remember we instance the ServerApplicationContext within a using block to be sure it gets disposed when we’re done. We also call report.Execute() to make sure the LINQ query is executed before the Context is disposed.    

Looks like there is a horse before the cart, so we need to get the ordering correct.

Lastly, we use the SqlFunctions to create a string format of Month/Year which we need for our Chart to display properly. Using SqlFunctions is important as the query is sent to SQL Server, which wouldn’t know how to parse:  String.Format("{0}/{1}", x.Key.Month, x.Key.Year)


VB
Public Function GetMonthlyReport(location_Id As String,
                                 beginDate As DateTime,
                                 endDate As DateTime) As Object
   Using context As ServerApplicationContext = ServerApplicationContext.CreateContext()

        Dim report = From olc In context.DataWorkspace.AmazingPieData.OrderLifeCycles
                     Where olc.Order.Location.Location_Id = location_Id AndAlso
                           olc.EventType_Id = "Complete" AndAlso
                           olc.EventTime >= beginDate AndAlso
                           olc.EventTime <= endDate
                     Group By olc.EventTime.Year,
                              olc.EventTime.Month,
                              olc.Order.Table.TableType.TableType_Id,
                              olc.Order.Table.TableType.DisplayOrder Into Group
                     Order By Year, Month, DisplayOrder
                     Select MonthYear = SqlFunctions.StringConvert(Month, 2) + "/" +                                         
SqlFunctions.StringConvert(Year, 4), TableType_Id, Seats = Group.Count() Return report.Execute()
End Using End Function
C#
private object GetMonthlyReport(string location_Id, DateTime beginDate, DateTime endDate) { using (ServerApplicationContext context = ServerApplicationContext.CreateContext()) { var report = context.DataWorkspace.AmazingPieData.OrderLifeCycles .Where(olc => (olc.Order.Location.Location_Id == location_Id) && (olc.EventType_Id == "Complete") && (olc.EventTime >= beginDate) && (olc.EventTime <= endDate)) .GroupBy(x => new { x.EventTime.Year, x.EventTime.Month, x.Order.Table.TableType.TableType_Id, x.Order.Table.TableType.DisplayOrder }) .OrderBy(o => new {o.Key.Year, o.Key.Month, o.Key.DisplayOrder}) .Select(x => new { MonthYear = SqlFunctions.StringConvert((decimal) x.Key.Month, 2) + "/" + SqlFunctions.StringConvert((decimal)x.Key.Year, 4), TableType_Id = x.Key.TableType_Id, Seats = x.Count() }); return report.Execute(); }; }

7. Add the GetWeeklyReport LINQ Query 

The query is very similar to the Monthly report, however this time we’re grouping by the day of the week using the SqlFunctions TSQL equivalent of DATEPART(DW, EventTime)


VB
Public Function GetWeeklyReport(location_Id As String,
beginDate
As DateTime,
endDate
As DateTime) As Object
Using
context As ServerApplicationContext = ServerApplicationContext
.CreateContext()
Dim report = From olc In context.DataWorkspace.AmazingPieData.OrderLifeCycles Where olc.Order.Location.Location_Id = location_Id AndAlso olc.EventType_Id = "Complete" AndAlso olc.EventTime >= beginDate AndAlso olc.EventTime <= endDate Group By DayOfWeek = SqlFunctions.DatePart("DW", olc.EventTime), olc.Order.Table.TableType.TableType_Id, olc.Order.Table.TableType.DisplayOrder Into Group Order By DayOfWeek, DisplayOrder Select DayOfWeek, TableType_Id, Seats = Group.Count()
        Return report.Execute()
    End Using
End Function
C#
private object GetWeeklyReport(string location_Id, DateTime beginDate, DateTime endDate) {
    using (ServerApplicationContext context = ServerApplicationContext.CreateContext()) {

        var report = context.DataWorkspace.AmazingPieData.OrderLifeCycles
            .Where(olc => (olc.Order.Location.Location_Id == location_Id) &&
                (olc.EventType_Id == "Complete") &&
                (olc.EventTime >= beginDate) &&
                (olc.EventTime <= endDate))
            .GroupBy(x => new { 
                DayOfWeek = SqlFunctions.DatePart("DW", x.EventTime), 
                x.Order.Table.TableType.TableType_Id, 
                x.Order.Table.TableType.DisplayOrder
            })
            .OrderBy(o => new {o.Key.DayOfWeek, o.Key.DisplayOrder})
            .Select(x => new {
                DayOfWeek = x.Key.DayOfWeek,
                TableType_Id = x.Key.TableType_Id,
                Seats = x.Count()
            });
        return report.Execute();
    }
}

Testing with Fiddler

Let’s do our normal Fiddler testing to be sure we have this portion correct before delving into javascript

1. Hit F5 to get the base URL of your app

2. Launch Fiddler and paste the base URL into the Composer

3. Modify it to include the following query string.  

http://localhost:30550/reports/seatedGuests/?period=monthly&id=BelSquare%20&beginDate=2010-05-07&endDate=2013-02-23

Note that we have period =monthly, and we’ve set the begin/endDate using the JSON serialized format.
(I’ve removed the time since we zero it out anyway)

Tip: Had I not tested the output with Fiddler, I wouldn’t have noticed that SqlFunctionsStringConvert was padding the month & year

Without setting the string length Using the StringConvert overload to set the length
MonthYear = SqlFunctions.StringConvert((decimal) x.Key.Month)  
  + "/" +   SqlFunctions.StringConvert((decimal)x.Key.Year)
MonthYear = SqlFunctions.StringConvert((decimal) x.Key.Month, 2)
    + "/" + SqlFunctions.StringConvert((decimal)x.Key.Year, 4)
image image

Adding the Graphs

With our WebAPI Reporting Service tested and ready, let’s add the new graphs

1. Switch back to Logical View

2. Open the Locaion_View screen

3. Select the Report Tab Rows Layout control to get the add control menu and select New Custom Control…

image

4. Using the property sheet, rename it ServedGuests

image

5. Choose Write Code –> ServedGuests_render

6. Add the following code to create the chart containers <div/> tags

Note: greyed out code indicates the previous code as the insertion reference point


myapp.Location_View.ServedGuests
_render =
function (element, contentItem) { // Each KendoUI chart needs it's own container // One for the Monthly graph var customersPerMonthChartContainer = $('<div/>'); customersPerMonthChartContainer.appendTo($(element)); // One for the weekly charts. var customersPerWeekChartContainer = $('<div/>'); customersPerWeekChartContainer.appendTo($(element));

7. Add Kendo UI Chart Control for the Monthly Report

Note that for now, we’re hardcoding the date range. We’ll build this up slowly to avoid tripping over coding issues with things like javascript dates. We’ve also placed this within a function, which we call immediately. Later on, we’ll add the ability to change the date range, and for each date change, we’ll want to redraw the chart.


displayMonthlyChart()
function displayMonthlyChart() { //setup the URI to the report, with the Location Parameter, and the date range var reportsAPI = "../reports/seatedGuests/?period=monthly&id=" + contentItem.screen.Location.Location_Id + "&beginDate=2010-07-20&endDate=2013-01-04"; // Add a Kendo UI BarChart customersPerMonthChartContainer.kendoChart({ // set the theme theme: $(document).data("kendoSkin") || "default", // Set the sourc to use our WebAPI, with a json payload dataSource: { transport: { read: { url: reportsAPI, dataType: "json" } }, // use the TableType_Id to create groupings in the chart group: { field: "TableType_Id" } }, title: { text: "Customers Per Month, By Table Type" }, legend: { position: "bottom" }, // Set the chart to a column (vertical) report type seriesDefaults: { type: "column", labels: { visible: true, // the 0:n0 means parameterize the label with the value - first 0 // and then :n0 means use numeric with 0 decimals format: "{0:n0}" } }, // map the vertical series to the number of seats, // notice the field: "Seats" matches the name in the json payload returned from our WebAPI series: [{ field: "Seats", name: "", colorField: "userColor", labels: { rotation: 320 } }], valueAxis: { labels: { format: "{0}" } }, // And the category is grouped by Month, also from our WebAPI json payload categoryAxis: { field: "MonthYear", labels: { //format: "{0:n0}" format: "{0}", rotation: 300 } } }); // Close of Kendo Monthly Chart }

8. Let’s F5 to see how things work so far:

image

Not so bad. We have quite a lot of data here, visually presented, allowing your users to know where to drill in, looking for more details.

Add Weekly Chart

We can see how the Bel Square location is trending during the year, but what about weekly, for a given month? We’ll now add another chart that will display the averaged seated guests, by day of the week for the month the user clicks on.

1. Add the displayWeeklyChart function, just blow our Monthly chart, and still within the render method

Note: we’re still commenting out the date ranges as we’ll plumb this through once we get the basic charts displayed. I’ve also placed the weekly chart within a function as we only want to show this chart when the user clicks on a time period within the monthly chart. Each time they click a different time slice, we’ll want to update the chart by calling the displayWeeklyChart function.


}
});
// Close of Kendo Monthly Chart } function displayWeeklyChart(beginDate, endDate) { customersPerWeekChartContainer.fadeIn(500); //setup the URI to the report, with the Location Parameter, and the date range var reportsAPI = "../reports/SeatedGuests/?period=weekly&id=" +
contentItem.screen.Location.Location_Id +
"&beginDate=2010-07-20&endDate=2013-01-04"; customersPerWeekChartContainer.kendoChart({ theme: $(document).data("kendoSkin") || "default", dataSource: { transport: { read: { url: reportsAPI, dataType: "json" } }, group: { field: "TableType_Id" } }, title: { text: "Customers Per Week, By Table Type" }, legend: { position: "bottom" }, seriesDefaults: { type: "column", labels: { visible: true, format: "{0:n0}" } }, series: [{ field: "Seats", name: "", colorField: "userColor" }], valueAxis: { labels: { format: "{0}" } }, categoryAxis: { field: "DayOfWeek" } }); };

Add a Click Event Handler to the Bar Chart

To drill into the data, we’ll enable click events on the chart. Most charts support this powerful feature.

1. Below the configuration of the Monthly chart, we’ll add the seriesClick event handler


categoryAxis: { field:
"MonthYear", labels: { //format: "{0:n0}" format: "{0}", rotation: 300 } }, // <-- note the comma to continue the configuration of the chart // hook up the Click event to drill into weekly reports seriesClick: onSeriesClick }); // Close of Kendo Monthly Chart } function onSeriesClick(e) { // Split the category label into Month/Year var dateElements = e.category.split("/"); // javascript uses Month 0 as January - so, start from Jan, // and add the selected month, which needs to be decremented to account for 0 base javascript // compared to the rest of the human readable world var beginDate = new Date(dateElements[1], parseInt(dateElements[0]) - 1, 1); var endDate = new Date(beginDate.getFullYear(), beginDate.getMonth() + 1,
beginDate.getDate(), beginDate.getHours()); displayWeeklyChart(beginDate, endDate); }
function
displayWeeklyChart(beginDate, endDate) { customersPerWeekChartContainer.fadeIn(500);

Adding Date Parameters

We’ll now add begin and endDate controls to narrow the results.

Adding Screen Parameters

We’ll want these values to come from the user, and don’t forget, LightSwitch uses a ViewModel approach

1. Open the Location_View screen

2. In the Reports Tab, add a new Group

  • Name it dateRange
  • Change the Group to Column layout
  • Move it below the Served Guests custom control

3. Add two new screen properties

  • On the top of the screen designer, select Add Data Item…
  • Change the Member Type to Local Property
    • Type = Date
    • Uncheck Is Required
    • and name it beginDate

clip_image001

  • Add another optional local property for endDate with the same options

4. Add beginDate and endDate screen properties as controls on the screen

  • Below the date Range Columns Layout (grouping), click the add button to add the two local properties

clip_image002[4]

  • Change the Control Types to Date Picker for both of the screen parameters
  • You’re screen designer should now look like this…

clip_image003[4]

5. Lets set the default values for the date range properties:

  • From the Write Code menu, select created

image

  • Default the beginning date to the date the location opened for business and the end date to today
    While we’re here, we’ll also set the screen display name to the Id of the location

myapp.Location_View.created
=
function (screen) { screen.beginDate = screen.Location.LocationOpened; screen.endDate = new Date(); screen.details.displayName = "Location: " + screen.Location.Location_Id; };

6. Change our Monthly Chart to use the new screen parameters  

Note: we use the Date.toJSON() function to convert the date to a format that will serialize across URLs.


function
displayMonthlyChart() { if (contentItem.screen.endDate < contentItem.screen.beginDate) return;
    var reportsAPI = "../reports/seatedGuests/?period=monthly&id=" + 
contentItem.screen.Location.Location_Id +
"&beginDate=" + contentItem.screen.beginDate.toJSON() + "&endDate=" + contentItem.screen.endDate.toJSON();

 

7. Lets hange the displayWeeklyChart() to also use the date range screen parameters by replacing the fixed date with the begin/end date parameters. Note the toJSON() conversion to make sure we encode the dates for URLs


function
displayWeeklyChart() { //setup the URI to the report, with the Location Parameter, and the date range var reportsAPI = "../reports/SeatedGuests/?period=weekly&id=" +
contentItem.screen.Location.Location_Id +
"&beginDate=" + contentItem.screen.beginDate.toJSON() + "&endDate=" + contentItem.screen.endDate.toJSON();
customersPerWeekChartContainer.kendoChart({

8. We’ll now Databind the date ranges to re-display the monthly report when the dates change. We’ll also  hide the chart until the user re-clicks a monthly slice.


// add the whole thing to the LightSwitch custom control
customersByTableTypeContainer.appendTo($(element)); // Databind the date range changes to rebuild the chart contentItem.dataBind("screen.beginDate", function () { customersPerWeekChartContainer.fadeOut(500); displayMonthlyChart(); }); contentItem.dataBind("screen.endDate", function () { customersPerWeekChartContainer.fadeOut(500); displayMonthlyChart(); });
displayMonthlyChart();


Run it and notice that now you can click on a month to get the weekly breakdown and when we change the dates, the charts will refresh.

image

Using Stored Procedures

Since reporting is typically based on aggregating large amounts of data, and you may be working with existing systems, your DBA may already have several stored procedures created, and you just need to return the results. Lets replace the weekly query with a stored procedure.

Getting the Connection String

To call the stored procedure, we’re going to use the traditional ADO.net objects directly. SqlConnection, SqlCommand and SqlDataReader. Of course, we need a connection string which we’ll read from the ConfigurationManager. This requires an additional reference.

1. From the File view, select Add Reference on the Server project

2. Check off System.Configuration

image

3. Open the SeatedGuestsController

4. Add the using/import statements for referencing the SQL ADO.net objects and the System.Configuration namespace


VB
Imports System.Configuration Imports System.Data Imports System.Data.SqlClient
C#
using System.Configuration; using System.Data; using System.Data.SqlClient;

5. Modify the GetWeeklyReport code to call the stored procedure

VB
Public Function GetWeeklyReport(location_Id As String,
                                beginDate As DateTime,
                                endDate As DateTime) As Object

    Using context As ServerApplicationContext = ServerApplicationContext.CreateContext()

        Using conn As SqlConnection =
            New SqlConnection(ConfigurationManager.ConnectionStrings(
                context.DataWorkspace.AmazingPieData.Details.Name).ConnectionString)

            Dim cmd As New SqlCommand()
            cmd.Connection = conn
            cmd.CommandText = "GetSeatedGuestsPerTableTypePerLocationByWeekday"
            cmd.CommandType = CommandType.StoredProcedure
            cmd.Parameters.Add(New SqlParameter("@location_Id", location_Id))
            cmd.Parameters.Add(New SqlParameter("@beginDateRange", beginDate))
            cmd.Parameters.Add(New SqlParameter("@endDateRange", endDate))
            cmd.Connection.Open()

            Using reader As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)

                Dim reportResult = (From dr In reader.Cast(Of IDataRecord)()
                                    Select DayOfWeek = dr.GetInt32(0),
                                           TableType_Id = dr.GetString(1),
                                           Seats = dr.GetInt32(2)).ToList()

                Return reportResult
            End Using
        End Using
    End Using
End Function
C#
private object GetWeeklyReport(string location_Id, DateTime beginDate, DateTime endDate) {
    object reportResult = null;
    using (ServerApplicationContext context = ServerApplicationContext.CreateContext()) {
        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings
[context.DataWorkspace.AmazingPieData.Details.Name].ConnectionString)) { SqlCommand cmd =
new SqlCommand(); cmd.Connection = conn; cmd.CommandText = "GetSeatedGuestsPerTableTypePerLocationByWeekday"; cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new SqlParameter("@location_Id", location_Id)); cmd.Parameters.Add(new SqlParameter("@beginDateRange", beginDate)); cmd.Parameters.Add(new SqlParameter("@endDateRange", endDate)); cmd.Connection.Open(); // Execute the reader into a new named type to be json serialized using (SqlDataReader reader = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection)) { reportResult = reader.Cast<IDataRecord>() .Select(dr => new { DayOfWeek = dr.GetInt32(0), TableType_Id = dr.GetString(1), Seats = dr.GetInt32(2) } ).ToList(); } } return reportResult; } }

Bonus Round

In case you’re still reading, and not ready to leave, I’ve got one more enhancement. It sure would be nice to display the names of the week. 

Changing the Weekly chart to show days of the week

1. In the displayWeeklyChart, add the following code to the displayWeeklyChart function to create an array for the days of the week, and use the Kendo chart dataBound event to convert the array to the categories of the chart.


function
displayWeeklyChart(beginDate, endDate) { //setup the URI to the report, with the Location Parameter, and the date range var reportsAPI = "../reports/SeatedGuests/?period=weekly&id=" +
contentItem.screen.Location.Location_Id +
"&beginDate=" + beginDate.toJSON() + "&endDate=" + endDate.toJSON(); var daysOfWeekJSON = [ { "DayOfWeek": "Mon" }, { "DayOfWeek": "Tues" }, { "DayOfWeek": "Wed" }, { "DayOfWeek": "Thur" }, { "DayOfWeek": "Fri" }, { "DayOfWeek": "Sat" }, { "DayOfWeek": "Sun" }]; customersPerWeekChartContainer.kendoChart({ theme: $(document).data("kendoSkin") || "black"
,
dataSource: { }, categoryAxis: { field:
"DayOfWeek"
}, dataBound: dataBound }); function dataBound(e) { var chart = e.sender, categories = chart.options.categoryAxis.categories, weekNumber; for (var i = 0; i < categories.length; i++) { weekNumber = categories[i]; categories[i] = daysOfWeekJSON[weekNumber - 1].DayOfWeek; } }
};

Wrapping it up

Visual Studio LightSwitch enables rapid productivity for the common components of your app. However, all apps are not created equal. With our extensibility points, developers can take their app in the direction they need, including rich visualizations, leveraging aggregate data from the data source to pixels on the screen.

By leveraging WebAPI, the new aggregate LINQ operators within LightSwitch, the ServerApplicationContext and some great chart controls, we can stitch together some great experiences, building on the “out of the box” features.

With some ADO.net code, we can utilize stored procedures to generate the reports, making sure our DBAs are happy leveraging the power of database query processors. Using parameters, we can narrow the results required by the user, allowing them to drill into specific slices of data.

I hope this blog was helpful and please continue to give us great feedback here and in the forum on what works, what’s tripping you up, and what we should do more of so we can keep you and your customers productive.

Steve Lasker

http://blogs.msdn.com/SteveLasker

Program Manager, Visual Studio LightSwitch

Leave a Comment
  • Please add 1 and 1 and type the answer here:
  • Post
  • Wow, incrediable stuff. I'm - just - blown - away... :)

  • Steve, Thank you.

    This is what exactly I've requested Telerik & Kendo UI in the last Month. Now you made it.. Very useful stuff.

  • Unhandled exception at line 13, column 15978 in http://localhost:50647/HTMLClient/Scripts/kendo.dataviz.min.js

    0x800a138f - JavaScript runtime error: Unable to get property 'length' of undefined or null reference

  • Random  Errors,

    This is usually caused by a mismatch in some names, or even casing. You might want to try using Fiddler to test the individual components.

    If you could give some more details of what was the last step that worked, and which didn't, I might be able to help some more.

    Steve

  • Does anyone know how to execute a stored procedure using parameters with the WebAPI? This page - msdn.microsoft.com/.../jj635144.aspx describes it very well for the desktop client (and I have that working) but I'd like to get the same thing working with the HTML client.

  • Hi Norm,

    Steve is showing how to pass parameters from the UI to the controller to the stored proc (last example) above.

    Cheers,

    -Beth

  • Hi Steve,

    Can't thank you enough.

    This tutorial made the difference  between our first LS project flying or dying.

    The binding demo was the crux for me.

    The stored procedure data retrieval just sits so well with our traditional way of accessing data.

    Icing on top of an incredible cake.

  • Hello

    thank a lot for your example

    I've got the error below when following the walkthrough

    "CustomControl error: ServedGuests_render() method error: ReferenceError: contentItem is not defined"

    i figure the methods "displayMonthlyChart" and  "displayWeeklyChart" require contentItem as parameter.

    how can i get it work by doing exactly what you done ?

    I'm using Visual Studio 2013

    am i  missed sommeting ?

    Thank for your answer

  • Hi ptchek-

    Can you double check to make sure that the displayMonthlyChart and displayWeeklyChart functions are defined within the body of the ServedGuests_render() method?  These methods need to defined within the body of the ServedGuests_render() method in order for the contentItem parameter (which is passed into ServedGuests_render) to be within scope.  Otherwise, you'll get a null ref error like you're seeing.

    For example, it should look something like this:

    myapp.Location_View.ServedGuests_render = function (element, contentItem) {

       // Write code here.

       displayMonthlyChart();

       function displayMonthlyChart() {

           var reportsAPI = "../reports/seatedGuests/?period=monthly&id=" + contentItem.screen.Location.Location_Id +

           "&beginDate=2010-07-20&endDate=2013-01-04";

       }

    };

Page 1 of 1 (9 items)