Support Forum
Hi,
We use the filterBar with a customized "store filtering" since the standard filter doesn't work with our data. When we enter text into the field the filtering happens, but right after that the field is emptied but the filtering remains. We don't have any code that does the clearing of the value.
The question is: how do we prevent that from happening?
Thanks!
We use the filterBar with a customized "store filtering" since the standard filter doesn't work with our data. When we enter text into the field the filtering happens, but right after that the field is emptied but the filtering remains. We don't have any code that does the clearing of the value.
The question is: how do we prevent that from happening?
Thanks!
Please provide a small test case based on this demo: https://www.bryntum.com/examples/scheduler/filtering/
Pavlo Miklashevych
Sr. Frontend Developer
I use https://www.bryntum.com/docs/scheduler/ ... ieldChange for the input fields in the filterBar. When I do that (and the script detects that it is a `userAction`) I loop trough the scheduler.store.filter and return true/false if there is a match or not. When that is done the field value is emptied (but the filter remains).
Am I using the wrong function to detect changes to the input field or is there some way of preventing the field from being reset?
Am I using the wrong function to detect changes to the input field or is there some way of preventing the field from being reset?
Now I've tried it in the filtering example and the error occurs there as well. Here is the code:
It has nothing to do with our code. Uncomment the "return true;" in the "scheduler.store.filter" function to verify that.
import { DateHelper,WidgetHelper,Scheduler,DomClassList } from '../../build/scheduler.module.js';
import shared from '../_shared/shared.module.js';
let scheduler;
var _filterSpecificColumn = function(filterValue, column, field) {
var i, dataText, dataColumn;
scheduler.store.filter(function(storeData) {
// return true;
dataColumn = storeData[column];
if (Array.isArray(dataColumn)) {
for (i = 0; i < dataColumn.length; i++) {
dataText = dataColumn[i].data.text || '';
if (_compareFilterString(dataText, filterValue)) {
return true;
}
}
} else if (typeof dataColumn === 'string') {
return _compareFilterString(dataColumn, filterValue);
} else {
dataText = dataColumn.text || '';
return _compareFilterString(dataText, filterValue);
}
return false;
});
};
var _compareFilterString = function(dataText, filterValue) {
dataText = dataText.toLowerCase();
filterValue = filterValue.toLowerCase();
if (dataText.indexOf(filterValue) !== -1) {
return true;
}
return false;
};
//region Widgets
WidgetHelper.append([{
type : 'textfield',
id : 'filterByName',
cls : 'b-bright',
placeholder : 'Find tasks by name',
clearable : true,
keyStrokeChangeDelay : 100,
onChange : ({ value }) => {
value = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
scheduler.eventStore.filter(event => event.name.match(new RegExp(value, 'i')));
}
}, {
type : 'textfield',
id : 'highlight',
cls : 'b-bright',
placeholder : 'Highlight tasks',
clearable : true,
keyStrokeChangeDelay : 100,
onChange : ({ value }) => {
scheduler.eventStore.forEach(task => {
const taskClassList = new DomClassList(task.cls),
matched = taskClassList['b-match'];
if (task.name.toLowerCase().indexOf(value) >= 0) {
if (!matched) {
taskClassList.add('b-match');
}
}
else if (matched) {
taskClassList.remove('b-match');
}
task.cls = taskClassList.value;
});
scheduler.element.classList[value.length > 0 ? 'add' : 'remove']('b-highlighting');
}
}], { insertFirst : document.getElementById('tools') || document.body });
//endregion
scheduler = new Scheduler({
appendTo : 'container',
minHeight : '20em',
eventStyle : 'colored',
eventColor : null,
features : {
filterBar: {
onColumnFilterFieldChange: function(eventData) {
if (eventData.userAction) {
var value = eventData.value,
column = eventData.source.name,
field = eventData.event.target;
_filterSpecificColumn(value, column, field);
}
},
},
stripe : true,
timeRanges : true,
eventEdit : {
extraWidgets : [
{ type : 'text', name : 'location', label : 'Location', dataset : { eventType : 'Meeting' } }
]
}
},
columns : [{
type : 'resourceInfo',
imagePath : '../_shared/images/users/',
text : 'Staff',
width : 170
}, {
text : 'Role',
field : 'role',
width : 140,
editor : {
type : 'combo',
items : ['Sales', 'Developer', 'Marketing', 'Product manager'],
editable : false,
pickerWidth : 140
}
}],
crudManager : {
autoLoad : true,
transport : {
load : {
url : 'data/data.json'
}
}
},
barMargin : 5,
rowHeight : 55,
startDate : new Date(2017, 1, 7, 8),
endDate : new Date(2017, 1, 7, 18),
viewPreset : 'hourAndDay',
// Specialized body template with header and footer
eventBodyTemplate : data => `
<div class="b-sch-event-header">${data.headerText}</div>
<div class="b-sch-event-footer">${data.footerText}</div>
`,
eventRenderer({ eventRecord, resourceRecord, tplData }) {
tplData.style = 'background-color:' + resourceRecord.color;
return {
headerText : DateHelper.format(eventRecord.startDate, this.displayDateFormat),
footerText : eventRecord.name || ''
};
}
});
Hello,
Thanks for applying the test case. It helps a lot to understand what is going on. I've checked the test case and here is what I'd like to say:
First of all onColumnFilterFieldChange is a private function and it's not supposed to be overridden.
If you still wish to override it, please follow the override concept.
If you look at the original onColumnFilterFieldChange function code you'll see that we suspend store tracking while we are filtering.
So adding suspendStoreTracking/resumeStoreTracking to your custom function will help to prevent the input from clearing.
Hope this will help you.
Best,
Pavel
Thanks for applying the test case. It helps a lot to understand what is going on. I've checked the test case and here is what I'd like to say:
First of all onColumnFilterFieldChange is a private function and it's not supposed to be overridden.
If you still wish to override it, please follow the override concept.
If you look at the original onColumnFilterFieldChange function code you'll see that we suspend store tracking while we are filtering.
onColumnFilterFieldChange({ source : field, value }) {
const me = this,
grid = me.grid;
// we don't want to hear back store "filter" event
// so we suspend store tracking
me.suspendStoreTracking();
if (value == null || value === '') {
// remove filter if setting to empty
grid.store.removeFieldFilter(field.name);
}
else {
grid.store.filter(Object.assign({
property : field.name
}, me.parseFilterValue(value)));
}
me.resumeStoreTracking();
}
class FilterBarOverride {
static get target() {
return {
class : FilterBar,
product : 'scheduler',
minVersion : '1.2.2',
maxVersion : '1.2.2'
};
}
onColumnFilterFieldChange(eventData) {
this.suspendStoreTracking();
// In case you need to call parent
// this._overridden.onColumnFilterFieldChange.call(this, eventData);
if (eventData.userAction) {
var value = eventData.value,
column = eventData.source.name,
field = eventData.event.target;
_filterSpecificColumn(value, column, field);
}
this.resumeStoreTracking();
}
}
Override.apply(FilterBarOverride);
Best,
Pavel
Pavlo Miklashevych
Sr. Frontend Developer
Also please keep in mind that every store supports filterBy function where you can describe your complex filtering.
Pavlo Miklashevych
Sr. Frontend Developer
Please see this event: https://www.bryntum.com/docs/scheduler/ ... ent-filter
"this" in FilterBarOverride is FilterBar feature. The scope is bound in constructor of the FilterBar.
"this" in FilterBarOverride is FilterBar feature. The scope is bound in constructor of the FilterBar.
onColumnFilterFieldChange(eventData) {
console.log(this.$name); // FilterBar
Pavlo Miklashevych
Sr. Frontend Developer