{"id":6887,"date":"2025-12-17T10:58:02","date_gmt":"2025-12-17T01:58:02","guid":{"rendered":"https:\/\/dandelions.co.jp\/blog\/?p=6887"},"modified":"2026-06-04T15:41:12","modified_gmt":"2026-06-04T06:41:12","slug":"engineer-blog-automatic-column-generation-in-outsystems-data-grid","status":"publish","type":"post","link":"http:\/\/dandelions.co.jp\/blog\/blog\/2025\/12\/17\/engineer-blog-automatic-column-generation-in-outsystems-data-grid\/","title":{"rendered":"Engineer Blog \u2013 Automatic Column Generation in OutSystems Data Grid"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In this engineer blog, I\u2019ll introduce what I\u2019ve been learning recently. This time, I\u2019ll explain automatic column generation in OutSystems Data Grid.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>OutSystems Data Grid is a spreadsheet-like grid that can be displayed and interacted with within an OutSystems application. <\/li><li>This article assumes prior knowledge of OutSystems Data Grid.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Problem Statement<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For example, let&#8217;s say we have a grid like the one below.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"342\" src=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/1-1024x342.jpg\" alt=\"\" class=\"wp-image-6872\" srcset=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/1-1024x342.jpg 1024w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/1-300x100.jpg 300w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/1-768x257.jpg 768w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/1.jpg 1481w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The usual way to create it would be as follows.<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Set the data to be displayed into a Structure that matches the grid layout, convert it into a list, transform it into JSON using ArrangeData, and set the resulting JSON as the grid\u2019s data. <\/li><li>Place a column widget on the grid for each column to be displayed, and configure each header, column width, display conditions, and so on.<\/li><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">For a grid with six columns like the one above, it\u2019s not too difficult. However, if the number of columns to display is variable, creating it becomes more challenging.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You need to determine the maximum number of columns to display, then prepare the Structure from step 1 and the column widgets from step 2 to match that maximum number. Additionally, you must control the visibility of each column based on how many you actually want to display. As a result, all the columns up to the maximum exist, but only the desired number of columns are visible.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Especially for step 2, if the grid\u2019s configuration is even slightly complex\u2014such as having merged headers with dynamic labels\u2014the amount of work required increases significantly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the maximum number is around 100, it might take some time, but it\u2019s still manageable. However, I once faced a case where the maximum number reached nearly 1,500. At that time, I looked into whether it was possible to generate the grid columns using JavaScript.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As a result of the automatic generation, step 1 of the usual method still needs to be done as is, but step 2 becomes much simpler.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In a grid like the one below, the columns outlined in red are the target for automatic generation. (The left three columns are placed as usual. The auto-generated columns are on the right.)<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1475\" height=\"493\" src=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/2-1024x342.jpg\" alt=\"\" class=\"wp-image-6874\" srcset=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/2-1024x342.jpg 1024w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/2-300x100.jpg 300w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/2-768x257.jpg 768w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/2.jpg 1475w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The cells in the auto-generated columns will be set to read-only. The column order in the grid will be fixed and cannot be changed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The data to be displayed in the grid has already been retrieved and is set to the grid as described in step \u2460 above.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The header labels (such as &#8216;\u30b0\u30eb\u30fc\u30d71&#8217;, &#8216;\u30c7\u30fc\u30bfX&#8217;, &#8216;\u540d\u540d\u540d&#8217;, etc.) are dynamic and have already been retrieved in a format that can be passed into JavaScript. (In the sample JavaScript code, these input parts will be shown<strong> in bold<\/strong>.)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the implementation JavaScript, we use a variable called <code>dataGrid<\/code>. You can obtain <code>dataGrid<\/code> as shown below. (Let <code>gridId<\/code> be the ID of the configured grid.)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>var dataGrid = OutSystems.GridAPI.GridManager.GetGridById('gridId').provider;<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preliminary Research<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">From the link below, I found that it\u2019s possible to push columns into <code>dataGrid.columns<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.outsystems.com\/forums\/discussion\/80001\/outsystems-data-grid-is-is-possible-to-add-columns-dynamically-on-datagrid\/\">https:\/\/www.outsystems.com\/forums\/discussion\/80001\/outsystems-data-grid-is-is-possible-to-add-columns-dynamically-on-datagrid\/<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Upon further investigation of <code>dataGrid<\/code>, I found that in addition to <code>columns<\/code>, there is also <code>columnGroups<\/code>. I thought that by pushing to <code>columnGroups<\/code>, it might be possible to create grouped, merged header columns.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Implementation Flow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In the &#8216;On After Fetch&#8217; action after retrieving the data, implement it as follows.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">The first column of &#8216;\u30b0\u30eb\u30fc\u30d71&#8217;<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Create the element to push\nvar newColGroup = new wijmo.grid.ColumnGroup (\n\t{header: '<strong>\u30b0\u30eb\u30fc\u30d71<\/strong>', align: 'left', columns: &#91;\n\t\t{header: '<strong>\u30c7\u30fc\u30bfX<\/strong>', align: 'left', columns: &#91;\n\t\t\t{header: '<strong>\u540d<\/strong>', binding: '<strong>Data1<\/strong>', width: 100, align: 'left', isReadOnly: true}\n\t\t]}\n\t]}\n)<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Push newColGroup into columnGroups\ndataGrid.columnGroups.push(newColGroup);\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"341\" src=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/3-1024x341.jpg\" alt=\"\" class=\"wp-image-6873\" srcset=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/3-1024x341.jpg 1024w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/3-300x100.jpg 300w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/3-768x256.jpg 768w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/3.jpg 1487w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">The second column of &#8216;\u30b0\u30eb\u30fc\u30d71&#8217;<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Create the element to push\nvar newColGroup = new wijmo.grid.ColumnGroup (\n\t{header: '<strong>\u30c7\u30fc\u30bf1<\/strong>', align: 'left', columns: &#91;\n\t\t{header: '<strong>\u540d\u540d<\/strong>', binding: '<strong>Data2<\/strong>', width: 100, align: 'left', isReadOnly: true}\n\t]}\n)\n\n\/\/ Push newColGroup into the columns of the target columnGroup\n\/\/ columnGroups&#91;3] refers to the created \"Group 1\", which is at index 3 in columnGroups\ndataGrid.columnGroups&#91;3].columns.push(newColGroup);<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"342\" src=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/4-1024x342.jpg\" alt=\"\" class=\"wp-image-6877\" srcset=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/4-1024x342.jpg 1024w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/4-300x100.jpg 300w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/4-768x256.jpg 768w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/4.jpg 1481w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">the &#8216;\u30b0\u30eb\u30fc\u30d72&#8217; column<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Create the element to push\nvar newColGroup = new wijmo.grid.ColumnGroup (\n\t{header: '<strong>\u30b0\u30eb\u30fc\u30d72<\/strong>', align: 'left', columns: &#91;\n\t\t{header: '<strong>\u30c7\u30fc\u30bfV<\/strong>', align: 'left', columns: &#91;\n\t\t\t{header: '<strong>\u540d\u540d\u540d<\/strong>', binding: '<strong>Data3<\/strong>', width: 100, align: 'left', isReadOnly: true}\n\t\t]}\n\t]}\n)\n\n\/\/ Push newColGroup to columnGroups\ndataGrid.columnGroups.push(newColGroup);\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"341\" src=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/5-1024x341.jpg\" alt=\"\" class=\"wp-image-6878\" srcset=\"http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/5-1024x341.jpg 1024w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/5-300x100.jpg 300w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/5-768x256.jpg 768w, http:\/\/dandelions.co.jp\/blog\/wp\/wp-content\/uploads\/2025\/12\/5.jpg 1483w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">As shown above, grouped columns with merged headers are created one by one. <br>By adjusting the structure of <code>newColGroup<\/code> and the target of the push accordingly, it should be possible to create column groups with different structures.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">additional support<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When automatically generating columns, the following two points must be taken into consideration.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>The variable <code>dataGrid<\/code> represents the grid obtained as a JavaScript object. At the time the &#8216;On After Fetch&#8217; action is executed after data retrieval, the grid must already exist. One way to handle this is to set the data retrieval action\u2019s timing to &#8216;Only on Demand&#8217; and execute it in the &#8216;OnReady&#8217; action.<\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li>If the grid contains columns with editable cells, a post-edit check is performed on the entire row to determine whether any cells were edited. However, if this check tries to access the automatically generated columns, it will result in an error. (In the grid used as an example in this article, the &#8216;Settings&#8217; column is editable.)<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">To handle this, adjust the edit check in the grid\u2019s &#8216;OnInitialize&#8217; action using JavaScript as shown below.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Regular cell edit check\nvar originalCheck = OutSystems.GridAPI.GridManager.GetGridById('gridId').features.dirtyMark._isDirtyCell;\n\n\/\/ Adjust the check\n\/\/ Immediately treat cells in auto-generated columns as unedited\n\/\/ Since columns with index 3 and above are auto-generated, control with \"columnIndex &gt; 2\"\nvar newCheck = function (rowIndex, columnIndex) {\n\tif (columnIndex &gt; 2) {\n\t\treturn false;\n\t} else {\n\t\tvar checkResult = originalCheck.call(this, rowIndex, columnIndex);\n\t\treturn checkResult;\n\t}\n}\n\n\/\/ Apply the adjusted check to the grid\nOutSystems.GridAPI.GridManager.GetGridById('gridId').features.dirtyMark._isDirtyCell = newCheck;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Stay tuned for the next developer blog.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this engineer blog, I\u2019ll introduce what I\u2019ve been learning recently. This time, I\u2019ll explain automatic colu &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/dandelions.co.jp\/blog\/blog\/2025\/12\/17\/engineer-blog-automatic-column-generation-in-outsystems-data-grid\/\" class=\"more-link\"><span class=\"screen-reader-text\">&#8220;Engineer Blog \u2013 Automatic Column Generation in OutSystems Data Grid&#8221; \u306e<\/span>\u7d9a\u304d\u3092\u8aad\u3080<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true},"categories":[8],"tags":[9],"class_list":["post-6887","post","type-post","status-publish","format-standard","hentry","category-8","tag-9"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/posts\/6887","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/comments?post=6887"}],"version-history":[{"count":5,"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/posts\/6887\/revisions"}],"predecessor-version":[{"id":7361,"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/posts\/6887\/revisions\/7361"}],"wp:attachment":[{"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/media?parent=6887"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/categories?post=6887"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/dandelions.co.jp\/blog\/wp-json\/wp\/v2\/tags?post=6887"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}