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 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 thecustomScript.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
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();
}
}
}