{"id":6473,"date":"2019-08-12T18:11:23","date_gmt":"2019-08-12T15:11:23","guid":{"rendered":"https:\/\/dhtmlx.com\/blog\/?p=6473"},"modified":"2026-09-24T18:26:00","modified_gmt":"2026-09-24T15:26:00","slug":"filter-tasks-javascript-gantt-dhtmlx-video-tutorial","status":"publish","type":"post","link":"https:\/\/dhtmlx.com\/blog\/filter-tasks-javascript-gantt-dhtmlx-video-tutorial\/","title":{"rendered":"How to Filter Tasks in a JavaScript Gantt &#8211; DHTMLX Video Tutorial"},"content":{"rendered":"<p>Here we go with a new video tutorial about <a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxGantt\/\" rel=\"noopener\" target=\"_blank\">JavaScript Gantt<\/a> configuration. We&#8217;ll learn a common approach to implementing filtering and searching for tasks in the grid of dhtmlxGantt:<\/p>\n<p><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/LyJ3zKSrmH4\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><\/p>\n<p>Let&#8217;s take a look at the example of a basic text filter. A user types something &#8211; and we display only the tasks that match the selection:<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2019\/08\/filtering-tasks-in-Gantt.gif\" alt=\"Filtering tasks in DHTMLX Gantt\" width=\"900\" height=\"503\" class=\"aligncenter size-full wp-image-6474\" \/> <\/p>\n<p>Such filters consist of two parts: <\/p>\n<ul>\n<li>the UI control that allows a user to select the filter criteria<\/li>\n<li>the code that will manage the visibility of rows in Gantt<\/li>\n<\/ul>\n<p>We already know how to <a href=\"https:\/\/dhtmlx.com\/blog\/add-custom-elements-grid-javascript-gantt-dhtmlx-gantt-video-tutorial\/\" rel=\"noopener\" target=\"_blank\">add UI controls<\/a>, and we know that we&#8217;ll update filters on the user input.<\/p>\n<p><strong>Now, how do we filter tasks in Gantt?<\/strong><\/p>\n<p>There is no <strong>filter tasks<\/strong> method in dhtmlxGantt. Instead, there is an API event called <strong>onBeforeTaskDisplay<\/strong>:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">attachEvent<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;onBeforeTaskDisplay&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>id<span class=\"sy0\">,<\/span> task<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">priority<\/span> <span class=\"sy0\">==<\/span> <span class=\"st0\">&quot;high&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p><a href=\"https:\/\/docs.dhtmlx.com\/gantt\/api__gantt_onbeforetaskdisplay_event.html\" rel=\"noopener\" target=\"_blank\">Check the API in the documentation ><\/a><\/p>\n<p>This event is called for each task during a complete repaint of Gantt data. We can add a handler for this event to our code, and skip rendering of tasks that don&#8217;t match the filter value.<\/p>\n<p>To begin with, we add a text field to the grid header:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> textFilter <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;&lt;input data-text-filter type='text' oninput='gantt.$doFilter(this.value)'&gt;&quot;<\/span><br \/>\n&nbsp; gantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">columns<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span>name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;text&quot;<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> textFilter<span class=\"sy0\">,<\/span> tree<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span> <span class=\"st0\">'*'<\/span><span class=\"sy0\">,<\/span> resize<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span>name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;start_date&quot;<\/span><span class=\"sy0\">,<\/span> align<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;center&quot;<\/span><span class=\"sy0\">,<\/span> resize<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span>name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;duration&quot;<\/span><span class=\"sy0\">,<\/span> align<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;center&quot;<\/span><span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Inside the <strong>oninput<\/strong> handler we&#8217;ll store the current value of the filter and trigger the repaint of the Gantt using the <strong>gantt render<\/strong> method:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> filterValue <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"kw1\">var<\/span> delay<span class=\"sy0\">;<\/span><br \/>\n&nbsp; gantt.$doFilter <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>value<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; filterValue <span class=\"sy0\">=<\/span> value<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; clearTimeout<span class=\"br0\">&#40;<\/span>delay<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; delay <span class=\"sy0\">=<\/span> setTimeout<span class=\"br0\">&#40;<\/span><span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">render<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; gantt.$root.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;[data-text-filter]&quot;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">focus<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">200<\/span><span class=\"br0\">&#41;<\/span> <br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>The <strong>gantt render<\/strong> method causes a complete repaint of the Gantt chart, during which the <strong>onBeforeTaskDisplay<\/strong> event will be called for each task. Then we check whether the task matches the filter criteria, and decide whether to show it or not.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">&nbsp; gantt.<span class=\"me1\">attachEvent<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;onBeforeTaskDisplay&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>id<span class=\"sy0\">,<\/span> task<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp;<span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>filterValue<span class=\"br0\">&#41;<\/span> <span class=\"kw1\">return<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> normalizedText <span class=\"sy0\">=<\/span> task.<span class=\"me1\">text<\/span>.<span class=\"me1\">toLowerCase<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> normalizedValue <span class=\"sy0\">=<\/span> filterValue.<span class=\"me1\">toLowerCase<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> normalizedText.<span class=\"me1\">indexOf<\/span><span class=\"br0\">&#40;<\/span>normalizedValue<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&gt;<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">1<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>At this stage, you may want to have a multiline header in your grid, for example, in order to show a column name above your filter.<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2019\/08\/bandicam-2019-08-12-18-27-35-761.png\" alt=\"Multiline headers in DHTMLX Gantt\" width=\"852\" height=\"508\" class=\"aligncenter size-full wp-image-6478\" srcset=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2019\/08\/bandicam-2019-08-12-18-27-35-761.png 852w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2019\/08\/bandicam-2019-08-12-18-27-35-761-300x179.png 300w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2019\/08\/bandicam-2019-08-12-18-27-35-761-768x458.png 768w\" sizes=\"auto, (max-width: 852px) 100vw, 852px\" \/><br \/>\nThe bad news is that Gantt doesn&#8217;t have a built-in config for multiline headers. But we can bypass it in the same way as we added the filter in the first place using custom HTML content. We can display multiple rows inside the column label:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> scaleHeight <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">scale_height<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"kw1\">var<\/span> textFilter <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">&quot;&lt;div class='gantt-sub-header' style='line-height:&quot;<\/span><span class=\"sy0\">+<\/span>scaleHeight<span class=\"sy0\">\/<\/span><span class=\"nu0\">2<\/span><span class=\"sy0\">+<\/span><span class=\"st0\">&quot;px'&gt;&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">&quot;&lt;div&gt;Name&lt;\/div&gt;&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">&quot;&lt;div&gt;Search: &lt;input data-text-filter type='text' oninput='gantt.$doFilter(this.value)'&gt;&lt;\/div&gt;&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">&quot;&lt;\/div&gt;&quot;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#93;<\/span>.<span class=\"me1\">join<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Implementing <strong>col span <\/strong>or <strong>row span<\/strong> won&#8217;t be so trivial, so hopefully, you won&#8217;t need it.<\/p>\n<p>We invite you to try filtering tasks yourself building your own JavaScript Gantt with the help of our<strong> <a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxGantt\/download.shtml\" rel=\"noopener\" target=\"_blank\">free evaluation version<\/a><\/strong>. Follow the steps described in this article and our video tutorial or consult our technical support team if any questions arise.<\/p>\n<p>Enjoy your Gantt and stay tuned for future tutorials!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here we go with a new video tutorial about JavaScript Gantt configuration. We&#8217;ll learn a common approach to implementing filtering and searching for tasks in the grid of dhtmlxGantt: &#8230;<\/p>\n","protected":false},"author":101012,"featured_media":6150,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[71,1],"tags":[33,20,14],"class_list":["post-6473","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","category-uncategorized","tag-all-posts","tag-gantt","tag-tips"],"_links":{"self":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/6473","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\/101012"}],"replies":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/comments?post=6473"}],"version-history":[{"count":1,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/6473\/revisions"}],"predecessor-version":[{"id":11337,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/6473\/revisions\/11337"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media\/6150"}],"wp:attachment":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media?parent=6473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/categories?post=6473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/tags?post=6473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}