24
24
25
25
import com .vaadin .flow .component .Component ;
26
26
import com .vaadin .flow .component .HasValueAndElement ;
27
- import com .vaadin .flow .component .button .Button ;
28
- import com .vaadin .flow .component .dependency .CssImport ;
27
+ import com .vaadin .flow .component .dependency .JsModule ;
29
28
import com .vaadin .flow .component .grid .ColumnPathRenderer ;
30
29
import com .vaadin .flow .component .grid .FilterField ;
31
30
import com .vaadin .flow .component .grid .FilterFieldDto ;
34
33
import com .vaadin .flow .component .grid .GridSorterFilterComponentRenderer ;
35
34
import com .vaadin .flow .component .grid .SortOrderProvider ;
36
35
import com .vaadin .flow .component .html .Div ;
37
- import com .vaadin .flow .component .icon .Icon ;
38
- import com .vaadin .flow .component .icon .VaadinIcon ;
36
+ import com .vaadin .flow .component .html .Span ;
39
37
import com .vaadin .flow .data .renderer .Renderer ;
40
38
import com .vaadin .flow .function .ValueProvider ;
39
+ import com .vaadin .flow .internal .HtmlUtils ;
41
40
42
41
/**
43
42
*
44
43
* {@link Grid.Column Column} that extends setHeader methods to add a filter button
45
44
* and a {@link FilterField filter component} to perform column's filtering.
46
45
*
47
46
*/
48
- @ CssImport (value = "./styles/enhanced-column.css" )
49
- @ CssImport (value = "./styles/enhanced-column-sorter.css" , themeFor = "vaadin-grid-sorter" )
47
+ @ JsModule (value = "./src/enhanced-grid-sorter.js" )
50
48
public class EnhancedColumn <T > extends Grid .Column <T > {
51
49
52
50
private HasValueAndElement <?, ? extends FilterFieldDto > filter ;
@@ -55,10 +53,10 @@ public class EnhancedColumn<T> extends Grid.Column<T> {
55
53
56
54
private EnhancedGrid <T > grid ;
57
55
58
- private Button filterButton ;
59
-
60
56
private FilterField filterField ;
61
57
58
+ private Component headerComponent ;
59
+
62
60
/**
63
61
* @see Column#Column(Grid, String, Renderer)
64
62
*
@@ -73,7 +71,7 @@ public EnhancedColumn(EnhancedGrid<T> grid, String columnId, Renderer<T> rendere
73
71
74
72
public EnhancedColumn <T > setHeader (String labelText , HasValueAndElement <?, ? extends FilterFieldDto > filter ) {
75
73
if (filter != null ) {
76
- Component headerComponent = new Div ();
74
+ Component headerComponent = new Span ();
77
75
headerComponent .getElement ().setText (labelText );
78
76
addFilterButtonToHeader (headerComponent , filter );
79
77
return setHeader (headerComponent );
@@ -108,18 +106,10 @@ public EnhancedColumn<T> setHeader(String labelText) {
108
106
109
107
private void addFilterButtonToHeader (Component headerComponent , HasValueAndElement <?, ? extends FilterFieldDto > filter ) {
110
108
this .filter = filter ;
111
-
112
- // add filter button
113
- filterButton = new Button (new Icon (VaadinIcon .FILTER ));
114
- filterButton .setId ("filter-button" );
115
- filterButton .addClassName ("filter-not-selected" );
116
- filterButton .getElement ().addEventListener ("click" , click -> {
117
- //do nothing
118
- }).addEventData ("event.stopPropagation()" );
109
+ this .headerComponent = headerComponent ;
119
110
120
- // add filter field popup and set filter as it's filter component
111
+ // add filter field ( popup component) and set filter as it's filter component
121
112
filterField = new FilterField ();
122
- filterField .setFor (filterButton .getId ().get ());
123
113
filterField .addApplyFilterListener (grid );
124
114
filterField .addFilterComponent (filter .getElement ().getComponent ().get ());
125
115
@@ -132,36 +122,55 @@ private void addFilterButtonToHeader(Component headerComponent, HasValueAndEleme
132
122
}
133
123
}
134
124
});
125
+
126
+ // need to add a not visible component so filterField (popup component) can be open
127
+ Div div = new Div ();
128
+ div .setId (getInternalId ());
129
+ div .getElement ().getStyle ().set ("display" , "inline-block" );
130
+ filterField .setFor (div .getId ().get ());
131
+ headerComponent .getElement ().appendChild (div .getElement ());
135
132
136
- headerComponent .getElement ().appendChild (filterButton .getElement ());
137
133
// this is needed to avoid js issues when adding popup
138
134
headerComponent .getElement ().executeJs ("return" ).then (ignore -> {
139
135
headerComponent .getElement ().appendChild (filterField .getElement ());
140
- });
136
+ });
137
+
138
+ grid .addFilterClickedEventListener (e -> {
139
+ if (e .buttonId .equals (getInternalId ())) {
140
+ if (filterField .isOpened ()) {
141
+ filterField .hide ();
142
+ } else {
143
+ filterField .show ();
144
+ }
145
+ }
146
+ });
141
147
}
142
-
148
+
143
149
HasValueAndElement <?, ? extends FilterFieldDto > getFilter () {
144
150
return filter ;
145
151
}
146
152
147
153
void updateFilterButtonStyle (){
148
- if (filter .isEmpty ()) {
149
- filterButton .getClassNames ().remove ("filter-selected" );
150
- filterButton .getClassNames ().add ("filter-not-selected" );
151
- } else {
152
- filterButton .getClassNames ().remove ("filter-not-selected" );
153
- filterButton .getClassNames ().add ("filter-selected" );
154
- }
154
+ if (headerComponent != null ) {
155
+ headerComponent .getElement ().executeJs ("return" ).then (ignore -> {
156
+ if (hasFilterSelected ()) {
157
+ headerComponent .getElement ().executeJs ("this.parentElement.parentElement._setProperty('filtered', true)" );
158
+ } else {
159
+ headerComponent .getElement ().executeJs ("this.parentElement.parentElement._setProperty('filtered', false);" );
160
+ }
161
+ });
162
+ }
155
163
}
156
-
164
+
157
165
ValueProvider <T , ?> getValueProvider (){
158
- if (this .getRenderer () instanceof ColumnPathRenderer ) {
159
- valueProvider = ((ColumnPathRenderer <T >)this .getRenderer ()).getValueProviders ().values ().iterator ().next ();
160
- } else if (valueProvider == null ){
166
+ if (this .valueProvider != null ) {
167
+ return this .valueProvider ;
168
+ } else if (this .getRenderer () instanceof ColumnPathRenderer ) {
169
+ return ((ColumnPathRenderer <T >)this .getRenderer ()).getValueProviders ().values ().iterator ().next ();
170
+ } else {
161
171
throw new UnsupportedOperationException ("Value provider for column is unknown. "
162
172
+ "Please set one calling setValueProvider method." );
163
173
}
164
- return valueProvider ;
165
174
}
166
175
167
176
public void setValueProvider (ValueProvider <T , ?> valueProvider ) {
@@ -234,5 +243,50 @@ public EnhancedColumn<T> setComparator(Comparator<T> comparator) {
234
243
protected void setHeaderComponent (Component component ) {
235
244
super .setHeaderRenderer (new GridSorterFilterComponentRenderer <>(this , component ));
236
245
}
237
-
246
+
247
+ /**
248
+ * Return if column shows filter field
249
+ *
250
+ * @return
251
+ */
252
+ public boolean isFilterable () {
253
+ return filterField != null ;
254
+ }
255
+
256
+ /**
257
+ * Returns if column is filtered
258
+ *
259
+ * @return
260
+ */
261
+ public boolean hasFilterSelected () {
262
+ return filter != null && !filter .isEmpty ();
263
+ }
264
+
265
+ /**
266
+ * Add enhanced-grid-sorter element to header template.
267
+ *
268
+ * This element is an extension of vaadin-grid-sorter that also
269
+ * adds the filtering button to the header.
270
+ *
271
+ * @param templateInnerHtml
272
+ * @return
273
+ */
274
+ public String addEnhancedGridSorter (String templateInnerHtml ) {
275
+ String escapedColumnId = HtmlUtils
276
+ .escape (this .getInternalId ());
277
+ String sortable = isSortable () ? " sortable" : "" ;
278
+ String filtered = hasFilterSelected () ? " filtered" : "" ;
279
+ return String .format (
280
+ "<enhanced-grid-sorter path='%s'" + sortable + filtered +">%s</enhanced-grid-sorter>" ,
281
+ escapedColumnId , templateInnerHtml );
282
+ }
283
+
284
+ /**
285
+ * @see Column#setKey(String)
286
+ *
287
+ */
288
+ @ Override
289
+ public EnhancedColumn <T > setKey (String key ) {
290
+ return (EnhancedColumn <T >) super .setKey (key );
291
+ }
238
292
}
0 commit comments