{"id":13608,"date":"2025-03-20T19:32:04","date_gmt":"2025-03-20T16:32:04","guid":{"rendered":"https:\/\/dhtmlx.com\/blog\/?p=13608"},"modified":"2025-03-20T20:22:57","modified_gmt":"2025-03-20T17:22:57","slug":"key-aspects-creating-javascript-pivot-grid-dhtmlx-widgets","status":"publish","type":"post","link":"https:\/\/dhtmlx.com\/blog\/key-aspects-creating-javascript-pivot-grid-dhtmlx-widgets\/","title":{"rendered":"Key Aspects of Creating a JavaScript Pivot Grid with DHTMLX Widgets"},"content":{"rendered":"<p>The latest <a href=\"https:\/\/www.capterra.com\/resources\/tech-trends-business-software-buying\/\" rel=\"noopener\" target=\"_blank\">Capterra\u2019s Tech Trends Survey<\/a> names data management as one of the main challenges finance businesses face when adopting new software solutions. Ready-made tools may not be flexible enough to meet specific requirements. Therefore, it is reasonable for organizations to consider investing in custom solutions like pivot grids to cover their data management and analysis needs. <\/p>\n<p>In this article, we&#8217;ll consider one of our new integration demos, comprising DHTMLX Grid and Pivot. Here we will highlight some technical tricks used by our dev team for creating a JavaScript pivot grid with these widgets.<\/p>\n<h5>Example of a JavaScript Pivot Grid Made with DHTMLX Grid and Pivot<\/h5>\n<p>DHTMLX Grid is a popular <a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxGrid\/\" rel=\"noopener\" target=\"_blank\">JavaScript datagrid widget<\/a> for handling tabular data, and its latest version (9.1) brings in great new PRO features such as row expander and multi-sorting. But the Grid widget can become even more powerful by combining it with DHTMLX Pivot. Using the live sample below, you can conveniently switch between Grid and Pivot modes, apply different aggregations, and analyze data dynamically. <\/p>\n<p><iframe data-src=\"https:\/\/snippet.dhtmlx.com\/0uo39y8c?mode=mobile\" frameborder=\"0\" width=\"100%\" height=\"560\"class=\"snippet-container js-iframe\"><\/iframe> <a href=\"https:\/\/snippet.dhtmlx.com\/0uo39y8c?tag=grid&#038;mode=wide rel=\"noopener\" target=\"_blank\">Check the sample ><\/a><\/p>\n<p>Fully overhauled last year, our <a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxPivot\/\" rel=\"noopener\" target=\"_blank\">JavaScript Pivot table<\/a> enhances data analysis capabilities by enabling dynamic data aggregations for comparing and analyzing complex data. This integration allows end-users to seamlessly switch between raw tabular data in the Grid view and the Pivot view, where the information can be easily organized into meaningful summaries required for effective decision-making.<\/p>\n<h5>Key Points to Consider When Integrating DHTMLX Grid with Pivot<\/h5>\n<p>Now, let us highlight the main aspects of integrating these DHTMLX widgets within a single pivot grid solution. Leaving aside the details on common things like including DHTMLX components in your project and initializing them, we\u2019ll focus on more challenging tasks. <\/p>\n<h6>Switching between Grid and Pivot Modes<\/h6>\n<p>Switching between these modes involves dynamically initializing and destroying instances of corresponding widgets while preserving configurations. The <strong>convertAndInit(state, save)<\/strong> function is responsible for this transition. <\/p>\n<p>When switching to Pivot mode (<strong>state === 1<\/strong>), the Grid is destroyed, and the Pivot table is initialized with stored or default settings.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">grid.<span class=\"me1\">destructor<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\npivotWidget <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> pivot.<span class=\"me1\">Pivot<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;#grid-pivot&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#123;<\/span> <br \/>\n&nbsp; &nbsp; fields<span class=\"sy0\">:<\/span> storedPivotFields <span class=\"sy0\">||<\/span> <span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; config<span class=\"sy0\">:<\/span> storedPivotConfig <span class=\"sy0\">||<\/span> <span class=\"br0\">&#123;<\/span><span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; data<span class=\"sy0\">:<\/span> dataset<span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>When switching back to Grid mode (<strong>state === 0<\/strong>), the Pivot is destroyed, and Grid reappears using previously saved settings:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">pivotWidget.<span class=\"me1\">destructor<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\ngrid <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> dhx.<span class=\"me1\">Grid<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;grid-pivot&quot;<\/span><span class=\"sy0\">,<\/span> storedGridConfig<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>This approach prevents memory leaks and avoids having multiple instances of the same component running at the same time. <\/p>\n<p>Additionally, the <strong>displayButtons<\/strong> function ensures that the appropriate UI buttons are shown for each mode:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">function<\/span> displayButtons<span class=\"br0\">&#40;<\/span>state<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; document.<span class=\"me1\">getElementById<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;edit-button&quot;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">style<\/span>.<span class=\"me1\">display<\/span> <span class=\"sy0\">=<\/span> state <span class=\"sy0\">===<\/span> <span class=\"nu0\">1<\/span> <span class=\"sy0\">?<\/span> <span class=\"st0\">&quot;none&quot;<\/span> <span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;block&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; document.<span class=\"me1\">getElementById<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;aux-buttons&quot;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">style<\/span>.<span class=\"me1\">display<\/span> <span class=\"sy0\">=<\/span> state <span class=\"sy0\">===<\/span> <span class=\"nu0\">1<\/span> <span class=\"sy0\">?<\/span> <span class=\"st0\">&quot;flex&quot;<\/span> <span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;none&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<h6>Handling Data Types Dynamically<\/h6>\n<p>DHTMLX Pivot requires properly defined data for fields. Without this, numeric columns might be treated as text, affecting sorting and aggregations. The use of the <strong>dataTypes<\/strong> object helps automatically detect column types based on the first row of Grid data:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> dataTypes <span class=\"sy0\">=<\/span> <span class=\"br0\">&#123;<\/span><span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> firstItem <span class=\"sy0\">=<\/span> grid.<span class=\"me1\">data<\/span>.<span class=\"me1\">getItem<\/span><span class=\"br0\">&#40;<\/span>grid.<span class=\"me1\">data<\/span>.<span class=\"me1\">getId<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">const<\/span> c <span class=\"kw1\">in<\/span> firstItem<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; dataTypes<span class=\"br0\">&#91;<\/span>c<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>firstItem<span class=\"br0\">&#91;<\/span>c<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">&quot;string&quot;<\/span> <span class=\"sy0\">?<\/span> <span class=\"st0\">&quot;text&quot;<\/span> <span class=\"sy0\">:<\/span> <span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>firstItem<span class=\"br0\">&#91;<\/span>c<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">&quot;number&quot;<\/span> <span class=\"sy0\">?<\/span> <span class=\"st0\">&quot;number&quot;<\/span> <span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;date&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>Then, the detected data types are used to generate Pivot fields dynamically:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">storedPivotFields <span class=\"sy0\">=<\/span> grid.<span class=\"me1\">config<\/span>.<span class=\"me1\">columns<\/span>.<span class=\"me1\">map<\/span><span class=\"br0\">&#40;<\/span>col <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span> <br \/>\n&nbsp; &nbsp; id<span class=\"sy0\">:<\/span> col.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span> <br \/>\n&nbsp; &nbsp; label<span class=\"sy0\">:<\/span> col.<span class=\"me1\">header<\/span><span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span>.<span class=\"me1\">text<\/span><span class=\"sy0\">,<\/span> <br \/>\n&nbsp; &nbsp; type<span class=\"sy0\">:<\/span> dataTypes<span class=\"br0\">&#91;<\/span>col.<span class=\"me1\">id<\/span><span class=\"br0\">&#93;<\/span> <br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>This ensures that the Pivot component correctly processes numeric and text-based data without manual configuration.<\/p>\n<h6>Avoiding an Empty Pivot Table Issue<\/h6>\n<p>A Pivot table with no defined rows, columns, or values appears blank. To avoid an unwanted empty UI and enable end-users to interact with Grid data in Pivot mode, you insert a temporary Grid inside the Pivot container using the <strong>replaceInnerGrid(pivotWidget)<\/strong> function:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">function<\/span> replaceInnerGrid<span class=\"br0\">&#40;<\/span>pivot<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> grid <span class=\"sy0\">=<\/span> pivot.<span class=\"me1\">container<\/span>.<span class=\"me1\">getElementsByClassName<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;wx-grid&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>grid.<span class=\"me1\">length<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; grid<span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span>.<span class=\"me1\">innerText<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; innerGrid <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> dhx.<span class=\"me1\">Grid<\/span><span class=\"br0\">&#40;<\/span>grid<span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> defaultGridConfig<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> <br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>The solution improves user experience by displaying meaningful data rather than a blank screen.<\/p>\n<h6>Preserving Settings and Maintaining Grid Consistency When Switching from Pivot<\/h6>\n<p>The rich functional capabilities of the Pivot component enable end-users to rearrange data and perform complex calculations to gain valuable insights. Therefore, it is important to preserve Pivot settings before switching to Grid mode:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> tableApi <span class=\"sy0\">=<\/span> pivotWidget.<span class=\"me1\">getTable<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> pivotConfig <span class=\"sy0\">=<\/span> pivotWidget.<span class=\"me1\">api<\/span>.<span class=\"me1\">getState<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">config<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The code does this by extracting Pivot\u2019s final state and applying it to the Grid. If no configuration changes were made in Pivot mode, you restore the original Grid configuration:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>pivotConfig.<span class=\"me1\">rows<\/span>.<span class=\"me1\">length<\/span> <span class=\"sy0\">&amp;&amp;<\/span> <span class=\"sy0\">!<\/span>pivotConfig.<span class=\"me1\">columns<\/span>.<span class=\"me1\">length<\/span> <span class=\"sy0\">&amp;&amp;<\/span> <span class=\"sy0\">!<\/span>pivotConfig.<span class=\"me1\">values<\/span>.<span class=\"me1\">length<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; storedGridConfig <span class=\"sy0\">=<\/span> defaultGridConfig<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; storedPivotConfig <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Since Pivot and Grid handle column widths differently, switching back to Grid may cause width inconsistencies. You have to ensure that each column has a predefined width:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">columns<span class=\"sy0\">:<\/span> columns.<span class=\"me1\">map<\/span><span class=\"br0\">&#40;<\/span>c <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span> <br \/>\n&nbsp; &nbsp; c.<span class=\"me1\">id<\/span> <span class=\"sy0\">=<\/span> c.<span class=\"me1\">id<\/span>.<span class=\"me1\">toString<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> <br \/>\n&nbsp; &nbsp; c.<span class=\"me1\">width<\/span> <span class=\"sy0\">=<\/span> c.<span class=\"me1\">width<\/span> <span class=\"sy0\">?<\/span> c.<span class=\"me1\">width<\/span> <span class=\"sy0\">:<\/span> <span class=\"nu0\">150<\/span><span class=\"sy0\">;<\/span> <br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> c<span class=\"sy0\">;<\/span> <br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><\/div><\/div>\n<p>Without this step, the Grid layout might break or appear misaligned after switching from Pivot mode.<\/p>\n<p>All in all, these measures help ensure a consistent and user-friendly experience when toggling between Grid and Pivot.<\/p>\n<p>Taking into consideration the points highlighted in this blog post, you can create a basic JavaScript pivot grid with DHTMLX Grid and Pivot components like in our sample. Using the well-documented APIs of these products, you can significantly extend their functionalities to meet various project requirements.<\/p>\n<h5>Wrapping Up<\/h5>\n<p>DHTMLX Grid and Pivot components can be a great addition to any data-intensive app with high demands on processing and analyzing large datasets. Just like all DHTMLX products, these components are highly compatible and can be easily integrated into one pivot grid solution in your web projects based on popular front-end frameworks. Download <a href=\"https:\/\/dhtmlx.com\/docs\/download\/\" rel=\"noopener\" target=\"_blank\">free 30-day trial versions<\/a> of Grid and Pivot components and test the capabilities of these products in your scenarios.<\/p>\n<h5>Related Materials<\/h5>\n<ul>\n<li><a href=\"https:\/\/dhtmlx.com\/blog\/tutorials\/\" rel=\"noopener\" target=\"_blank\">Other DHTMLX tutorials<\/a><\/li>\n<li><a href=\"https:\/\/docs.dhtmlx.com\/suite\/grid\/\" rel=\"noopener\" target=\"_blank\">DHTMLX Grid documentation<\/a><\/li>\n<li><a href=\"https:\/\/docs.dhtmlx.com\/pivot\/\" rel=\"noopener\" target=\"_blank\">DHTMLX Pivot documentation<\/a><\/li>\n<li><a href=\"https:\/\/snippet.dhtmlx.com\/9txizaow?tag=grid&#038;mode=wide\" rel=\"noopener\" target=\"_blank\">DHTMLX Grid samples<\/a><\/li>\n<li><a href=\"https:\/\/snippet.dhtmlx.com\/tn1yw14m?tag=pivot&#038;mode=wide\" rel=\"noopener\" target=\"_blank\">DHTMLX Pivot samples<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>The latest Capterra\u2019s Tech Trends Survey names data management as one of the main challenges finance businesses face when adopting new software solutions. Ready-made tools may not be flexible &#8230;<\/p>\n","protected":false},"author":101014,"featured_media":13611,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[71],"tags":[33,6,57],"class_list":["post-13608","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-all-posts","tag-dhtmlxgrid","tag-pivot"],"_links":{"self":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/13608","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/users\/101014"}],"replies":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/comments?post=13608"}],"version-history":[{"count":3,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/13608\/revisions"}],"predecessor-version":[{"id":13610,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/13608\/revisions\/13610"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media\/13611"}],"wp:attachment":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media?parent=13608"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/categories?post=13608"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/tags?post=13608"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}