Developers always want to follow the latest technologies. Microsoft announced in June ASP.Net MVC 4 RC. Perhaps many of you are asking: how new versions of ASP.Net MVC work with existing components. This blog is a quick review how you can use Infragistics jQuery controls with MVC 4.
The latest NetAdvantage for jQuery Vol. 12.1 includes many new exciting components and many feature enhancements to existing controls. You could find a detailed information about the existing controls in the Infragistics jQuery blogs.
One of the advantages to using nice client components as those in NetAdvantage for jQuery is the ability to create quickly beautiful dashboards in your WEB applications using pre-defined styles and themes. ASP.Net MVC 4 offers better UI and possibility to easily create applications in Metro Style.
Before to start:
You need to install ASP.Net MVC 4 RC and NetAdvantage for jQuery Vol. 12.1. This demo is created with Visual Studio 2010Sp1. It is possible to create the project to create a similar manner and with Visual Studio 2012 RC
Scripts and styles references
In ASP.Net MVC4 you could place Infragistics css and js files in the same place like in ASP.Net MVC 3 projects.
Infragistics recommends :
- styles to be placed under /Content/Infragistics folder
- JavaScript files location is under /Scripts/Infragistics folder
You can use another location and change the path to your files
ASP.Net MVC4 – Bundling
One of the handy new features in ASP.NET MVC 4 is the ability to easily bundle your JavaScript and CSS.
What means Bundling: this is the process of combining all of your disparate js and css files into one file (one for js and one for css).
When you create a new ASP.NET MVC 4 application, you will find this code in the Application_Start() event in the Global.asax:
1: protected void Application_Start()
2: {
3: ....
4: BundleConfig.RegisterBundles(BundleTable.Bundles);
5: }
You could configure your bundle using BundleConfig,cs
The code below demonstrates you you could add to your bundle Infragistics script loader.
1: public class BundleConfig
2: {
3: public static void RegisterBundles(BundleCollection bundles)
4: {
5: bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
6: "~/Scripts/jquery-1.*"));
7:
8: bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
9: "~/Scripts/jquery-ui*"));
10:
11: bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
12: "~/Scripts/jquery.unobtrusive*",
13: "~/Scripts/jquery.validate*"));
14:
15: bundles.Add(new ScriptBundle("~/bundles/infragistics.loader").Include(
16: "~/Scripts/Infragistics/js/infragistics.loader*"));
17:
18: bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
19: "~/Scripts/modernizr-*"));
20:
21: bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
22:
23: bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
24: "~/Content/themes/base/jquery.ui.core.css",
25: "~/Content/themes/base/jquery.ui.resizable.css",
26: "~/Content/themes/base/jquery.ui.selectable.css",
27: "~/Content/themes/base/jquery.ui.accordion.css",
28: "~/Content/themes/base/jquery.ui.autocomplete.css",
29: "~/Content/themes/base/jquery.ui.button.css",
30: "~/Content/themes/base/jquery.ui.dialog.css",
31: "~/Content/themes/base/jquery.ui.slider.css",
32: "~/Content/themes/base/jquery.ui.tabs.css",
33: "~/Content/themes/base/jquery.ui.datepicker.css",
34: "~/Content/themes/base/jquery.ui.progressbar.css",
35: "~/Content/themes/base/jquery.ui.theme.css"));
36: }
37: }
If you prefer to add script and styles references without bundling it is possible to use the script and styles references in the same way like in ASP.Net MVC 3. If you refer styles and scripts you need to know that the reference path starts from the site root – not from the current document location:
- /Scripts/Infragistics/js/[my resource] – MVC 4
instead
- ../../Scripts/Infragistics/js/[my resource] – MVC 3
If you want to use MVC wrappers there is another step:
MVC wrappers reference
In ASP.Net MVC 4 it is possible to use libraries, build against MVC 3. You can add reference to:
[NetAdvantage for jQuery install path]\MVC\MVC3\Bin\Infragistics.Web.Mvc.dll
Application design
The sample application is an ASP.Net MVC 4 Application, that uses Northwind sample database via Entity Framework. In the sample are used Infragistics jQuery Grid, Chart and Map (igGrid, igDataChart and igMap).
Application has views with dashboards about Northwind customers:
- JavaScript dashboard (uses Infragistics jQuery widgets)
- MVC dashboard (uses Infragistics MVC library)
Creating a dashboard using JavaScript
The easiest way to add Infragistics jQuery controls is via Infragistics Script Loader. This is the reason to include this library in the bundle. Infragistics Loader is used via JavaScript in the same way like in other types of projects (see the code below) . The only one difference is in the path used when load other scripts – path starts from the site root – not from the current document location!
1: $.ig.loader({
2: scriptPath: "/Scripts/Infragistics/js/", //local files version
3: cssPath: "/Content/Infragistics/css/",
4: resources: "igGrid.Selection.Paging.Sorting,igMap,igDataChart.*",
5: theme: "metro"
6: });
Using Infragistics jQuery controls.
NetAdvantage for jQuery controls could be included via JavaScript in the same way like in other project types.
1: $("#map").igMap({
2: width: "500px",
3: height: "500px",
4: panModifier: "control",
5: horizontalZoomable: true,
6: verticalZoomable: true,
7: windowResponse: "immediate",
8: overviewPlusDetailPaneVisibility: "visible",
9: seriesMouseLeftButtonUp: function (ui, args) {
10: var tets = args;
11: }
12: });
The code below shows the whole script, used for JavaScript Dashboard
1: <script type="text/javascript">
2: jQuery.support.cors = true;
3: $.ig.loader({
4: scriptPath: "/Scripts/Infragistics/js/", //local files version
5: cssPath: "/Content/Infragistics/css/",
6: resources: "igGrid.Selection.Paging.Sorting,igMap,igDataChart.*",
7: theme: "metro"
8: });
9: $.ig.loader(function () {
10: var data = [];
11: var selected;
12:
13: $("#map").igMap({
14: width: "500px",
15: height: "500px",
16: panModifier: "control",
17: horizontalZoomable: true,
18: verticalZoomable: true,
19: windowResponse: "immediate",
20: overviewPlusDetailPaneVisibility: "visible",
21: seriesMouseLeftButtonUp: function (ui, args) {
22: var tets = args;
23: }
24: });
25:
26:
27: $("#chart").igDataChart({
28: width: "650px",
29: height: "220px",
30: dataSource: "/Home/Orders",
31: axes: [{ name: "xAxis", type: "categoryX", label: "OrderID", labelVisibility: "visible" },
32: { name: "yAxis", type: "numericY", labelVisibility: "visible"}],
33: series: [
34: { name: "series",
35: title: "Order Freight Series",
36: type: "line",
37: xAxis: "xAxis",
38: yAxis: "yAxis",
39: valueMemberPath: "Freight", trendLineThickness: 6, thickness: 4,
40: trendLineBrush: "cyan",
41: transitionDuration: 1500,
42: trendLineType: "exponentialAverage"
43: }],
44: horizontalZoomable: true,
45: verticalZoomable: true,
46: windowResponse: "immediate",
47: overviewPlusDetailPaneVisibility: "visible"
48: });
49:
50: $('#grid').igGrid({
51: virtualization: false, height: 280, width: 650,
52: dataSource: "/Home/Customers",
53: autoGenerateColumns: false,
54: columns: [
55: { headerText: "Customer ID", key: "CustomerID", width: "120px", dataType: "string" },
56: { headerText: "Country", key: "Country", width: "150px", dataType: "string" },
57: { headerText: "City", key: "City", dataType: "string" },
58: { headerText: "Contact Name", key: "ContactName", dataType: "string" },
59: {headerText: "Phone", key: "Phone", dataType: "string" }
60: ],
61: features: [
62:
63: {
64: name: 'Selection',
65: mode: 'row',
66: multipleSelection: false,
67: rowSelectionChanged: function (ui, args) {
68: $("#chart").igDataChart({
69: dataSource: "/Home/Orders?userID=" + args.row.element[0].cells[0].textContent
70: });
71:
72: selected = args.row.element[0].cells[0].textContent; //keep track of selected user
73: var url = "http://nominatim.openstreetmap.org/search/" + args.row.element[0].cells[1].textContent + "?format=json";
74: $.getJSON(url,
75: function (json, text) {
76: var name, lat, lon;
77: $.each(json, function (index, value) {
78: if (value.class === "place" && value.type === "country") {
79: name = value.display_name;
80: lat = parseFloat(value.lat);
81: lon = parseFloat(value.lon);
82: //alert(lat);
83: }
84: });
85: data = [{ Name: name, Latitude: lat, Longitude: lon}];
86: //add or override existing series named 'Countries'
87: //adding this series *after* the shapefile ones will cause the markers to appear above the shape lines, which is what we want
88: $("#map").igMap({
89: series: [{
90: name: "Countries",
91: type: "geographicSymbol",
92: longitudeMemberPath: "Longitude",
93: latitudeMemberPath: "Latitude",
94: /*
95: The provided object should have properties called render and optionally measure.
96: These are functions which will be called that will be called to handle the user specified custom rendering.
97: */
98: markerTemplate: {
99: render: function (renderInfo) {
100: var ctx = renderInfo.context; //2d canvas context
101: var x = renderInfo.xPosition;
102: var y = renderInfo.yPosition;
103:
104: if (renderInfo.isHitTestRender) {
105: // This is called for tooltip hit test only
106: // Rough marker rectangle size calculation
107: ctx.fillStyle = "yellow";
108: ctx.fillRect(x, y, renderInfo.availableWidth, renderInfo.availableHeight);
109: } else {
110: //actual marker drawing is here:
111: var markerData = renderInfo.data;
112: var name = markerData.item()["Name"];
113: //set font or measure will be for the default one
114: ctx.font = '10pt Segoe UI';
115: var textWidth = ctx.measureText(name).width;
116:
117: //Move the path point to the desired coordinates:
118: ctx.moveTo(x, y);
119: //Draw lines:
120: ctx.beginPath();
121: ctx.lineTo(x - (textWidth / 2) - 5, y + 5);
122: ctx.lineTo(x - (textWidth / 2) - 5, y + 40); // 35width rect.
123: ctx.lineTo(x + (textWidth / 2) + 5, y + 40); // full textWidth line plus 5 margin
124: ctx.lineTo(x + (textWidth / 2) + 5, y + 5); // 35 up
125: ctx.lineTo(x, y);
126: //finish the shape
127: ctx.closePath();
128: ctx.fillStyle = "rgba(78,183,226,0.7)";
129: ctx.fill();
130: ctx.lineWidth = 0.5;
131: ctx.strokeStyle = "#185170";
132: ctx.stroke();
133: //add a point at the start
134: ctx.beginPath();
135: ctx.fillStyle = "black";
136: ctx.arc(x, y, 1.5, 0, 2 * Math.PI, true);
137: ctx.fill();
138:
139: // Draw text
140: ctx.textBaseline = "top";
141: ctx.fillStyle = "black";
142: ctx.textAlign = 'center';
143: ctx.fillText(selected, x, y + 8);
144: ctx.fillText(name, x, y + 20);
145: }
146: }
147: },
148: dataSource: data
149: }]
150: });
151: //}
152: });
153:
154: }
155: }
156: ,
157:
158: {
159: name: 'Sorting',
160: type: "remote"
161: },
162: {
163: name: 'Paging',
164: type: "local",
165: pageSize: 10
166: }]
167: ,
168: rendered: function (ui, args) {
169: //set up on-load selection
170: $('#grid').igGridSelection("selectRow", 0);
171: //another way to get cell value independant of event parameters
172: var id = $('#grid').igGrid("getCellValue", 0, "CustomerID");
173: $("#chart").igDataChart({
174: dataSource: "/Home/Orders?userID=" + id
175: });
176:
177:
178: }
179: });
180: });
181: </script>
You could see below the HTML, which defines the view layout
1: <div style="display: block; height: 500px; width: 1155px;">
2: <div style="float: left; width:650px; height: 280px; margin-right: 5px;">
3: <table id="grid">
4: </table>
5: </div>
6: <div style="float: right; top: -280px; height: 500px; width: 500px;">
7: <div id="map" />
8: </div>
9: <div style="position: relative; width: 650px; height: 260px; top: -220px; left: -650px; margin-right: 5px;">
10: <div id="chart" />
11: </div>
12:
13: </div>
Application start page
JavaScript dashboard in action!
No worries! Everything works. Dashboard presents Northwind customers. When you select a specific customer from the grid you could see customer orders in the chart and his country (you will see a pushpin, that shows the county on the map).
Creating a dashboard using MVC Wrappers
The next step is to see how MVC libraries, built against MVC 3 work in ASP.Net MVC.4 projects. Infragistics.Web.Mvc library contains MVC wrappers of the Infragistics jQuery components. The whole logic is related with the application UI and you could use it without any issues in MVC 4 applications.
MVC Dashboard view demonstrates how you could use MVC wrappers.
The first step is to add Infragistics Script Loader with Razor. You could use the wrapper in the same way like in MVC 3 projects. The resources path should be started from the application root (like for the JavaScript dashboard).
1: @using Infragistics.Web.Mvc;
2:
3: @(Html.Infragistics().Loader()
4: .ScriptPath(Url.Content("/Scripts/Infragistics/js/"))
5: .CssPath(Url.Content("/Content/Infragistics/css/"))
6: .Theme("metro")
7: .Render()
8: )
The layout should be created like MVC 3 view layout with Razor – no changes!
1: <div style="display: block; height: 500px; width: 1155px;">
2: <div style="float: left; width:650px; height: 280px; margin-right: 5px;">
3: @(Html.Infragistics().Grid<jQueryMapMVC4Demo.Customer>()
4: .DataSourceUrl("/Home/Customers").ResponseDataKey("")
5: .ID("grid").Width("650px").Height("280px")
6: .LoadOnDemand(false)
7: .AutoGenerateColumns(false)
8: .Columns(column =>
9: {
10: column.For(x => x.CustomerID).HeaderText("Customer ID").Width("120px").DataType("string");
11: column.For(x => x.Country).HeaderText("Country").Width("150px").DataType("string");
12: column.For(x => x.City).HeaderText("City").Width("120px").DataType("string");
13: column.For(x => x.ContactName).HeaderText("Contact Name").DataType("string").Width("140px");
14: column.For(x => x.Phone).HeaderText("Phone").DataType("string").Width("120px");
15: })
16: .Features(features =>
17: {
18: features.Paging().Type(OpType.Local).VisiblePageCount(5).ShowPageSizeDropDown(true).PageSize(10).PrevPageLabelText("Previous").NextPageLabelText("Next");
19: features.Sorting().Mode(SortingMode.Single).ColumnSettings(settings =>
20: {
21: settings.ColumnSetting().ColumnKey("CustomerID").AllowSorting(true);
22:
23: });
24: features.Selection().MouseDragSelect(true).MultipleSelection(false).Mode(SelectionMode.Row);
25: })
26: .Width("650")
27: .DataBind()
28: .Render()
29: )
30: </div>
31: <div style="float: right; top: -280px; height: 500px; width: 500px;">
32: @(Html.Infragistics().Map()
33: .ID("map")
34: .Width("500px").Height("500px")
35: .VerticalZoomable(true)
36: .HorizontalZoomable(true)
37: .OverviewPlusDetailPaneVisibility(Visibility.Visible)
38: .BackgroundContent(bgr => bgr.OpenStreetMaps())
39: .PanModifier(ModifierKeys.Control)
40: .WindowResponse(WindowResponse.Immediate)
41: //.WindowRect(0.27, 0.20, 0.5, 0.5)
42: .DataBind()
43: .Render()
44: )
45: </div>
46: <div style="position: relative; width: 650px; height: 220px; top: 280px; margin-right: 5px;">
47: @( Html.Infragistics().DataChart<jQueryMapMVC4Demo.Order>().DataSourceUrl("/Home/Orders").ResponseDataKey("")
48: .ID("chart")
49: .Width("650px")
50: .Height("220px")
51: .VerticalZoomable(true)
52: .HorizontalZoomable(true)
53: .Axes(axes =>
54: {
55: axes.CategoryX("xAxis").Label(item => item.OrderID).LabelVisibility(Visibility.Visible);
56: axes.NumericY("yAxis");
57: })
58: .Series(series =>
59: {
60: series
61: .Line("series").Title("Order Freight Series")
62: .XAxis("xAxis").YAxis("yAxis")
63: .ValueMemberPath(item => item.Freight).ValueMemberPath("Freight").TrendLineThickness(6).TrendLineBrush("blue")
64: .TrendLineType(TrendLineType.ExponentialAverage).TransitionDuration(1500)
65: .Thickness(4);
66: })
67: .DataBind()
68: .Render()
69: )
70: </div>
71:
72: </div>
When you are using live events there also no changes.
1: <script type="text/javascript">
2: var data = [];
3: var selected;
4: $('#grid').live('iggridselectionactiverowchanged', function (event, args) {
5: //set data chart source
6: $("#chart").igDataChart({
7: dataSource: "/Home/Orders?userID=" + args.row.element[0].cells[0].textContent
8: });
9: //set map series
10: selected = args.row.element[0].cells[0].textContent; //keep track of selected user
11: var url = "http://nominatim.openstreetmap.org/search/" + args.row.element[0].cells[1].textContent + "?format=json";
12:
13: $.getJSON(url,
14: function (json, text) {
15: var name, lat, lon;
16: $.each(json, function (index, value) {
17: if (value.class === "place" && value.type === "country") {
18: name = value.display_name;
19: lat = parseFloat(value.lat);
20: lon = parseFloat(value.lon);
21: //alert(lat);
22: }
23: });
24: data = [{ Name: name, Latitude: lat, Longitude: lon}];
25: //add or override existing series named 'Countries'
26: //adding this series *after* the shapefile ones will cause the markers to appear above the shape lines, which is what we want
27: $("#map").igMap({
28: series: [{
29: name: "Countries",
30: type: "geographicSymbol",
31: longitudeMemberPath: "Longitude",
32: latitudeMemberPath: "Latitude",
33: /*
34: The provided object should have properties called render and optionally measure.
35: These are functions which will be called that will be called to handle the user specified custom rendering.
36: */
37: markerTemplate: {
38: render: function (renderInfo) {
39: var ctx = renderInfo.context; //2d canvas context
40: var x = renderInfo.xPosition;
41: var y = renderInfo.yPosition;
42:
43: if (renderInfo.isHitTestRender) {
44: // This is called for tooltip hit test only
45: // Rough marker rectangle size calculation
46: ctx.fillStyle = "yellow";
47: ctx.fillRect(x, y, renderInfo.availableWidth, renderInfo.availableHeight);
48: } else {
49: //actual marker drawing is here:
50: var markerData = renderInfo.data;
51: var name = markerData.item()["Name"];
52: //set font or measure will be for the default one
53: ctx.font = '10pt Segoe UI';
54: var textWidth = ctx.measureText(name).width;
55:
56: //Move the path point to the desired coordinates:
57: ctx.moveTo(x, y);
58: //Draw lines:
59: ctx.beginPath();
60: ctx.lineTo(x - (textWidth / 2) - 5, y + 5);
61: ctx.lineTo(x - (textWidth / 2) - 5, y + 40); // 35width rect.
62: ctx.lineTo(x + (textWidth / 2) + 5, y + 40); // full textWidth line plus 5 margin
63: ctx.lineTo(x + (textWidth / 2) + 5, y + 5); // 35 up
64: ctx.lineTo(x, y);
65: //finish the shape
66: ctx.closePath();
67: ctx.fillStyle = "rgba(78,183,226,0.7)";
68: ctx.fill();
69: ctx.lineWidth = 0.5;
70: ctx.strokeStyle = "#185170";
71: ctx.stroke();
72: //add a point at the start
73: ctx.beginPath();
74: ctx.fillStyle = "black";
75: ctx.arc(x, y, 1.5, 0, 2 * Math.PI, true);
76: ctx.fill();
77:
78: // Draw text
79: ctx.textBaseline = "top";
80: ctx.fillStyle = "black";
81: ctx.textAlign = 'center';
82: ctx.fillText(selected, x, y + 8);
83: ctx.fillText(name, x, y + 20);
84: }
85: }
86: },
87: dataSource: data
88: }]
89: });
90:
91: });
92:
93: });
94:
95: $('#grid').live('iggridrendered', function (event, args) {
96: $('#grid').igGridSelection("selectRow", 0);
97: //another way to get cell value independant of event parameters
98: var id = $('#grid').igGrid("getCellValue", 0, "CustomerID");
99: $("#chart").igDataChart({
100: dataSource: "/Home/Orders?userID=" + id
101: });
102: });
103: ript>
Congratulations! You have a real MVC 4 dashboard with the Infragistics jQuery controls.
If you want to move forward and start using ASP.Net MVC 4 you could use all your jQuery stuff and it’s MVC 3 wrappers.
You can find ASP.Net MVC 4 Demo project here. Northwind sample database is available here.
As always, you can follow us on Twitter: @mihailmateev and @Infragistics , all tweets with hashtag #infragistcs and stay in touch on Facebook, Google+ , LinkedIn and Infragistics Friends User Group !