Open a Detail View When the Grid Row is Clicked in the Dashboard (Blazor)
- 4 minutes to read
This topic describes how to invoke a Detail View when a user clicks a row in GridDashboardItem. In the invoked Detail View, a user can view or edit a business object corresponding to the clicked row.
This example consists of the following parts:
- Dashboard Hidden Measure
Allows you to get an identifier of an object displayed in a clicked row. - Client-Side Script
Handles row clicks and delegates Detail View invocation to the server side. - Server-Side Controller
Registers a reference to itself on the client side and opens the Detail View.
Add a Dashboard Hidden Measure
Add a key property to the Dashboard hidden measures and set the summary type to Min or Max. The key property in this example is Oid. Since Oid values are unique in the underlying dataset, the Min or Max function generates a list of identifiers that are unique within the aggregated data. This associates each row with Oid of the underlying object.
Create a Client-Side Script
In your Blazor application project (MySolution.Blazor.Server), add a new JavaScript file to the wwwroot/js folder. In this file, declare an object (customScript) and implement the following methods in it:
- registerController
- Stores a reference to the server-side Controller that calls this method.
- processItemClick
- A callback that retrieves the ID of the object clicked in the Dashboard grid item and passes this ID to the server-side Controller’s ShowDetailView method.
- onBeforeRender
- Registers processItemClick as a callback that the Dashboard control invokes when a user clicks a grid row.
File: MySolution.Blazor.Server\wwwroot\js\customScript.js.
"use strict";
globalThis.customScript = {
showDetailViewController: null,
onBeforeRender: function (dashboardControl) {
const viewerApi = dashboardControl.findExtension("viewerApi");
viewerApi.on("itemClick", globalThis.customScript.processItemClick);
},
registerController: function (controller) {
globalThis.customScript.showDetailViewController = controller;
},
processItemClick: function (args) {
const itemData = args.getData(),
dataSlice = itemData.getSlice(args.getAxisPoint()),
oidMeasure = dataSlice.getMeasures().find((measure) => measure.dataMember === 'Oid').id,
measureValue = dataSlice.getMeasureValue(oidMeasure),
objectId = measureValue.getValue();
globalThis.customScript.showDetailViewController.invokeMethodAsync("ShowDetailView", objectId);
}
}
In the same file, create the globalThis.xafBlazorDashboardUserScripts array if it does not exist and add the customScript object to it. This ensures that the object’s onBeforeRender method is called before the Dashboard control is rendered.
File: MySolution.Blazor.Server\wwwroot\js\customScript.js.
// ...
if (!globalThis.xafBlazorDashboardUserScripts) {
globalThis.xafBlazorDashboardUserScripts = [];
}
globalThis.xafBlazorDashboardUserScripts.push(globalThis.customScript);
Reference this script in the _Host.cshtml file in a <script>
tag:
File: MySolution.Blazor.Server\Pages\_Host.cshtml.
<!-- ... -->
<html lang="en">
<!-- ... -->
<body>
<!-- ... -->
<script src="_framework/blazor.server.js"></script>
<script src="js/customScript.js"></script>
<!-- ... -->
</body>
</html>
Create a Server-Side Controller
Declare a BlazorShowDetailViewFromDashboardController ObjectViewController<ViewType, ObjectType> with the DetailView and IDashboardData generic parameters in the ASP.NET Core Blazor module project (MySolution.Module.Blazor). If your solution does not contain this project, add this Controller to the application project (MySolution.Blazor.Server). Customize the Controller as outlined below:
- Create a DotNetObjectReference that stores the reference to this Controller.
- In the overridden OnActivated method, use the IJSRuntime service to register a reference to this Controller on the client side. To do this, call the customScript.registerController method with this reference.
- Declare the ShowDetailView method and decorate it with the JSInvokable attribute. This method is called from the client side and opens the Detail View for the clicked object.
File:
MySolution.Blazor.Server\Controllers\BlazorShowDetailViewFromDashboardController.cs in solutions without the ASP.NET Core Blazor-specific module project.
MySolution.Module.Blazor\Controllers\BlazorShowDetailViewFromDashboardController.cs in solutions with the ASP.NET Core Blazor-specific module project.
using System;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Blazor;
using DevExpress.Persistent.Base;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
// ...
public class BlazorShowDetailViewFromDashboardController : ObjectViewController<DetailView, IDashboardData> {
private IJSRuntime JSRuntime { get; set; }
private DotNetObjectReference<BlazorShowDetailViewFromDashboardController> controllerReference;
public BlazorShowDetailViewFromDashboardController() {
controllerReference = DotNetObjectReference.Create(this);
}
protected override void OnActivated() {
base.OnActivated();
var application = (BlazorApplication)Application;
JSRuntime = application.ServiceProvider.GetRequiredService<IJSRuntime>();
_ = JSRuntime.InvokeVoidAsync("customScript.registerController", controllerReference).Preserve();
}
protected override void Dispose(bool disposing) {
base.Dispose(disposing);
controllerReference.Dispose();
}
[JSInvokable]
public void ShowDetailView(string oidString) {
if(!Guid.TryParse(oidString, out var oid)) {
return;
}
var objectSpace = Application.CreateObjectSpace(typeof(Employee));
var item = objectSpace.FirstOrDefault<Employee>(employee => employee.Oid == oid);
if(item is not null) {
var detailView = Application.CreateDetailView(objectSpace, item);
Frame.SetView(detailView);
}
else {
objectSpace.Dispose();
}
}
}