Data presentation is a key application in the RIA application. Various JavaScript frameworks also provide their own grid widgets to present table-class data. Treegrid, as a special grid, has the advantages of multi-layer tree structure and complex data display of multiple data items in the grid, is a good control for processing complex multi-level data. However, for tree or treegrid, due to various implementation restrictions, the delayed loading of data is only applicable to hierarchical structures, that is, when a node is expanded, all subnodes under the node are instantly requested. Although this can basically meet requirements for general application scenarios, when the data structure of secondary nodes is complex and there are many nodes, it may cause extremely serious performance problems. To address this specific requirement, dojo has launched a brand new control, lazytreegrid, from 1.6.
As an extension of the dojo DataGrid, lazytreegrid still adopts the MVC structure in the overall data structure. Lazytreegrid Structure
Figure 1. lazytreegrid Structure Model
Figure 1 is a basic architecture model of treegrid. In terms of the overall structure, lazytreegrid is not much different from treegrid and DataGrid. A view is a directly visible part of a grid, including the grid header, row, column, cell, and treegrid-specific node expansion buttons, the entire treegrid obtains data and constructs content through the rolling event of the virtual scroll bar in the content view and the trigger of the expand or close event of the node expand button expando.
However, to meet the paging delay loading and rendering functions for secondary nodes, lazytreegrid needs to be scaled in the model and view sections based on the tree hierarchy. The following describes the design idea and implementation method of lazytreegrid based on its data model and view structure.
Lazytreegrid Data Model
Tree data in normal state is in hierarchical nesting mode, as shown in the following example:
data = { identifier: 'id',label: 'name', items: [ { id: 'AF',name: 'Africa', children: [ { id: 'EG', name: 'Egypt' }, { id: 'KE', name: 'Kenya', children: [ { id: 'Nairobi', name: 'Nairobi', type: 'city' }, { id: 'Mombasa', name: 'Mombasa',type: 'city' } ] }, ... ] }, ... ]}
Similar to the Data Implementation requirements of other tree-type applications designed for delayed loading, data on the parent node needs to be flattened for the purpose of delayed loading of secondary data, separate it from the child node in the structure so that only the required parent node data can be loaded during the initial data request, the secondary data under the parent node is loaded only when the parent node is expanded. In addition, in lazytreegrid, if the number of some sub-nodes is small and loading does not need to be delayed, data nodes that are not flattened are also allowed, as shown in the following example:
data = { identifier: 'id',label: 'name', items: [ { id: 'AF', name: 'Africa',children: 10 }, { id: 'EG', name: 'Egypt',children: false }, { id: 'KE',name: 'Kenya', children: [ { id: 'Nairobi',name: 'Nairobi',type: 'city' }, { id: 'Mombasa', name: 'Mombasa',type: 'city' } ] }, ... ]}
The data structure required by lazytreegrid allows the parent node to replace the original nested data with a positive integer or Boolean value to represent the number of subnodes or whether there are subnodes (false, if the node is not a positive number or has no corresponding attribute, the node does not have a subnode ). It should be noted that lazytreegrid requires that the data must have a unique primary key ID, so that the server can use this ID to request the child data of the corresponding data entry.
In the lazytreegrid Data Model section, in addition to the original datastore (Dojo data storage) of the DataGrid, The datastore of dojo itself has insufficient support for APIs of the tree data structure, in addition, a treemodel is added to provide specific support for tree structure data. To meet the requirements of paging to load secondary data, lazytreegrid implements a special treemodel: dojox. grid. lazytreegridstoremodel is mainly used to establish a backend Data Acquisition protocol. by specifying the sequence of parent nodes and child nodes, the server returns the corresponding paging data correctly. When requesting secondary data, lazytreegrid will send a request similar to the following to the backend server:
Http: // localhost: 8080/treegrid/fakedataservlet? Parentid = root1 & START = 0 & COUNT = 25
Here, parentid is the parent node ID of the data to be requested, and start and count represent the subnode sequence at the beginning of the request and the number of requested nodes respectively.
The following code creates a simple lazytreegridstoremodel:
// programmaticvar treeModel = new dojox.grid.LazyTreeGridStoreModel({ store: queryReadStore, serverStore: true});// declarative<span data-dojo-type="dojox.grid.LazyTreeGridStoreModel" data-dojo-props="store:queryReadStore, serverStore:true" ></span>
To create a lazytreegridstoremodel, You Need To determine two parameters: store and serverstore. Store is used to specify the dojo datastore for obtaining data. serverstore receives a Boolean value, it is used to determine whether data is transmitted by the server and whether data entries are stored and transmitted in a flattened manner (the delayed loading mode is not required for data stored on the client ). If the secondary data volume is small and you do not need to load the child data by page, you can also choose to use the original dijit. Tree. foreststoremodel of dojo.
Lazytreegrid View)
The existing dojo. grid. treegrid adopts the view Construction Method to think that all the child nodes are content extensions of the parent node at the upper level, that is, all the expanded child node structures are rendered within one row, as shown in:
Figure 2. dojox. Grid. treegrid View
In this example, rowselector is the leftmost part of each row in the grid. The row selection button is used according to the rowselector allocation, we can clearly see that the row structure is divided by the first level node.
Although this approach is not inappropriate in terms of the overall view structure, the treegrid reuse the row-by-row structure of the DataGrid for paging delay loading and rendering mechanisms, therefore, the content of all rows on the current page will be loaded and rendered at one time. When there are many secondary nodes and complex nodes, such loading, especially the resource consumption and response time caused by rendering, will become very prominent and unbearable.
In lazytreegrid, based on the data preprocessing in the data model, the data is separated based on the level information retained, in this way, all data can be loaded and rendered as an independent data row in the view. As shown in figure 3, each piece of data is a separate row. Therefore, even if the data contains many secondary nodes, the hierarchical structure is also ignored, and only the grid page configuration is divided to delay loading and rendering of data entries, thus greatly improving the performance.
Figure 3. lazytreegrid View
Other features in lazytreegrid
In tree-structured data, different levels of data entries may have different data columns. More often, the upper-level data is the summary data, secondary data exists as detailed data. Therefore, in this case, users may need to customize different expressions for different levels of data. To meet this requirement, lazytreegrid supports cell merging and hierarchical data formatting respectively.
Figure 4. lazytreegrid instance
Figure 4 is an example of a simple storage management table. The top-level data is the storage group. The second-level and third-level data are physical disks and Virtual Disks. In this example, a hierarchical merge cell and hierarchical cell formatting is performed based on the inconsistency between the root-level data and the secondary data to make the overall view clearer and clearer.
To merge cells in a hierarchical manner, you must add a colspans attribute to lazytreegrid:
colSpans: {0: [ {start: 0, end: 1}, {start: 2, end: 3, primary: 2}], 1: […], 2:… }
The colspans property receives a JSON object with the key 0/1/2 /... Corresponding to each level, the value is used to specify the details of cell merging. Start indicates merging from the first cell, and end indicates merging to the first cell (both with 0 as the starting value ), primary indicates that the content of the cells to be merged is displayed. If no value is specified, the default value is the value of start.
The hierarchical cell formatting inherits the same formatting method as the cell formatting method of the DataGrid, that is, the formatter function is set for each column separately. The difference is that, the third parameter of the provided formatter function is the level of the row data. The following example shows a simple formatter function:
var fmtByLevel = function(value, idx, level) { return level == 0 ? "root" : level == 1 ? "2nd" : "3rd";};
Lazytreegrid
The following describes how to build a lazytreegrid based on the example in Figure 4.
In short, because lazytreegrid inherits from the DataGrid, its basic creation process is basically the same as that of the DataGrid. The main difference is that the treemodel needs to be added between the grid and datastore. The following is a front-end code example for creating lazytreegrid using JS programming.
First, you need to define the view structure of lazytreegrid:
// Lazytreegrid structure definition var layout = [{name: "name", field: "name", width: "150px", formatter: fmtname}, {name: "status ", field: "status", width: "40px", formatter: fmtstatus}, {name: "capacity", field: "capacity", width: "80px", formatter: fmtcapacity}, {name: "uid", field: "uid", width: "240px"}];
Layout mainly defines the grid column name, column width, and corresponding value data items. In addition, we can see that three formatter functions are defined for the first three columns, defines the format of cells for classification. The fmtcapacity function uses a child widget that returns a progressbar for the first level of data:
// progress bar formattervar fmtCapacity = function (value, idx, level) { return level == 0 new dijit.ProgressBar({ progress: value * 100, maximum: 100, report: function (percent) { return (percent * 100).toFixed(2) + "% Storage Online"; } }): value + "GB"; };
Datastore uses dojox. Data. queryreadstore to obtain data through a servlet in the same domain, and creates a lazytreegridstoremodel based on this datastore to connect to lazytreegrid. The following code is shown:
// Create datastorevar queryreadstore = new dojox. data. queryreadstore ({ID: "queryreadstore", URL: "fakedataservlet"}); // create treemodelvar treemodel = new dojox. grid. lazytreegridstoremodel ({ID: "treemodel", serverstore: True, store: queryreadstore });
Finally, we need to put a div with ID 'gridcontainer 'in the page as the container element of lazytreegrid, and create and initialize lazytreegrid after the page is loaded:
// Create lazytreegridvar grid; dojo. addonload (function () {grid = new dojox. grid. lazytreegrid ({ID: "Grid", rowselector: True, treemodel: treemodel, structure: layout, colspans: {0: [{start: 0, end: 1}, & nbsp; {start: 2, end: 3, primary: 2}]}); dojo. byid ('gridiner iner '). appendchild (grid. domnode); grid. startup ();});
So far, we have completed lazytreegrid's page creation. The next step is to create appropriate background code to correctly respond to lazytreegrid's data requests.
Summary
As a new widget introduced by dojo1.6, although lazytreegrid still has many defects or problems that need to be solved urgently, for example, the expand/collapse all function during initialization and runtime is not yet supported, and the API can be called less. However, it is used as an RIA application widget to present complex multi-level data, the solution proposed by Alibaba Cloud for delayed loading and delayed rendering is still breakthrough. users who have application requirements in this area may try again.
This article has been first published on the infoq Chinese site. All Rights Reserved. The original Article is "lazytreegrid control in Dojo". If you need to reprint it, please attach this statement. Thank you.
Infoq Chinese site is an online independent community for mid-and high-end technical personnel ,. net, Ruby, SOA, agility, architecture and other fields to provide timely and in-depth information, high-end technology conferences such as qcon, offline technology exchange activities qclub, free mini book download such as architect, etc..