Premium support for our pure JavaScript UI components


Post by seany84 »

We have use the example from: https://www.bryntum.com/products/gantt/examples/fieldfilters/ to implement the gridfieldfilterpickergroup on our tradeDiscipline column in the Gantt's grid.

We are using v5.2.9 of the Bryntum Gantt package.

In our class that extends TaskModel, we have applied our relations:

    static relations = {
        tradeDiscipline : {
            foreignKey   : 'tradeDisciplineId',
            foreignStore : tradeDisciplineStore
        }
    }

We have implemented our Grid feature:

    get filterFeature() {
        const filterPickerFields = {
            tradeDisciplineId: {
                relatedDisplayField: 'description'
            }
        };
        return {
            isMulti: {
                allowedFieldNames: ['activityName', 'startDate', 'endDate', 'duration', 'responsible', 'tradeDisciplineId', 'progress'],
                fields: filterPickerFields
            }
        }
    }

Our columns are defined as follows:

    get columns() {
        const data = this.data;
        return [
            { id: "id", field : "id", text : 'ID', hidden: true },
            { id: "activityName", type: "name", field: 'activityName', text: 'Activity Name' },
            { id: "issueConstraints", type: "issue-column", width: "50px", text: "Issues/Constraints" },
            { id: "comment", type: "comment-column", width: "50px", text: "Comment"},
            { id: "startDate", type: "startdate", field : 'startDate', text : 'Start Date', format: bryntumDateFormat },
            { id: "endDate", type: "enddate", field : 'endDate', text : 'End Date', format: bryntumDateFormat },
            { id: "duration", type: "duration", field : "duration", text : "Duration", width: "50px"},
            {
                id: "discipline",
                field : 'tradeDisciplineId',
                type: 'number',
                text : 'Discipline',
                renderer : ({ record }) => record.tradeDiscipline?.description
            },
            {
                id: 'responsible',
                field: 'responsible',
                text: 'Responsible'
            },
            { id: "progress", type: "percentdone", field:'progress', showCircle: true, width: 70, text: "Progress" }
        ];
    }

Our new store:

import {Model, Store} from "@bryntum/gantt";

class TradeDiscipline extends Model {
    static $name = 'TradeDiscipline';

static fields = [
    'id', 'description'
];
}

// Define a separate store holding additional data that we can attach to the main TaskModel, to
// demonstrate setting up relations between models and filtering on them
const tradeDisciplineStore = new Store({
    modelClass : TradeDiscipline,
    data:
        window.clientModel.tradeDisciplines.map(x => {
            return {id: x.tradeDisciplineId, description: x.description}
        })
});

export default tradeDisciplineStore;

From our project-component.vue which wraps the Bryntum Project:

computed: {
        projectConfig() {
            return {
                ...this.$attrs
            };
        },
        taskStore() {
            const vm = this;
            return {
                modelClass: ActivityModel,
                tradeDisciplineStore: tradeDisciplineStore,
                listeners: {
                  .....
            };
        },

Steps to reproduce:

  1. When clicking the filter button on the tradeDiscipline column
  2. Selecting "is one of"
  3. Selecting a value from the dropdown

We get the following error in the console:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'sort')
    at eval (gantt.module.js?3374:99129:1)
    at Array.map (<anonymous>)
    at eval (gantt.module.js?3374:99107:1)
    at Array.forEach (<anonymous>)
    at Filter.refreshHeaders (gantt.module.js?3374:99092:1)
    at Filter.onStoreFilter (gantt.module.js?3374:99875:1)
    at TaskStore.trigger (gantt.module.js?3374:6056:1)
    at TaskStore.trigger (gantt.module.js?3374:127400:1)
    at TaskStore.triggerFilterEvent (gantt.module.js?3374:29113:1)
    at TaskStore.afterPerformFilter (gantt.module.js?3374:29105:1)

gantt.module.js?3374:99129:1

if (isColumnFiltered) {
              const bullet = '&#x2022 ';
              filterText = `${me.L('L{filter}')}: ` + (columnFilters.length > 1 ? '<br/><br/>' : '') + columnFilters.map(columnFilter => {
                var _columnFilter$value, _me$store, _me$store$modelRelati;
                let value = (_columnFilter$value = columnFilter.value) !== null && _columnFilter$value !== void 0 ? _columnFilter$value : '';
                const isArray = Array.isArray(value),
                  relation = (_me$store = me.store) === null || _me$store === void 0 ? void 0 : (_me$store$modelRelati = _me$store.modelRelations) === null || _me$store$modelRelati === void 0 ? void 0 : _me$store$modelRelati.find(({
                    foreignKey
                  }) => foreignKey === columnFilter.property);
                if (columnFilter.displayValue) {
                  value = columnFilter.displayValue;
                } else {
                  if (me.isMulti && relation) {
                    var _me$isMulti$fields;
                    // Look up remote display value per filterable-field config (FieldFilterPicker.js#FieldOption)
                    const {
                      relatedDisplayField
                    } = (_me$isMulti$fields = me.isMulti.fields) === null || _me$isMulti$fields === void 0 ? void 0 : _me$isMulti$fields[columnFilter.property];
                    if (relatedDisplayField) {
                      const getDisplayValue = foreignId => {
                        var _relation$foreignStor;
                        return (_relation$foreignStor = relation.foreignStore.getById(foreignId)) === null || _relation$foreignStor === void 0 ? void 0 : _relation$foreignStor[relatedDisplayField];
                      };
                      if (isArray) {
                          //relatedDisplayField is "description"
[EXCEPTION LINE]                          value = value[relatedDisplayField].sort((a, b) => (a !== null && a !== void 0 ? a : '').localeCompare(b !== null && b !== void 0 ? b : ''));
                      } else {
                        value = getDisplayValue(value);
                      }
                    }
                  } else if (column.formatValue && value) {
                    value = isArray ? value.map(val => column.formatValue(val)) : column.formatValue(value);
                  }
                  if (isArray) {
                    value = `[ ${value.join(', ')} ]`;
                  }
                }
                return (columnFilters.length > 1 ? bullet : '') + (typeof columnFilter === 'string' ? columnFilter : `${columnFilter.operator} ${value}`);
              }).join('<br/><br/>');
            }

However the filter dialog does appear and items can be selected to filter by, but the filter is not actually applied to the data in the grid:

(There is data in the Trade Discipline columns, behind the filter pop-up)

Untitled.png
Untitled.png (77.16 KiB) Viewed 433 times

Post by emil »

Hi seany84,

I believe this is an issue that is being fixed right now. I'll update this ticket as soon as I have an expected release date for the fix.

Thanks,

Emil


Post by seany84 »

emil wrote: Sun Mar 26, 2023 6:29 am

Hi seany84,

I believe this is an issue that is being fixed right now. I'll update this ticket as soon as I have an expected release date for the fix.

Thanks,

Emil

Thank you Emil, would you have an estimated release date/version that this fix is being tracked against?

There is a second issue which I believe could be related to this one. The 'Duration' column filter is just showing "No results". This column type is duration and there is no custom store etc.

Can you tell me if this is related or if I should create a new thread for this?

Untitled2.png
Untitled2.png (10.22 KiB) Viewed 377 times

Post by emil »

I've inquired about the target version and will report back here once I know more.

Regarding the duration issue, is the underlying field on your custom TaskModel actually "duration" (as specified in your column definition)? Normally a DurationColumn would use the "fullDuration" field and I think the filter feature expects a Duration-type field like fullDuration. As a test, if you remove the "field: 'duration'" from your Gantt's columns definition, does it change anything?


Post by emil »

Update: the fix is currently targeting release with 5.3.2. I don't have a date for that yet. I expect the fix to appear in nightlies in the next day or two.


Post by seany84 »

emil wrote: Tue Mar 28, 2023 4:14 am

I've inquired about the target version and will report back here once I know more.

Regarding the duration issue, is the underlying field on your custom TaskModel actually "duration" (as specified in your column definition)? Normally a DurationColumn would use the "fullDuration" field and I think the filter feature expects a Duration-type field like fullDuration. As a test, if you remove the "field: 'duration'" from your Gantt's columns definition, does it change anything?

This worked perfectly for 'duration', as you mentioned, once I removed the 'field' property from the Gantt column and used the 'fullDuration' type it worked 100%.

We have a third and final issue with custom column filtering. Should I post the details here on this thread or raise a new thread?


Post by emil »

A new thread is probably best, but either way is OK. Thanks.


Post by seany84 »

Thanks Emil, I have posted the custom column multi filtering issue here: viewtopic.php?t=24417


Post by seany84 »

emil wrote: Tue Mar 28, 2023 8:01 pm

Update: the fix is currently targeting release with 5.3.2. I don't have a date for that yet. I expect the fix to appear in nightlies in the next day or two.

As a workaround for us here, is it possible to have the gridfieldfilterpickergroup applied to an individual column and have the other columns use the default?


Post by emil »

seany84 wrote: Thu Mar 30, 2023 12:22 pm

As a workaround for us here, is it possible to have the gridfieldfilterpickergroup applied to an individual column and have the other columns use the default?

Hi seany84,

There's no way to achieve that right now. We're making some changes to this feature currently and I'll see if per-column UI selection is something we can/want to support there.

Thanks,

Emil


Post Reply