Custom searchbar


#1

Hi,

I’m trying to implement custom searchbar in my gantt chart.

So far it is rendered properly - however the only way that I could find is by using ‘onGanttRender’ event.
It is a Vue component.

const searchInputInstance = new ScheduleSearchInput({
  propsData: {
    value: this.searchValue,
    placeholder: this.$t('schedule.searchInputPlaceholder'),
  },
})
searchInputInstance.$on('search', async (event: any) => {
  await this.fetchPeople(event.target.value)
})
searchInputInstance.$mount('#search-input')

and fetching function:

async fetchPeople(value: string) {
  const params = new URLSearchParams()
  params.append('search', value)
  await this.$api.allocations.index(params).then(async (data) => {
    this.setAllAllocations(mapApi(data.results))
    await gantt.parse({ data: this.mappedAllocationsToDhtmlx })
  })

}

And unfortunately after gantt.parse is triggered the whole searchbar component is re-rendered, and it feels clunky.

My searchbox is defined is columns template like so:

columns: [
  {
    name: 'text',
    label: '<div id="search-input"></div>', ...

Is there any other way to implement that?

Let me know if my question is clear enough.

Thanks,
Bartosz


#2

Hi,
At the moment, after rendering, only cells of the grid can be changed using the onrender attribute.
For the column header, you need to add a Vue component to the onGanttRender event as well as to the onDataRender event:

gantt.attachEvent("onDataRender", () => {
    searchInputInstance.$mount('#search-input');
});
gantt.attachEvent("onGanttRender", () => {
    searchInputInstance.$mount('#search-input');
});

This is because there are scenarios in Gantt in which the header of the grid is redrawn and onDataRender fires without onGanttRender.
For example here is a snippet with only onGanttRender event: https://snippet.dhtmlx.com/eqtev4ej. If you remove the task, the searchbox stops working.

and here is an example when there are events onDataRender and onGanttRender then the searchbox works properly: https://snippet.dhtmlx.com/nsuxnf4t.


#3

Hi Makism,

Thank you for the response. However what you have done here is basically a filtering, rarther than connection with the endpoint - like I did.

So let me explain again:

I need this searchbox with backend contract, so whenever i type something, there is a call to backend which, in response, gives me new data. This new data I have to parse through gantt.
And there is a problem, beacuse whenever I type something, searchbox is rerendered. (beacuse of gantt.parse I presume)


#4

Here is my current code:

private searchBox = document.getElementById('search')

// implements onGanttRender gantt event
private onGanttRender() {
  this.searchBox = document.getElementById('search')
}

// implements onDataRender gantt event
private onDataRender() {
  this.searchBox = document.getElementById('search')
  this.searchBox.addEventListener('input', async () => {
    await this.fetchPeople(this.searchBox!.value)
  })
}

// this.$api.index is a call to backend.
async fetchPeople(value: string) {
  const params = new URLSearchParams()
  params.append('search', value)
  await this.$api.allocations.index(params).then((data) => {
    this.setAllAllocations(mapApi(data.results))
    gantt.batchUpdate(() => {
      gantt.parse({ data: this.mappedAllocationsToDhtmlx })
    })
  })
}

and here is a video to show you what happens:


#5

Hi,
Yes, you are right, Gantt is redrawn after gantt.parse and also after gantt.render function calls.

There is no way to prevent the repaint of the header area. The usual approach is to preserve the value of the search box and apply it back to the control after the repaint.

You can check this video tutorial where we implement something similar:

In your case the code could be the following:

let filterData;
let searchBox = document.getElementById("search");
function changeDetector() {
    filterData = searchBox.value;
    gantt.refreshData();
}

gantt.attachEvent("onGanttRender", () => {
    searchBox = document.getElementById("search");
    searchBox.focus();
    if(prevSearchBoxValue) {
        searchBox.value = prevSearchBoxValue;
    }
});

Please see the snippet: https://snippet.dhtmlx.com/2yely73l. In the example, I have added the “Parse” button. After clicking the button, gantt.parse will occur and Gantt will be redrawn, i.e. what happens in your case.


#6

@Maksim_Lakatkou

I’ve implemented the filtering you’ve suggested from your first response.

However I’ve found that refreshingData is not the best solution, beacuse the height of chart remains the same.

I’ve recorded it, and also tested on the snippet. The problem is present.

Could you help me with that as well?


#7

In this case, gantt.render() will redraw the whole Gantt chart and update its height. Please use this method instead of gantt.refreshData():

function changeDetector() {
    filterData = searchBox.value;
    gantt.render();
}

please see the snippet: https://snippet.dhtmlx.com/0augfjjw.