Our blazing fast Grid component built with pure JavaScript


Post by jintech »

Here are 3 UI-related changes. Could you please explain whether they are possible in Bryntum or not, if possible can you please share the bryntum configurations or CSS.

1 - visible the filter and sort icon (event without applied or hover sort and filter) with some specific color.

In Bryntum Grid, if we don’t apply a filter or sorting, the filter and sort icons are not shown in the header.

We display the filter and sort icons when they are applied or on hover. Correct.

Is there a way to display the filter and sort icons for all columns, even without hover or active filters, with a specific color?(Without hover I can see the order option and filter option)

1.png
1.png (89.89 KiB) Viewed 395 times

2 - Is there a way to add a checkbox on the right side of the list created using listItemTpl, similar to the jobs kanban area. Can we enable and disable the filter functionality in the same way as the date filter?

3.png
3.png (48.98 KiB) Viewed 395 times

3 - When we open any filter picker, the filter icon in the selected header becomes hidden. We want it to remain visible when typing in the filter picker.

4.png
4.png (13.16 KiB) Viewed 395 times

When we uncheck the filter status using the checkbox, the filter icon for that column should remain visible and change to a specific color, like red.


Post by tasnim »

Hi,

You can achieve the 1 & 3 by adding this CSS

		.b-grid-header .b-filter-icon {
			display: unset;
		}

	.b-grid-header .b-filter-icon::after {
		color:red;
	}

	.b-grid-header .b-sort-icon::before {
		font-family: "Font Awesome 6 Free", FontAwesome6Free;
		font-weight: 900;
		font-size: 0.8em;
		/* color: #e5e7e9; */
		color : red;
		transition: transform 0.3s, color 0.2s;
		transform: none;
		background: inherit;
		content: "\f15e";
	}
msedge_Gh7t0hfD8h.png
msedge_Gh7t0hfD8h.png (44.48 KiB) Viewed 358 times

And Regarding the questions number 2, do you want to disable the whole date input or just the date picker?


Post by jintech »

@tasnim thanks for the response.

Regarding point #3, I am providing further clarification. Please review and share your thoughts on whether it is possible to achieve all the points in Bryntum.

  • Initial state - Default - The filter and sort icons are with red color by default.
  • On hover, the icon color changes to black.
  • When a filter is applied or an item is sorted, the icon turns blue.

For filter states, can we use a class instead of Unicode for the filter icon?

  • When no filter is applied, then on Hover the filter icon should turn black, using the regular filter icon class (class="fa-thin fa-filter").
  • When a filter is applied, the filter icon should be blue, using the solid filter icon class (class="fa-solid fa-filter").
  • After a filter is applied, on hover, the icon should still turn black, but it will remain the solid filter icon (class="fa-solid fa-filter").

The filter icon (blue color) should appear when I start typing, indicating that the filter is becoming active. For example, when I click on the filter icon and start typing in the column name, the filter icon in header should become active (blue). Means when the filter modal is opened, the filter icon should be visible as active.

When the Filter is Applied:

  1. The user clicks the header filter icon.
  2. The filter icon becomes active (blue).
  3. The user selects a filter type (e.g., a dropdown selector).
  4. The user clicks outside the filter area or header, and the filter is applied, keeping the icon active.

When the Filter is Not Applied:

  1. The user clicks the header filter icon.
  2. The filter icon becomes active (blue).
  3. The user does not select a filter type.
  4. The user clicks outside the filter area or header, and the filter remains inactive.

Please refer to the red circle in the image below. When I type "Joh" in the name column, the filter icon becomes active, and its color changes to blue.
And when I unchecked the button (inactive the filter) then filter color is also changed to yellow (to indicate that the filter is disabled).

4.png
4.png (12.85 KiB) Viewed 337 times

For point #2, I would like a checkmark button in the city filter popup that functions the same way as the one in the Name column. And I don't want filter like Name column have, I want the list in city filter.

5.png
5.png (34.75 KiB) Viewed 337 times

Below is the code for point#2 and point#3:

https://bryntum.com/products/grid/examples/columntypes/

Css code:
.b-grid-header .b-filter-icon {
display: unset;
}
.b-grid-header .b-filter-icon::after {
color:red;
}
.b-grid-header .b-sort-icon::before {
font-family: "Font Awesome 6 Free", FontAwesome6Free;
font-weight: 900;
font-size: 0.8em;
color : red;
transition: transform 0.3s, color 0.2s;
transform: none;
background: inherit;
content: "\f15e";
}
.b-grid-header.b-filter .b-filter-icon:after {
color: blue!important;
}
.b-gridbase.b-sort .b-grid-header.b-sort .b-grid-header-text .b-sort-icon:before {
color: blue!important;
content: "\f15e"; /* Modified the sort icon, AZ with arrow */
}
.b-grid-header .b-filter-icon:hover:after {
color: black !important;
}
.b-gridbase.b-sort .b-grid-header.b-sort .b-grid-header-text:hover, .b-grid-header.b-filter .b-grid-header-text:hover {
color: black !important;
}
.b-gridbase.b-sort:not(.b-column-resizing,.b-row-reordering,.b-dragging-header) .b-grid-header-container .b-grid-header.b-sortable.b-depth-0:hover:not(.b-sort):not(.b-group) .b-grid-header-text .b-sort-icon:before, .b-gridbase.b-sort:not(.b-column-resizing,.b-row-reordering,.b-dragging-header) .b-grid-header-container .b-grid-header.b-sortable.b-depth-0:focus:not(.b-sort):not(.b-group) .b-grid-header-text .b-sort-icon:before{
color: black !important;
}
/-----------END-----------/

import { Toast, Grid, DataGenerator, Column, ColumnStore, StringHelper, Model } from '../../build/grid.module.js?479836';
import shared from '../_shared/shared.module.js?479836';

class CityModel extends Model {
    static idField = 'name';
    static fields = [
        'name',
        'region'
    ];
}

const cityCombo = {
    type         : 'combo',
    valueField   : 'name',
    displayField : 'name',
    cls          : 'city-combo',
    chipView     : {
        iconTpl : () => '<i class="b-icon b-fa-city"></i>'
    },
    listItemTpl : ({ name }) => `<i class="b-icon b-fa-city"></i>${name}`,
    picker      : {
        cls              : 'city-list',
        allowGroupSelect : false
    },
    store : {
        modelClass : CityModel,
        groupers   : [
            { field : 'region', ascending : true }
        ],
        data : [
            { name : 'Stockholm', region : 'Europe' },
            { name : 'Barcelona', region : 'Europe' },
            { name : 'Paris', region : 'Europe' },
            { name : 'Dubai', region : 'Middle East' },
            { name : 'Istanbul', region : 'Middle East' },
            { name : 'Riyadh', region : 'Middle East' },
            { name : 'New York', region : 'US' },
            { name : 'San Francisco', region : 'US' },
            { name : 'Washington', region : 'US' },
            { name : 'Montreal', region : 'Canada' },
            { name : 'St Petersburg', region : 'Russia' }
        ]
    }
};

new Grid({

appendTo : 'container',
 
features : {   
    filter: {
			pickerConfig: {
				// remove 'Add Filter' button
				showAddFilterButton : false,
				// Remove the trash icon
				canDeleteFilter     : () => false,
				listeners : {
					beforeAddFilter : ({ filter }) => {
						if ((filter.property === 'start') && filter.operator === '=') {
							filter.operator = 'isToday'; // Change to an allowed default operator
						}
					}
				},
				getFieldFilterPickerConfig : (filter) => {

					if (filter.property === 'start') {
						return {
							operators : {
								// 'date' is redundant because we already know it's a date column, but this is how this config works
								date : [
									{ value: "isToday", text: "Today", argCount: 0 },
									{ value: "isYesterday", text: "Yesterday", argCount: 0 },
									{ value: "isTomorrow", text: "Tomorrow", argCount: 0 },
									{ value: "isLastWeek", text: "Last Week", argCount: 0 },
									{ value: "isLastMonth", text: "Last Month", argCount: 0 },
									{ value: "isNextWeek", text: "Next Week", argCount: 0 },
									{ value: "isNextMonth", text: "Next Month", argCount: 0 },
									{ value: "between", text: "Between", argCount: 2 }
								]
							}
						};
					} else if (filter.property === 'name') {

						return {
							operatorFieldConfig: {
								cls : 'hidden-operator'
							}
						};
 
					}

					return undefined; // Leave UI unchanged for other columns
				}
			}
		},
		quickFind : true,
},

// Headers will ripple on tap in Material theme
ripple : {
    delegate : '.b-grid-header'
},

columns : [
    {
        text   : 'Name',
        field  : 'name',
        flex   : 2,
        editor : {
            type     : 'textfield',
            required : true
        }
    },  { text : 'When', field : 'start', width : 200, type : 'date' }
    , {
        text  : 'City',
        field : 'city',
        flex  : 1,
		editor     : cityCombo,
        minWidth   : 190,
        filterable : {
            filterField : Object.assign(cityCombo, { multiSelect : true })
        }
    }, {
        text  : 'Food',
        field : 'food',
        flex  : 1
    }, {
        type  : 'color',
        text  : 'Color',
        field : 'color',
        width : 80
    }
],

data : DataGenerator.generateData(50)

});


Post by joakim.l »

I'll start by answering #3

This can be somewhat achieved with CSS and some additional JS listeners.
This example code is not thoroughly tested, and will probably need some adjusting before working properly in all conditions.

// Add this to your features.filter config
pickerConfig : {
   listeners : {
      // This event will be triggered when a popup is shown
      paint({ source }) {
         // Add CSS class to column header element to be able to affect filter icon styling
         source.owner.forElement.classList.add('filter-popup-open');
         // Add a hide listener to the created Popup-class
         source.owner.on({
            hide({ source }) {
               // When the filter popup closes, remove the class
               source.forElement.classList.remove('filter-popup-open');
            },
            once : true
         });
      }
   }
}

// Add a listener to the Store
grid.store.on('filter', ({ filters }) => {
    const disabledFilterFields = filters.values.filter(filter => filter.disabled).map(filter => filter.property);
    grid.columns.forEach(column => {
        if (disabledFilterFields.includes(column.field)) {
            column.element.classList.add('filter-disabled');
        }
        else {
            column.element.classList.remove('filter-disabled');
        }
    });
});

And the CSS


/* Make filter icon always visible and default color red
.b-grid-header.b-filterable .b-filter-icon {
	display: flex;
	color:red;
}

/* Simplifies CSS rules a bit */
.b-grid-header.b-filterable .b-filter-icon:after{
	color:inherit;
}

/* Filter icon black on hover */
.b-grid-header .b-filter-icon:hover{
	color:black;
}

/* Change icon when there is an active filter */
.b-grid-header.b-filter .b-filter-icon:after{
	/* This is only to display what's possible. We only include the FontAwesome Free icons, and the thin icons isn't available there.
	     You can always load your own FontAwesome package. We have a guide on how to do that. */
	content:'\e17b';
}

/* Yellow color when filter popup is open */
.b-grid-header.filter-popup-open .b-filter-icon {
	color:yellow !important;
}

/* Green color when there is a disabled filter */
.b-grid-header.filter-disabled .b-filter-icon {
	color:green !important;
}

Regards
Joakim


Post by jintech »

Thanks @joakim.

Could you also provide feedback on the following point? Is this achievable in the Bryntum Grid?

For point #2, I would like a checkmark button in the city filter (on list dropdown column) popup that functions the same way as the one in the Name column. And I don't want filter like Name column have, I want the list in city filter.

5.png
5.png (34.75 KiB) Viewed 278 times

I am adding the code again.

https://bryntum.com/products/grid/examples/basic/


import { Toast, Grid, DataGenerator, Column, ColumnStore, StringHelper, Model} from '../../build/grid.module.js?479836';
import shared from '../_shared/shared.module.js?479836';

class CityModel extends Model {
    static idField = 'name';
    static fields = [
        'name',
        'region'
    ];
}

const cityCombo = {
    type         : 'combo',
    valueField   : 'name',
    displayField : 'name',
    cls          : 'city-combo',
    chipView     : {
        iconTpl : () => '<i class="b-icon b-fa-city"></i>'
    },
    listItemTpl : ({ name }) => `<i class="b-icon b-fa-city"></i>${name}`,
    picker      : {
        cls              : 'city-list',
        allowGroupSelect : false
    },
    store : {
        modelClass : CityModel,
        groupers   : [
            { field : 'region', ascending : true }
        ],
        data : [
            { name : 'Stockholm', region : 'Europe' },
            { name : 'Barcelona', region : 'Europe' },
            { name : 'Paris', region : 'Europe' },
            { name : 'Dubai', region : 'Middle East' },
            { name : 'Istanbul', region : 'Middle East' },
            { name : 'Riyadh', region : 'Middle East' },
            { name : 'New York', region : 'US' },
            { name : 'San Francisco', region : 'US' },
            { name : 'Washington', region : 'US' },
            { name : 'Montreal', region : 'Canada' },
            { name : 'St Petersburg', region : 'Russia' }
        ]
    }
};

const grid = new Grid({

appendTo : 'container',
 
features : {   
filter: { pickerConfig: { // remove 'Add Filter' button showAddFilterButton : false, // Remove the trash icon canDeleteFilter : () => false, listeners : { beforeAddFilter : ({ filter }) => { } }, getFieldFilterPickerConfig : (filter) => { return undefined; // Leave UI unchanged for other columns } } }, quickFind : true, }, // Headers will ripple on tap in Material theme ripple : { delegate : '.b-grid-header' }, columns : [ { text : 'City', field : 'city', flex : 1, editor : cityCombo, minWidth : 190, filterable : { filterField : Object.assign(cityCombo, { multiSelect : true }) } }, { text : 'Name', field : 'name', flex : 2, editor : { type : 'textfield', required : true } } ], data : DataGenerator.generateData(50) });

Post by emil »

Hi jintech,

For your point #2 above, would it be possible for you to use the new UI instead of the legacy filterField config? You could use the getValueFieldConfig function to customize the value field and give it your cityCombo config:

getFieldFilterPickerConfig : (filter) => {
    if (filter.property === 'city') {
        return {
            getValueFieldConfig : (filter, fieldConfig) => ({
                ...fieldConfig,
                ...cityCombo
            })
        };
    }
}

Post Reply