In this article, I will show you how to use the Kendo Grid in tandem with the Kendo Window with ColdFusion to implement a master-detail interface. We have covered both the Kendo Grid and the Kendo Window in previous articles and won't elaborate on all of the implementation details, but instead focus on how these two Kendo widgets work together to create a master-detail interface.



Master-Detail Interface Example Using the Kendo Grid and Window

The following example queries our World-State-City database and returns the cities that are located in Washington State. We have covered how to create Kendo Grids and Kendo Windows in previous articles, there is nothing new here other than a Kendo command button on the right side of the grid that is used to invoke JavaScript functions to open up a city details window. In this example, once the window is open, the city detail page displays the city and renders the location of the city in a Kendo Bing Map Tile Layer. We will cover the logic below.


Reviewing the Full Code

It may be helpful to open up the code to follow along by clicking on the buttons below. You don't need to comprehend the logic of the entire code, we will cover the essential elements and point the reader to our previous articles if you want to research the nuts and bolts of the code.


Linking Records in a Kendo Grid to a Kendo Window


Create a Custom Command Column in the Grid

Other than adding a few lines of code to create a custom command button, our approach to instantiate the grid here is no different than our previous 'Most Active ColdFusion Blogs' article. The main thing to note here is that we are creating a new button labeled 'Detail' in the last column in the grid, and invoking the showCityDetails JavaScript function when the button is clicked. 


}, { 
	command: 
	// Define multiple commands in an array
	[ 
		{ name: "details", text: "Detail", click: showCityDetails}
	], 
	title: " ", 
	width: "10%"
}]// columns:

Extracting the Values of the Selected Row From the Grid

The showCityDetails JavaScript function below simply gets the selected CityId found in the grid's CityId field and passes it to the createCityWindow function. 

It's important to note that we can obtain any value from the row that is declared in the grid. For example, if you want to pass the CountryId instead, change the dataItem['CityId'] to dataItem['CountryId']. You're also not limited to numeric values, you can also pass text fields, such as dataItem['Country']. See https://docs.telerik.com/kendo-ui/api/javascript/ui/grid/methods/dataitem for more information.


function showCityDetails(e){
	e.preventDefault();
	// Get the Id
	var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
	// Get the cityId
	selectedId = (dataItem['CityId']);
	// Open the window
	createCityWindow(selectedId);
}

Create a Function to Open a Kendo Window with the Selected Id

This function takes the CityId and opens up a new dynamic Kendo Window that will be appended to the document body. The content of the new window will be fetched from the /blog/demo/WorldDb/city.cfm?cityId=xxx template on the server. The CityId will be passed to this template via the URL. For more information, please see our previous 'A Comprehensive Look at the Kendo Window'  article explaining this approach.


// Detail window script
function createCityWindow(id) {

	// Remove the window if it already exists
	if ($("#cityDynamicWindow").length > 0) {
		$("#cityDynamicWindow").parent().remove();
	}

	$(document.body).append('<div id="cityDynamicWindow"></div>');
	$('#cityDynamicWindow').kendoWindow({
		title: "City Details",
		actions: ["Minimize", "Maximize", "Refresh", "Close"],
		modal: false,
		resizable: true,
		draggable: true,
		width: "75%",
		height: "65%",
		iframe: false, // Don't use iframes unless it is content derived outside of your own site. 
		content: "/blog/demo/WorldDb/city.cfm?cityId=" + id,
		close: function() {
			setTimeout(function() {
				$('#cityDynamicWindow').kendoWindow('destroy');
			}, 200);
		}
	}).data('kendoWindow').center();// Centers the window
}

Create the Detail Template

Much of the following code should be easily understood by a ColdFusion programmer. Here, we are querying the database using the CityId that was passed via the URL and outputting the city name below. 

We are also using the longitude and latitude information to render a Bing map in a Kendo Map control. We will cover how to use Bing Maps API in our next article.


<cfquery name="Data" datasource="#dsn#">
	SELECT
		CountryId
		,Country
		,Capital
		,Currency
		,CurrencyName
		,ISO2
		,ISO3
		,Flag
		,Latitude
		,Longitude
		,StateId
		,State
		,StateFlag
		,Type
		,CityId
		,City
		,CityLatitude
		,CityLongitude
		,CityFlag
	FROM ViewCountryStateCity
	WHERE CityId = <cfqueryparam value="#URL.cityId#" cfsqltype="integer">
</cfquery>
</cfsilent>	
<cfoutput>
<h2><cfoutput>Map of #Data.City#</cfoutput></h2>
</cfoutput>
	
<div id="mapViewer" style="width:90%; height: 85%">
    
     <div id="map"></div>
	
    <script>
        
        function createMap() {
			//  Creating a document ready function inside of a JavaScript function often clears up any wierd issues with the window not being initialized while still allowing the function to be called outside of the document ready scope.
			$( document ).ready(function() {
				$("#map").kendoMap({
					center: <cfoutput>[#Data.CityLatitude#, #Data.CityLongitude#]</cfoutput>,
					zoom: 12,
					layers: [{
						type: "bing",
						imagerySet: "aerialWithLabels",
						// IMPORTANT: This key is locked to gregoryalexander.com
						// If you copy my code, please replace with your own Bing Key
						key: "AqLDTaLtbFD4nnlRDwPqI7KU8wP5L0D3l00IUgi0r_XXRqHyCdsNSuKexIaojd8W"
					}],
					layerDefaults: {
						marker: {
							shape: "customMarker",
							tooltip: {
								animation: {
									open: {
										effects: "fade:in",
										duration: 1000
									}
								}
							}
						}
					},
					markers: [{
						location: <cfoutput>[#Data.CityLatitude#, #Data.CityLongitude#]</cfoutput>,
						shape: "customMarker",
						tooltip: {
							content: "<cfoutput>#Data.City#</cfoutput>"
						}
					}]
				});
						  
			});//..$( document ).ready(function() {
    	}

    	$(document).ready(createMap);
    
    </script>
	<style>
      .k-map .k-i-marker-custom-marker {
        background-image: url('/images/symbol/mapMarkerButton.gif');/*images/symbol/mapMarker.gif */
        width: 59px;/* 30px */
        height: 59px; /* 41px */
      }
    </style>
    
</div>

Final Thoughts

It should be noted that this type of interface is very common and I have probably coded this linkage between a grid and a window several hundreds of times over the course of my career. I have made the process fairly generic and easy to replicate, just copy the code and change some of the lines as necessary. I have also programmed various code generators to do this programmatically and will share them in a future post. 

Further Reading

Master the Master-Detail Pattern