From 81891024289c5d605f0766a6c6efe3e5b560366e Mon Sep 17 00:00:00 2001 From: Marin Bratanov Date: Tue, 16 Jun 2020 18:04:22 +0300 Subject: [PATCH 1/6] chore(grid): split templates article to separate pages --- _config.yml | 7 +- components/grid/hierarchy.md | 2 +- components/grid/manual-operations.md | 2 +- components/grid/state.md | 2 +- components/grid/templates.md | 490 ------------------ .../grid/templates/column-group-footer.md | 87 ++++ components/grid/templates/column-header.md | 126 +++++ components/grid/templates/column.md | 80 +++ components/grid/templates/editor.md | 99 ++++ components/grid/templates/group-header.md | 90 ++++ .../{ => templates}/images/cell-template.png | Bin .../images/column-group-footer-template.png | Bin .../{ => templates}/images/edit-template.png | Bin .../images/group-header-template.png | Bin .../images/header-template.png | Bin .../{ => templates}/images/row-template.png | Bin components/grid/templates/overview.md | 39 ++ components/grid/templates/row.md | 70 +++ components/grid/toolbar.md | 2 +- components/grid/virtual-scrolling.md | 2 +- 20 files changed, 601 insertions(+), 497 deletions(-) delete mode 100644 components/grid/templates.md create mode 100644 components/grid/templates/column-group-footer.md create mode 100644 components/grid/templates/column-header.md create mode 100644 components/grid/templates/column.md create mode 100644 components/grid/templates/editor.md create mode 100644 components/grid/templates/group-header.md rename components/grid/{ => templates}/images/cell-template.png (100%) rename components/grid/{ => templates}/images/column-group-footer-template.png (100%) rename components/grid/{ => templates}/images/edit-template.png (100%) rename components/grid/{ => templates}/images/group-header-template.png (100%) rename components/grid/{ => templates}/images/header-template.png (100%) rename components/grid/{ => templates}/images/row-template.png (100%) create mode 100644 components/grid/templates/overview.md create mode 100644 components/grid/templates/row.md diff --git a/_config.yml b/_config.yml index 54e794d511..28fab9c934 100644 --- a/_config.yml +++ b/_config.yml @@ -65,12 +65,15 @@ navigation: "*components/grid/editing": title: "Editing" position: 10 + "*components/grid/templates": + title: "Templates" + position: 25 "*components/grid/export": title: "Export" - position: 24 + position: 30 "*components/grid/selection": title: "Selection" - position: 24 + position: 35 "*components/chart/types": title: "Types" position: 15 diff --git a/components/grid/hierarchy.md b/components/grid/hierarchy.md index 9c38bed0d9..6bbc39fdf3 100644 --- a/components/grid/hierarchy.md +++ b/components/grid/hierarchy.md @@ -5,7 +5,7 @@ description: Enable and configure hierarchy and detail records in Grid for Blazo slug: components/grid/features/hierarchy tags: telerik,blazor,grid,hierarchy,detail,detail template published: True -position: 25 +position: 40 --- # Grid Hierarchy diff --git a/components/grid/manual-operations.md b/components/grid/manual-operations.md index 5c82a390b4..bb4c6d6463 100644 --- a/components/grid/manual-operations.md +++ b/components/grid/manual-operations.md @@ -5,7 +5,7 @@ description: How to implement your own read, page, fiter, sort operations for th slug: components/grid/manual-operations tags: telerik,blazor,grid,read,filter,sort,page,manual,data,data source published: True -position: 50 +position: 55 --- # Manual Data Source Operations diff --git a/components/grid/state.md b/components/grid/state.md index 117a499089..2a5ebb2c07 100644 --- a/components/grid/state.md +++ b/components/grid/state.md @@ -5,7 +5,7 @@ description: Save, load, change the Grid for Blazor state - grouping, sorting, f slug: grid-state tags: telerik,blazor,grid,state,save,load,layout,set,change,management published: True -position: 40 +position: 50 --- # Grid State diff --git a/components/grid/templates.md b/components/grid/templates.md deleted file mode 100644 index ccb08176ea..0000000000 --- a/components/grid/templates.md +++ /dev/null @@ -1,490 +0,0 @@ ---- -title: Templates -page_title: Grid for Blazor | Templates -description: Use custom templates in Grid for Blazor -slug: components/grid/features/templates -tags: telerik,blazor,grid,templates -published: True -position: 35 ---- - -# Grid Templates - -The Grid component can use templates for: -* [columns (cells)](#column-template) -* [rows](#row-template) -* [editing of a field](#edit-template) -* [column header](#header-template) -* [column group footer](#column-group-footer) -* [group header](#group-header) - - -Like other Blazor content, they can receive a `context` argument that is the type of the model. To use templates, you must bind the grid to a named model. - -You must make sure to provide valid HTML in the templates. - -## Column Template - -By default, the grid renders the value of the field in the column, as it is provided from the data source. You can change this behavior by using the `Template` of the column and add your own content and/or logic to make a string out of the object. - -The example below shows how to: - -* set the `Template` (make sure to use the capital `T`, at the time of writing the Visual Studio autocomplete tends to use the lowercase `t` which breaks the template logic and does not allow you to access the context) -* access the `context` of the model item so you can employ your own logic -* set HTML in the column -* use inline or multi-line template -* take the field name from the model - ->caption Using cell (column) template - -````CSHTML -Cell template that renders an image based on model data - - - - - - - - - - - - - - - - - -@code { - public class SampleData - { - public int ID { get; set; } - public string Name { get; set; } - public DateTime HireDate { get; set; } - } - - public IEnumerable MyData = Enumerable.Range(1, 50).Select(x => new SampleData - { - ID = x, - Name = "name " + x, - HireDate = DateTime.Now.AddDays(-x) - }); -} -```` - ->caption The result from the code snippet above - -![](images/cell-template.png) - -## Row Template - -The row template allows you to define in your own code the entire contents of the `` element the grid will render for each record. To set it, provide contents to the `` inner tag of the grid. - -It can be convenient if you want to use templates for most or all of the columns, as it requires less markup than setting individual templates for many columns. - -The contents of the row template must be `` elements and their number (or total `colspan`) must match the number of columns defined in the grid. - -You can use the `Context` attribute of the `` tag of the grid to set the name of the context variable. Its type is the model type to which the grid is bound. - ->important Using the row template takes functionality away from the grid because it no longer controls its own rendering. For example, InCell and Inline editing could not render editors, detail templates will not be available, column resizing and reordering cannot change the data cells anymore, only the headers, and row selection must be implemented by the app ([example](https://feedback.telerik.com/blazor/1463819)). - ->caption Using a row template - -````CSHTML -Render the entire row with your own code and logic - - - - - employee photo - @employee.Name - - - Hired on: @(String.Format("{0:dd MMM yyyy}", employee.HireDate)) - - - - - - - - -@code { - public class SampleData - { - public int ID { get; set; } - public string Name { get; set; } - public DateTime HireDate { get; set; } - } - - public IEnumerable MyData = Enumerable.Range(1, 50).Select(x => new SampleData - { - ID = x, - Name = "name " + x, - HireDate = DateTime.Now.AddDays(-x) - }); -} -```` - ->caption The result from the code snippet above - -![](images/row-template.png) - -## Edit Template - -The column's `EditTemplate` defines the inline template or component that will be rendered when the user is [editing]({%slug components/grid/overview%}#editing) the field. - -You can data bind components in it to the current context, which is an instance of the model the grid is bound to. You will need a global variable that is also an instance of the model to store those changes. The model the template receives is a copy of the original model, so that changes can be cancelled (the `Cancel` command). - -If you need to perform logic more complex than simple data binding, use the change event of the custom editor component to perform it. You can also consider using a [custom edit form](https://demos.telerik.com/blazor-ui/grid/editing-custom-form). - ->caption Sample edit template - -````CSHTML -@* This example shows how to use a dropdownlist to edit strings. You can implement any desired logic instead. -If you have an enum, the grid can edit and filter it out-of-the-box without the need for an edit template *@ - - - - - - - - @{ - CurrentlyEditedEmployee = context as SampleData; - - } - - - - Update - Edit - - - - -@code { - public SampleData CurrentlyEditedEmployee { get; set; } - - public void UpdateHandler(GridCommandEventArgs args) - { - SampleData item = (SampleData)args.Item; - - //perform actual data source operations here - //if you have a context added through an @inject statement, you could call its SaveChanges() method - //myContext.SaveChanges(); - - var index = MyData.FindIndex(i => i.ID == item.ID); - if (index != -1) - { - MyData[index] = item; - } - } - - protected override void OnInitialized() - { - MyData = new List(); - - for (int i = 0; i < 50; i++) - { - MyData.Add(new SampleData() - { - ID = i, - Name = "name " + i, - Role = Roles[i % Roles.Count] - }); - } - } - - //in a real case, keep the models in dedicated locations, this is just an easy to copy and see example - public class SampleData - { - public int ID { get; set; } - public string Name { get; set; } - public string Role { get; set; } - } - - public List MyData { get; set; } - - public static List Roles = new List { "Manager", "Employee", "Contractor" }; -} -```` - ->caption The result from the code snippet above, after Edit was clicked on the first row and the user expanded the dropdown from the template - -![](images/edit-template.png) - - -## Header Template - -Bound columns render the name of the field or their `Title` in their header. Through the `HeaderTemplate`, you can define custom content there instead of the title text. - ->caption Sample Header Template - -````CSHTML -@* Header templates override the built-in title but leave sorting indicators and filter menu icons *@ - - - - - -
Id
- @* this is a block element and it will push the sorting indicator, see the notes below *@ -
-
- - - Employee
Name -
-
- - - Hire date
- Do something -
- @{ - if (!string.IsNullOrEmpty(result)) - { - @result - } - else - { -
something will appear here if you click the button
- } - } -
-
- - - - - Column with Icon - - - -
-
- -@code { - string result { get; set; } - void DoSomething() - { - result = $"button in header template clicked on {DateTime.Now}, something happened"; - } - - public class SampleData - { - public int ID { get; set; } - public string Name { get; set; } - public DateTime HireDate { get; set; } - } - - public IEnumerable MyData = Enumerable.Range(1, 50).Select(x => new SampleData - { - ID = x, - Name = "name " + x, - HireDate = DateTime.Now.AddDays(-x) - }); -} -```` - ->caption The result from the code snippet above - -![](images/header-template.png) - ->note Header Templates are not available for the `GridCheckboxColumn` and the `GridCommandColumn`. - ->note If you need to use block elements in the header templates, keep in mind that they will push the sort indicator out of its expected position. If you cannot avoid block elements (such as in the `ID` column in the example above), add a CSS rule like the ones below to adjust the sort indicator. - ->caption Sort indicator adjustments when block elements are in the header template - -````CSS -.k-grid th.k-header .k-icon.k-i-sort-asc-sm, -.k-grid th.k-header .k-icon.k-i-sort-desc-sm { - position: absolute; - right: 0; - top: 8px; -} - -/* OR */ - -.k-grid-header .k-header > .k-link { - padding-right: 1.5em; -} - - .k-grid-header .k-header > .k-link > .k-icon { - position: absolute; - top: 50%; - right: 0.5em; - transform: translateY(-50%); - margin-left: 0; - } - -.k-grid-header .k-sort-order { - position: absolute; - right: 0.25em; -} -```` - -## Column Group Footer - -When the grid is grouped, the columns can display a footer with information about the column data [aggregates]({%slug grid-aggregates%}) and some custom text/logic. The template is strongly typed and exposes the available aggregates values. - ->caption Sample Column Group Footer Template - -````CSHTML -@* Group by the Team column to see the results and aggregate data in the footer *@ - - - - - - - - - - - - Team Members: @context.Count - - - - - @* you can use a group footer for non-groupable columns as well *@ - Total montly salary: @context.Sum -
- Top paid employee: @context.Max -
-
- - -
-
- -@code { - public List GridData { get; set; } - - protected override void OnInitialized() - { - GridData = new List(); - var rand = new Random(); - for (int i = 0; i < 15; i++) - { - Random rnd = new Random(); - GridData.Add(new Employee() - { - EmployeeId = i, - Name = "Employee " + i.ToString(), - Team = "Team " + i % 3, - Salary = rnd.Next(1000, 5000), - ActiveProjects = i % 4 == 0 ? 2 : 5 - }); - } - } - - public class Employee - { - public int EmployeeId { get; set; } - public string Name { get; set; } - public string Team { get; set; } - public decimal Salary { get; set; } - public int ActiveProjects { get; set; } - } -} -```` - ->caption The result from the code snippet above after grouping by the `Team` column - -![](images/column-group-footer-template.png) - -## Group Header - -When the grid is grouped, the top row above the group provides information about the current group value by default. You can use this template to add custom content there in addition to the current value. For more information and examples, see the [Aggregates]({%slug grid-aggregates%}) article. - ->caption Sample Group Header Template - -````CSHTML -@* Group by the Team and Active Projects fields to see the results *@ - - - - - - - - - - @context.Value @* the default text you would get without the template *@ -  Team size: @context.Count - - - - - - @{ - Currently active projects: @context.Value   - - //sample of conditional logic in the group header - if ( (int)context.Value > 3) // in a real case, ensure type safety and add defensive checks - { - These people work on too many projects - } - } - - - - - -@code { - public List GridData { get; set; } - - protected override void OnInitialized() - { - GridData = new List(); - var rand = new Random(); - for (int i = 0; i < 15; i++) - { - Random rnd = new Random(); - GridData.Add(new Employee() - { - EmployeeId = i, - Name = "Employee " + i.ToString(), - Team = "Team " + i % 3, - Salary = rnd.Next(1000, 5000), - ActiveProjects = i % 4 == 0 ? 2 : 5 - }); - } - } - - public class Employee - { - public int EmployeeId { get; set; } - public string Name { get; set; } - public string Team { get; set; } - public decimal Salary { get; set; } - public int ActiveProjects { get; set; } - } -} -```` - ->caption The result from the code snippet above after grouping by the `Team` and `Active Projects` columns - -![](images/group-header-template.png) - -## See Also - - * [Live Demo: Grid Templates](https://demos.telerik.com/blazor-ui/grid/templates) - * [Live Demo: Grid Custom Editor Template](https://demos.telerik.com/blazor-ui/grid/customeditor) - diff --git a/components/grid/templates/column-group-footer.md b/components/grid/templates/column-group-footer.md new file mode 100644 index 0000000000..4598d50826 --- /dev/null +++ b/components/grid/templates/column-group-footer.md @@ -0,0 +1,87 @@ +--- +title: Column Group Footer +page_title: Grid for Blazor | Column Group Footer Template +description: Use custom column group footer templates in Grid for Blazor +slug: grid-templates-column-group-footer +tags: telerik,blazor,grid,templates,column,group,footer +published: True +position: 25 +--- + +## Column Group Footer + +When the grid is grouped, the columns can display a footer with information about the column data [aggregates]({%slug grid-aggregates%}) and some custom text/logic. The template is strongly typed and exposes the available aggregates values. + +>caption Sample Column Group Footer Template + +````CSHTML +@* Group by the Team column to see the results and aggregate data in the footer *@ + + + + + + + + + + + + Team Members: @context.Count + + + + + @* you can use a group footer for non-groupable columns as well *@ + Total montly salary: @context.Sum +
+ Top paid employee: @context.Max +
+
+ + +
+
+ +@code { + public List GridData { get; set; } + + protected override void OnInitialized() + { + GridData = new List(); + var rand = new Random(); + for (int i = 0; i < 15; i++) + { + Random rnd = new Random(); + GridData.Add(new Employee() + { + EmployeeId = i, + Name = "Employee " + i.ToString(), + Team = "Team " + i % 3, + Salary = rnd.Next(1000, 5000), + ActiveProjects = i % 4 == 0 ? 2 : 5 + }); + } + } + + public class Employee + { + public int EmployeeId { get; set; } + public string Name { get; set; } + public string Team { get; set; } + public decimal Salary { get; set; } + public int ActiveProjects { get; set; } + } +} +```` + +>caption The result from the code snippet above after grouping by the `Team` column + +![](images/column-group-footer-template.png) + + +## See Also + + * [Live Demo: Grid Templates](https://demos.telerik.com/blazor-ui/grid/templates) + * [Live Demo: Grid Custom Editor Template](https://demos.telerik.com/blazor-ui/grid/customeditor) + diff --git a/components/grid/templates/column-header.md b/components/grid/templates/column-header.md new file mode 100644 index 0000000000..860271fd25 --- /dev/null +++ b/components/grid/templates/column-header.md @@ -0,0 +1,126 @@ +--- +title: Column Header +page_title: Grid for Blazor | Column Header Template +description: Use custom column header templates in Grid for Blazor +slug: grid-templates-column-header +tags: telerik,blazor,grid,templates,column,header +published: True +position: 20 +--- + +## Column Header Template + +Bound columns render the name of the field or their `Title` in their header. Through the `HeaderTemplate`, you can define custom content there instead of the title text. + +>caption Sample Header Template + +````CSHTML +@* Header templates override the built-in title but leave sorting indicators and filter menu icons *@ + + + + + +
Id
+ @* this is a block element and it will push the sorting indicator, see the notes below *@ +
+
+ + + Employee
Name +
+
+ + + Hire date
+ Do something +
+ @{ + if (!string.IsNullOrEmpty(result)) + { + @result + } + else + { +
something will appear here if you click the button
+ } + } +
+
+ + + + + Column with Icon + + + +
+
+ +@code { + string result { get; set; } + void DoSomething() + { + result = $"button in header template clicked on {DateTime.Now}, something happened"; + } + + public class SampleData + { + public int ID { get; set; } + public string Name { get; set; } + public DateTime HireDate { get; set; } + } + + public IEnumerable MyData = Enumerable.Range(1, 50).Select(x => new SampleData + { + ID = x, + Name = "name " + x, + HireDate = DateTime.Now.AddDays(-x) + }); +} +```` + +>caption The result from the code snippet above + +![](images/header-template.png) + +>note Header Templates are not available for the `GridCheckboxColumn` and the `GridCommandColumn`. + +>note If you need to use block elements in the header templates, keep in mind that they will push the sort indicator out of its expected position. If you cannot avoid block elements (such as in the `ID` column in the example above), add a CSS rule like the ones below to adjust the sort indicator. + +>caption Sort indicator adjustments when block elements are in the header template + +````CSS +.k-grid th.k-header .k-icon.k-i-sort-asc-sm, +.k-grid th.k-header .k-icon.k-i-sort-desc-sm { + position: absolute; + right: 0; + top: 8px; +} + +/* OR */ + +.k-grid-header .k-header > .k-link { + padding-right: 1.5em; +} + + .k-grid-header .k-header > .k-link > .k-icon { + position: absolute; + top: 50%; + right: 0.5em; + transform: translateY(-50%); + margin-left: 0; + } + +.k-grid-header .k-sort-order { + position: absolute; + right: 0.25em; +} +```` + +## See Also + + * [Live Demo: Grid Templates](https://demos.telerik.com/blazor-ui/grid/templates) + * [Live Demo: Grid Custom Editor Template](https://demos.telerik.com/blazor-ui/grid/customeditor) + diff --git a/components/grid/templates/column.md b/components/grid/templates/column.md new file mode 100644 index 0000000000..6e33f5214c --- /dev/null +++ b/components/grid/templates/column.md @@ -0,0 +1,80 @@ +--- +title: Column (Cell) +page_title: Grid for Blazor | Column (Cell) Template +description: Use custom column and cell templates in Grid for Blazor +slug: grid-templates-column +tags: telerik,blazor,grid,templates,column,cell +published: True +position: 5 +--- + +# Column Template + +By default, the grid renders the value of the field in the column, as it is provided from the data source. You can change this behavior by using the `Template` of the column and add your own content and/or logic to make a string out of the object. + +The example below shows how to: + +* set the `Template` (make sure to use the capital `T`, at the time of writing the Visual Studio autocomplete tends to use the lowercase `t` which breaks the template logic and does not allow you to access the context) +* access the `context` of the model item so you can employ your own logic +* set HTML in the column +* use inline or multi-line template +* take the field name from the model + +>caption Using cell (column) template + +````CSHTML +Cell template that renders an image based on model data + + + + + + + + + + + + + + + + + +@code { + public class SampleData + { + public int ID { get; set; } + public string Name { get; set; } + public DateTime HireDate { get; set; } + } + + public IEnumerable MyData = Enumerable.Range(1, 50).Select(x => new SampleData + { + ID = x, + Name = "name " + x, + HireDate = DateTime.Now.AddDays(-x) + }); +} +```` + +>caption The result from the code snippet above + +![](images/cell-template.png) + +## See Also + + * [Live Demo: Grid Templates](https://demos.telerik.com/blazor-ui/grid/templates) + * [Live Demo: Grid Custom Editor Template](https://demos.telerik.com/blazor-ui/grid/customeditor) + diff --git a/components/grid/templates/editor.md b/components/grid/templates/editor.md new file mode 100644 index 0000000000..7b7b0b4a50 --- /dev/null +++ b/components/grid/templates/editor.md @@ -0,0 +1,99 @@ +--- +title: Editor +page_title: Grid for Blazor | Editor Template +description: Use custom editor templates in Grid for Blazor +slug: grid-templates-editor +tags: telerik,blazor,grid,templates,editor +published: True +position: 15 +--- + +# Edit Template + +The column's `EditTemplate` defines the inline template or component that will be rendered when the user is [editing]({%slug components/grid/overview%}#editing) the field. + +You can data bind components in it to the current context, which is an instance of the model the grid is bound to. You will need a global variable that is also an instance of the model to store those changes. The model the template receives is a copy of the original model, so that changes can be cancelled (the `Cancel` command). + +If you need to perform logic more complex than simple data binding, use the change event of the custom editor component to perform it. You can also consider using a [custom edit form](https://demos.telerik.com/blazor-ui/grid/editing-custom-form). + +>caption Sample edit template + +````CSHTML +@* This example shows how to use a dropdownlist to edit strings. You can implement any desired logic instead. +If you have an enum, the grid can edit and filter it out-of-the-box without the need for an edit template *@ + + + + + + + + @{ + CurrentlyEditedEmployee = context as SampleData; + + } + + + + Update + Edit + + + + +@code { + public SampleData CurrentlyEditedEmployee { get; set; } + + public void UpdateHandler(GridCommandEventArgs args) + { + SampleData item = (SampleData)args.Item; + + //perform actual data source operations here + //if you have a context added through an @inject statement, you could call its SaveChanges() method + //myContext.SaveChanges(); + + var index = MyData.FindIndex(i => i.ID == item.ID); + if (index != -1) + { + MyData[index] = item; + } + } + + protected override void OnInitialized() + { + MyData = new List(); + + for (int i = 0; i < 50; i++) + { + MyData.Add(new SampleData() + { + ID = i, + Name = "name " + i, + Role = Roles[i % Roles.Count] + }); + } + } + + //in a real case, keep the models in dedicated locations, this is just an easy to copy and see example + public class SampleData + { + public int ID { get; set; } + public string Name { get; set; } + public string Role { get; set; } + } + + public List MyData { get; set; } + + public static List Roles = new List { "Manager", "Employee", "Contractor" }; +} +```` + +>caption The result from the code snippet above, after Edit was clicked on the first row and the user expanded the dropdown from the template + +![](images/edit-template.png) + +## See Also + + * [Live Demo: Grid Templates](https://demos.telerik.com/blazor-ui/grid/templates) + * [Live Demo: Grid Custom Editor Template](https://demos.telerik.com/blazor-ui/grid/customeditor) + diff --git a/components/grid/templates/group-header.md b/components/grid/templates/group-header.md new file mode 100644 index 0000000000..af663c654e --- /dev/null +++ b/components/grid/templates/group-header.md @@ -0,0 +1,90 @@ +--- +title: Group Header +page_title: Grid for Blazor | Group Header Template +description: Use custom group header templates in Grid for Blazor +slug: grid-templates-group-header +tags: telerik,blazor,grid,templates,group,header +published: True +position: 30 +--- + + +# Group Header + +When the grid is grouped, the top row above the group provides information about the current group value by default. You can use this template to add custom content there in addition to the current value. For more information and examples, see the [Aggregates]({%slug grid-aggregates%}) article. + +>caption Sample Group Header Template + +````CSHTML +@* Group by the Team and Active Projects fields to see the results *@ + + + + + + + + + + @context.Value @* the default text you would get without the template *@ +  Team size: @context.Count + + + + + + @{ + Currently active projects: @context.Value   + + //sample of conditional logic in the group header + if ( (int)context.Value > 3) // in a real case, ensure type safety and add defensive checks + { + These people work on too many projects + } + } + + + + + +@code { + public List GridData { get; set; } + + protected override void OnInitialized() + { + GridData = new List(); + var rand = new Random(); + for (int i = 0; i < 15; i++) + { + Random rnd = new Random(); + GridData.Add(new Employee() + { + EmployeeId = i, + Name = "Employee " + i.ToString(), + Team = "Team " + i % 3, + Salary = rnd.Next(1000, 5000), + ActiveProjects = i % 4 == 0 ? 2 : 5 + }); + } + } + + public class Employee + { + public int EmployeeId { get; set; } + public string Name { get; set; } + public string Team { get; set; } + public decimal Salary { get; set; } + public int ActiveProjects { get; set; } + } +} +```` + +>caption The result from the code snippet above after grouping by the `Team` and `Active Projects` columns + +![](images/group-header-template.png) + +## See Also + + * [Live Demo: Grid Templates](https://demos.telerik.com/blazor-ui/grid/templates) + * [Live Demo: Grid Custom Editor Template](https://demos.telerik.com/blazor-ui/grid/customeditor) + diff --git a/components/grid/images/cell-template.png b/components/grid/templates/images/cell-template.png similarity index 100% rename from components/grid/images/cell-template.png rename to components/grid/templates/images/cell-template.png diff --git a/components/grid/images/column-group-footer-template.png b/components/grid/templates/images/column-group-footer-template.png similarity index 100% rename from components/grid/images/column-group-footer-template.png rename to components/grid/templates/images/column-group-footer-template.png diff --git a/components/grid/images/edit-template.png b/components/grid/templates/images/edit-template.png similarity index 100% rename from components/grid/images/edit-template.png rename to components/grid/templates/images/edit-template.png diff --git a/components/grid/images/group-header-template.png b/components/grid/templates/images/group-header-template.png similarity index 100% rename from components/grid/images/group-header-template.png rename to components/grid/templates/images/group-header-template.png diff --git a/components/grid/images/header-template.png b/components/grid/templates/images/header-template.png similarity index 100% rename from components/grid/images/header-template.png rename to components/grid/templates/images/header-template.png diff --git a/components/grid/images/row-template.png b/components/grid/templates/images/row-template.png similarity index 100% rename from components/grid/images/row-template.png rename to components/grid/templates/images/row-template.png diff --git a/components/grid/templates/overview.md b/components/grid/templates/overview.md new file mode 100644 index 0000000000..8cc697acf5 --- /dev/null +++ b/components/grid/templates/overview.md @@ -0,0 +1,39 @@ +--- +title: Overview +page_title: Grid for Blazor | Templates Overview +description: Use custom templates in Grid for Blazor +slug: components/grid/features/templates +tags: telerik,blazor,grid,templates +published: True +previous_url: /grid/templates +position: 0 +--- + +# Grid Templates + +You can customize the grid appearance and behavior through the various templates it provides so you can add more details for your users such as aggregate data, format numbers and dates, use custom editing logic, implement custom filters and more. + +The Grid component can use templates for: + +* [columns (cells)]({%slug grid-templates-column%}) - the rendering of each cell (column). You can, for example, change string formats or add your own components. + +* [rows]({%slug grid-templates-row%}) - the entire rendering of the `tr` element of the row, so you can fully customize the grid behavior and rendering. + +* [editing of a field]({%slug grid-templates-editor%}) - when a cell is in edit mode, it will render this template where you can use custom editors, components and logic. + +* [column header]({%slug grid-templates-column-header%}) - the title portion of the column. + +* [column group footer]({%slug grid-templates-column-group-footer%}) - the footer of the column when the grid is [grouped]({%slug components/grid/features/grouping%}) by this column. You can use it, for example, to display [aggregates]({%slug grid-aggregates%}). + +* [group header]({%slug grid-templates-group-header%}) - the shared section that denotes each grid [group]({%slug components/grid/features/grouping%}). + + +Like other Blazor content, they can receive a `context` argument that is the type of the model. To use templates, you must bind the grid to a named model. + +You must make sure to provide valid HTML in the templates. + +## See Also + + * [Live Demo: Grid Templates](https://demos.telerik.com/blazor-ui/grid/templates) + * [Live Demo: Grid Custom Editor Template](https://demos.telerik.com/blazor-ui/grid/customeditor) + diff --git a/components/grid/templates/row.md b/components/grid/templates/row.md new file mode 100644 index 0000000000..fb9b97d9b9 --- /dev/null +++ b/components/grid/templates/row.md @@ -0,0 +1,70 @@ +--- +title: Row +page_title: Grid for Blazor | Row Template +description: Use custom row templates in Grid for Blazor +slug: grid-templates-row +tags: telerik,blazor,grid,templates,row +published: True +position: 10 +--- + +# Row Template + +The row template allows you to define in your own code the entire contents of the `` element the grid will render for each record. To set it, provide contents to the `` inner tag of the grid. + +It can be convenient if you want to use templates for most or all of the columns, as it requires less markup than setting individual templates for many columns. + +The contents of the row template must be `` elements and their number (or total `colspan`) must match the number of columns defined in the grid. + +You can use the `Context` attribute of the `` tag of the grid to set the name of the context variable. Its type is the model type to which the grid is bound. + +>important Using the row template takes functionality away from the grid because it no longer controls its own rendering. For example, InCell and Inline editing could not render editors, detail templates will not be available, column resizing and reordering cannot change the data cells anymore, only the headers, and row selection must be implemented by the app ([example](https://feedback.telerik.com/blazor/1463819)). + +>caption Using a row template + +````CSHTML +Render the entire row with your own code and logic + + + + + employee photo + @employee.Name + + + Hired on: @(String.Format("{0:dd MMM yyyy}", employee.HireDate)) + + + + + + + + +@code { + public class SampleData + { + public int ID { get; set; } + public string Name { get; set; } + public DateTime HireDate { get; set; } + } + + public IEnumerable MyData = Enumerable.Range(1, 50).Select(x => new SampleData + { + ID = x, + Name = "name " + x, + HireDate = DateTime.Now.AddDays(-x) + }); +} +```` + +>caption The result from the code snippet above + +![](images/row-template.png) + + +## See Also + + * [Live Demo: Grid Templates](https://demos.telerik.com/blazor-ui/grid/templates) + * [Live Demo: Grid Custom Editor Template](https://demos.telerik.com/blazor-ui/grid/customeditor) + diff --git a/components/grid/toolbar.md b/components/grid/toolbar.md index 4c15174e30..2fda9a1ddf 100644 --- a/components/grid/toolbar.md +++ b/components/grid/toolbar.md @@ -5,7 +5,7 @@ description: Use toolbar and custom actions in Grid for Blazor slug: components/grid/features/toolbar tags: telerik,blazor,grid,toolbar published: True -position: 30 +position: 45 --- # Grid Toolbar diff --git a/components/grid/virtual-scrolling.md b/components/grid/virtual-scrolling.md index 056ee4cbf8..8af095abf3 100644 --- a/components/grid/virtual-scrolling.md +++ b/components/grid/virtual-scrolling.md @@ -5,7 +5,7 @@ description: Enable and configure virtual scrolling in Grid for Blazor slug: components/grid/virtual-scrolling tags: telerik,blazor,grid,virtual,scrolling published: True -position: 55 +position: 60 --- # Virtual Scrolling From 18572ad018444131fd17ead08772b8cd74dfbf61 Mon Sep 17 00:00:00 2001 From: Marin Bratanov Date: Tue, 16 Jun 2020 18:08:13 +0300 Subject: [PATCH 2/6] chore(grid): fix typo --- components/grid/templates/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/grid/templates/overview.md b/components/grid/templates/overview.md index 8cc697acf5..c743b5aae2 100644 --- a/components/grid/templates/overview.md +++ b/components/grid/templates/overview.md @@ -23,7 +23,7 @@ The Grid component can use templates for: * [column header]({%slug grid-templates-column-header%}) - the title portion of the column. -* [column group footer]({%slug grid-templates-column-group-footer%}) - the footer of the column when the grid is [grouped]({%slug components/grid/features/grouping%}) by this column. You can use it, for example, to display [aggregates]({%slug grid-aggregates%}). +* [column group footer]({%slug grid-templates-column-group-footer%}) - the footer of the column when the grid is [grouped]({%slug components/grid/features/grouping%}). You can use it, for example, to display [aggregates]({%slug grid-aggregates%}). * [group header]({%slug grid-templates-group-header%}) - the shared section that denotes each grid [group]({%slug components/grid/features/grouping%}). From 57fd894844b79d9bbe922cd8b4ab46e54b3dbc00 Mon Sep 17 00:00:00 2001 From: Marin Bratanov Date: Thu, 18 Jun 2020 19:29:29 +0300 Subject: [PATCH 3/6] docs(grid): first sample for custom filter menu --- .../grid/templates/column-group-footer.md | 2 +- components/grid/templates/column-header.md | 2 +- components/grid/templates/filter.md | 142 ++++++++++++++++++ .../images/filter-menu-template-basic.png | Bin 0 -> 13511 bytes 4 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 components/grid/templates/filter.md create mode 100644 components/grid/templates/images/filter-menu-template-basic.png diff --git a/components/grid/templates/column-group-footer.md b/components/grid/templates/column-group-footer.md index 4598d50826..44da3e4f36 100644 --- a/components/grid/templates/column-group-footer.md +++ b/components/grid/templates/column-group-footer.md @@ -8,7 +8,7 @@ published: True position: 25 --- -## Column Group Footer +# Column Group Footer When the grid is grouped, the columns can display a footer with information about the column data [aggregates]({%slug grid-aggregates%}) and some custom text/logic. The template is strongly typed and exposes the available aggregates values. diff --git a/components/grid/templates/column-header.md b/components/grid/templates/column-header.md index 860271fd25..8d65e13ad6 100644 --- a/components/grid/templates/column-header.md +++ b/components/grid/templates/column-header.md @@ -8,7 +8,7 @@ published: True position: 20 --- -## Column Header Template +# Column Header Template Bound columns render the name of the field or their `Title` in their header. Through the `HeaderTemplate`, you can define custom content there instead of the title text. diff --git a/components/grid/templates/filter.md b/components/grid/templates/filter.md new file mode 100644 index 0000000000..bbdc508cdc --- /dev/null +++ b/components/grid/templates/filter.md @@ -0,0 +1,142 @@ +--- +title: Filter +page_title: Grid for Blazor | Filter Template +description: Use custom filter templates in Grid for Blazor +slug: grid-templates-filter +tags: telerik,blazor,grid,templates,filter +published: True +position: 35 +--- + + +# Filter Template + +The Filter Template lets you customize the appearance and logic of the built-in filters. It lets you step on the built-in filtering logic of the grid and implement your own design and logic for setting their values. + +There are two different templates you can use depending on the [Filter Mode]({%slug components/grid/filtering%}) that you use: + +* Filter Menu + +* Filter Row + +## Filter Menu + +By default, the filter menu contains two filter values that are tied with a logical operator - OR or AND. The filter template for it (`` under the corresponding ``) provides you with the default composite filter in its `context`, and the `Filter` and `Clear` buttons below the template. + +In the example below, you can see how to: + +* Keep only one input (declare only one, and clear the subsequent filter from the composite filter the grid provides). +* Customize the user input experience (set some properties to the numeric textbox or the corresponding editor you use). +* Choose the desired filter operators while using custom text for them (a dropdown list with the desired data source). +* Change the size of the filter popup (defining your own layout with desired size and styles) - which is not mandatory. + +Comments in the code offer more insights into how all the features tie together. + +>caption Customize Filter Menu operators and value area + +````CSHTML +@using Telerik.DataSource + + + + + + @{ + // we step on the built-in filter descriptor of the grid + // and reuse it to populate it from the custom filter input + // the built-in Filter and Clear buttons of the grid remain available + // and in this case we ensure only one filter is used, and customize the way + // filter operators and values are provided to the grid filtering + UnitPriceFilterMenuTemplateContext = context; + + // leave only one filter descriptor (there are two by default) + var descriptor1 = UnitPriceFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.ElementAtOrDefault(0); + UnitPriceFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.Clear(); + UnitPriceFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.Add(descriptor1); + } + + @* you can customize the appearance and size of the template area *@ +
+
+ + +
+ +
+ +
+
+
+
+ +
+
+ +@code { + // sample data for the grid + List GridData { get; set; } = Enumerable.Range(1, 50).Select(x => new SampleData { Id = x, Price = x * 0.5m }).ToList(); + + // stores the default filter context with the default column filter that the Grid has + // this lets you manipulate it and reuse it according to your logic + public FilterMenuTemplateContext UnitPriceFilterMenuTemplateContext { get; set; } + + // this references the first built-in filter descriptor so you can easily + // populate its value from the custom filter component - a numeric textbox in this sample + public FilterDescriptor UnitPriceFilterDescriptor + { + get + { + var descriptor = UnitPriceFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.ElementAt(0) as FilterDescriptor; + return descriptor; + } + } + + // the value that is used for the custom filter + // populated with two-way binding of the custom filter component + public decimal? UnitPrice + { + get => (decimal?)(UnitPriceFilterDescriptor.Value); + set => UnitPriceFilterDescriptor.Value = (decimal?)value; + } + + // filter operator field - two-way binding with the custom filter component + FilterOperator SelectedFilterOperator + { + get => (FilterOperator)(UnitPriceFilterDescriptor.Operator); + set => UnitPriceFilterDescriptor.Operator = value; + } + + // the custom list of filter operators - we can change the available ones, the default one and their text as needed + List FilterOperatorsList { get; set; } = new List + { + new FilterOperatorDdlModel { Text = "- LESS THAN -", Value = FilterOperator.IsLessThan }, + new FilterOperatorDdlModel { Text = "- EQUALS -", Value = FilterOperator.IsEqualTo}, + new FilterOperatorDdlModel { Text = "- GREATER THAN -", Value = FilterOperator.IsGreaterThan } + }; + + // models for the data - the grid and the custom list of filter operators + + public class SampleData + { + public int Id { get; set; } + public decimal Price { get; set; } + } + + public class FilterOperatorDdlModel + { + public Telerik.DataSource.FilterOperator Value { get; set; } + public string Text { get; set; } + } +} +```` + +>caption The result from the snippet above after opening the filter menu + +![Custom filter menu template](images/filter-menu-template-basic.png) + + +## See Also + + * [Live Demo: Grid Custom Filter](https://demos.telerik.com/blazor-ui/grid/custom-filter) + diff --git a/components/grid/templates/images/filter-menu-template-basic.png b/components/grid/templates/images/filter-menu-template-basic.png new file mode 100644 index 0000000000000000000000000000000000000000..5d7cc974532b6e867b62548e0727fb7e4e03b1f4 GIT binary patch literal 13511 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 byAwagxL%n@Q=?YkML Date: Thu, 18 Jun 2020 20:09:34 +0300 Subject: [PATCH 4/6] docs(grid): filter menu template example 2 --- components/grid/templates/filter.md | 269 +++++++++++++++++- .../filter-menu-template-three-operators.png | Bin 0 -> 14428 bytes 2 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 components/grid/templates/images/filter-menu-template-three-operators.png diff --git a/components/grid/templates/filter.md b/components/grid/templates/filter.md index bbdc508cdc..1ddf17864c 100644 --- a/components/grid/templates/filter.md +++ b/components/grid/templates/filter.md @@ -21,7 +21,18 @@ There are two different templates you can use depending on the [Filter Mode]({%s ## Filter Menu -By default, the filter menu contains two filter values that are tied with a logical operator - OR or AND. The filter template for it (`` under the corresponding ``) provides you with the default composite filter in its `context`, and the `Filter` and `Clear` buttons below the template. +By default, the filter menu contains two filter values that are tied with a logical operator - OR or AND. The filter template for it (`` under the corresponding ``) provides you with the default composite filter in the `FilterDescriptor` field of its `context`, and the `Filter` and `Clear` buttons below the template. + +You can get started from the following examples: + + + +* [Basic Template - Single Filter Operator](#basic-template---single-filter-operator) +* [Add A Third Filter Operator](#add-a-third-filter-operator) + + + +### Basic Template - Single Filter Operator In the example below, you can see how to: @@ -32,7 +43,7 @@ In the example below, you can see how to: Comments in the code offer more insights into how all the features tie together. ->caption Customize Filter Menu operators and value area +>caption Customize Filter Menu operators and value area to use only one operator ````CSHTML @using Telerik.DataSource @@ -135,6 +146,260 @@ Comments in the code offer more insights into how all the features tie together. ![Custom filter menu template](images/filter-menu-template-basic.png) +### Add A Third Filter Operator + +In the example below, you can see how to: + +* mimic the default behavior (by implementing the default functionality) +* add a third operator (by adding another instance of the filter operator editor) +* provide custom filter operators lists and texts (through the data sources of the custom dropdowns) + +Comments in the code offer more insights into how all the features tie together. + +>caption Add a third filter operator + +````CSHTML +@using Telerik.DataSource + + + + + + @{ + UnitsInStockFilterMenuTemplateContext = context; + + var compositeFilterDescriptor = UnitsInStockFilterMenuTemplateContext.FilterDescriptor as CompositeFilterDescriptor; + + var descriptor1 = compositeFilterDescriptor.FilterDescriptors.ElementAtOrDefault(0) as FilterDescriptor; + + var descriptor3 = new FilterDescriptor() + { + Member = descriptor1.Member, + MemberType = descriptor1.MemberType, + }; + + UnitsInStockFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.Add(descriptor3); + } + + @* first filter logic *@ +
+ + +
+
+ +
+ + @* logical operator *@ +
+ + +
+ + @* second filter logic *@ +
+ + +
+
+ +
+ + @* third filter logic *@ +
+ + +
+
+ +
+
+
+ +
+
+ +@code { + public List GridData { get; set; } = Enumerable.Range(1, 50).Select(x => new SampleData { ProductId = x, UnitsInStock = x % 10 }).ToList(); + + // data sources for the custom filter dropdowns + public List FilterLogicalOperators { get; set; } + public List UnitsInStockFilterOperators { get; set; } + + // the filter template context that lets you customize its filter operators list + public FilterMenuTemplateContext UnitsInStockFilterMenuTemplateContext { get; set; } + + // get the filter descriptor list from the context + public CompositeFilterDescriptor UnitsInStockCompositeFilterDescriptor + { + get => UnitsInStockFilterMenuTemplateContext.FilterDescriptor; + } + + // custom filter operators- they use two-way binding with the customized components in the template + public FilterOperator UnitsInStockFilterOperator1 + { + get => UnitsInStockFilterDescriptor1.Operator; + set => UnitsInStockFilterDescriptor1.Operator = value; + } + + public FilterOperator UnitsInStockFilterOperator2 + { + get => UnitsInStockFilterDescriptor2.Operator; + set => UnitsInStockFilterDescriptor2.Operator = value; + } + + public FilterOperator UnitsInStockFilterOperator3 + { + get => UnitsInStockFilterDescriptor3.Operator; + set => UnitsInStockFilterDescriptor3.Operator = value; + } + + // custom filter values - they use two-way binding with the customized components in the template + public short? UnitsInStockFilterValue1 + { + get => (short?)(UnitsInStockFilterDescriptor1.Value); + set => UnitsInStockFilterDescriptor1.Value = (short?)value; + } + + public short? UnitsInStockFilterValue2 + { + get => (short?)(UnitsInStockFilterDescriptor2.Value); + set => UnitsInStockFilterDescriptor2.Value = (short?)value; + } + + public short? UnitsInStockFilterValue3 + { + get => (short?)(UnitsInStockFilterDescriptor3.Value); + set => UnitsInStockFilterDescriptor3.Value = (short?)value; + } + + // logical operator value + public FilterCompositionLogicalOperator UnitsInStockFilterLogicalOperator1 + { + get => UnitsInStockCompositeFilterDescriptor.LogicalOperator; + set => UnitsInStockCompositeFilterDescriptor.LogicalOperator = value; + } + + // shortcuts to get the filter descriptors + public FilterDescriptor UnitsInStockFilterDescriptor1 => GetUnitsInStockFilterDescriptor(0); + + public FilterDescriptor UnitsInStockFilterDescriptor2 => GetUnitsInStockFilterDescriptor(1); + + public FilterDescriptor UnitsInStockFilterDescriptor3 => GetUnitsInStockFilterDescriptor(2); + + public FilterDescriptor GetUnitsInStockFilterDescriptor(int index) + { + var unitsInStockFilter = UnitsInStockFilterMenuTemplateContext.FilterDescriptor; + var descriptor = unitsInStockFilter.FilterDescriptors.ElementAtOrDefault(index) as FilterDescriptor; + return descriptor; + } + + + // initialize data for the filter operators and logical operators lists + protected override async Task OnInitializedAsync() + { + // filter operators + UnitsInStockFilterOperators = GetNumericFilterOperators(); + // logical operators + FilterLogicalOperators = GetFilterLogicalOperators(); + } + + + + // model class for the custom dropdowns with the filter operators + public class FilterOperatorDescriptor + { + public string Text { get; set; } = "Is equal to"; + + public FilterOperator Operator { get; set; } = FilterOperator.IsEqualTo; + } + + // model class for the dropdowns with logical operators list + public class FilterLogicalOperatorDescriptor + { + public string Text { get; set; } + + public FilterCompositionLogicalOperator Operator { get; set; } + } + + // provide a list with the custom logical operators to the template + public List GetFilterLogicalOperators() + { + var data = new List(); + + data.Add(new FilterLogicalOperatorDescriptor() + { + Text = "- OR -", + Operator = FilterCompositionLogicalOperator.Or + }); + + data.Add(new FilterLogicalOperatorDescriptor() + { + Text = "- AND -", + Operator = FilterCompositionLogicalOperator.And + }); + + return data; + } + + // provide a list with the filter operators to the template + public List GetNumericFilterOperators() + { + var data = new List(); + + data.Add(new FilterOperatorDescriptor() + { + Text = "- DIFFERENT FROM -", + Operator = FilterOperator.IsNotEqualTo + }); + + data.Add(new FilterOperatorDescriptor() + { + Text = "- LESS THAN -", + Operator = FilterOperator.IsLessThan + }); + + data.Add(new FilterOperatorDescriptor() + { + Text = "- GREATER THAN -", + Operator = FilterOperator.IsGreaterThan + }); + + return data; + } + + // sample model for the grid + public class SampleData + { + public int ProductId { get; set; } + public int UnitsInStock { get; set; } + } +} +```` + +>caption The result from the code snippet above, after opening the filter menu and applying some filteres + +![Three filteres in the filter menu](images/filter-menu-template-three-operators.png) + + + ## See Also diff --git a/components/grid/templates/images/filter-menu-template-three-operators.png b/components/grid/templates/images/filter-menu-template-three-operators.png new file mode 100644 index 0000000000000000000000000000000000000000..83c6a65d2b190b20767586ce703727560bdf18fd GIT binary patch literal 14428 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 QE(lVV*N`iE_A2220Gsd(yZ`_I literal 0 HcmV?d00001 From f3e1829618d45f3771f94255301da423711f6180 Mon Sep 17 00:00:00 2001 From: Marin Bratanov Date: Thu, 18 Jun 2020 20:13:55 +0300 Subject: [PATCH 5/6] chore(grid): plumbing and links for filter tremplates --- components/grid/templates/filter.md | 17 ++++++++++++----- components/grid/templates/overview.md | 5 ++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/components/grid/templates/filter.md b/components/grid/templates/filter.md index 1ddf17864c..3f2bcf8665 100644 --- a/components/grid/templates/filter.md +++ b/components/grid/templates/filter.md @@ -15,9 +15,14 @@ The Filter Template lets you customize the appearance and logic of the built-in There are two different templates you can use depending on the [Filter Mode]({%slug components/grid/filtering%}) that you use: -* Filter Menu + + +* [Filter Menu](#filter-menu) + * [Basic Template - Single Filter Operator](#basic-template---single-filter-operator) + * [Add A Third Filter Operator](#add-a-third-filter-operator) +* [Filter Row](#filter-row) -* Filter Row + ## Filter Menu @@ -25,13 +30,10 @@ By default, the filter menu contains two filter values that are tied with a logi You can get started from the following examples: - - * [Basic Template - Single Filter Operator](#basic-template---single-filter-operator) * [Add A Third Filter Operator](#add-a-third-filter-operator) - ### Basic Template - Single Filter Operator In the example below, you can see how to: @@ -401,6 +403,11 @@ Comments in the code offer more insights into how all the features tie together. +## Filter Row + + + + ## See Also * [Live Demo: Grid Custom Filter](https://demos.telerik.com/blazor-ui/grid/custom-filter) diff --git a/components/grid/templates/overview.md b/components/grid/templates/overview.md index c743b5aae2..5a88d27a82 100644 --- a/components/grid/templates/overview.md +++ b/components/grid/templates/overview.md @@ -27,8 +27,11 @@ The Grid component can use templates for: * [group header]({%slug grid-templates-group-header%}) - the shared section that denotes each grid [group]({%slug components/grid/features/grouping%}). +* [filter]({%slug grid-templates-filter%}) - the content of the filter cell or filter menu where you can implement custom rendering and logic for the filters. -Like other Blazor content, they can receive a `context` argument that is the type of the model. To use templates, you must bind the grid to a named model. + + +Like other Blazor content, most of them can receive a `context` argument that is the type of the model. To use templates, you must bind the grid to a named model. The filter templates are the exception as they are not related to rows and models. You must make sure to provide valid HTML in the templates. From 902cb283cc23f8568bdeaaf3b2b678a81104458b Mon Sep 17 00:00:00 2001 From: Marin Bratanov Date: Sat, 20 Jun 2020 18:13:14 +0300 Subject: [PATCH 6/6] docs(grid): filter template docs --- components/grid/templates/filter.md | 503 +++++++----------- .../images/custom-filter-cell-min-max.png | Bin 0 -> 19968 bytes .../images/custom-filter-menu-checkboxes.png | Bin 0 -> 19061 bytes .../images/filter-menu-template-basic.png | Bin 13511 -> 0 bytes .../filter-menu-template-three-operators.png | Bin 14428 -> 0 bytes 5 files changed, 196 insertions(+), 307 deletions(-) create mode 100644 components/grid/templates/images/custom-filter-cell-min-max.png create mode 100644 components/grid/templates/images/custom-filter-menu-checkboxes.png delete mode 100644 components/grid/templates/images/filter-menu-template-basic.png delete mode 100644 components/grid/templates/images/filter-menu-template-three-operators.png diff --git a/components/grid/templates/filter.md b/components/grid/templates/filter.md index 3f2bcf8665..5b564a2ca9 100644 --- a/components/grid/templates/filter.md +++ b/components/grid/templates/filter.md @@ -13,402 +13,291 @@ position: 35 The Filter Template lets you customize the appearance and logic of the built-in filters. It lets you step on the built-in filtering logic of the grid and implement your own design and logic for setting their values. -There are two different templates you can use depending on the [Filter Mode]({%slug components/grid/filtering%}) that you use: +There are two different templates you can use depending on the [Filter Mode]({%slug components/grid/filtering%}) that you chose: - +* [Filter Row Template](#filter-row-template) +* [Filter Menu Template](#filter-menu-template) -* [Filter Menu](#filter-menu) - * [Basic Template - Single Filter Operator](#basic-template---single-filter-operator) - * [Add A Third Filter Operator](#add-a-third-filter-operator) -* [Filter Row](#filter-row) - +## Filter Row Template -## Filter Menu +By default, the filter row puts an appropriate editor (like a numeric textbox for numbers) and its `ValueChanged` handler triggers grid filtering on every keystroke. There is also a button for the user to choose a filter operator, and a clear filter button when there is a value in the editor. -By default, the filter menu contains two filter values that are tied with a logical operator - OR or AND. The filter template for it (`` under the corresponding ``) provides you with the default composite filter in the `FilterDescriptor` field of its `context`, and the `Filter` and `Clear` buttons below the template. +To customize the filter cell, use the `` tag of the ``. It receives a `context` of type `FilterCellTemplateContext` that provides the following members: -You can get started from the following examples: +* `FilterDescriptor` - the object that describes the column filter. By default it has a first filter with the type and name of the field, and you can add more to its `FilterDescriptors` collection, or change its `LogicalOperator` from the default `AND`. -* [Basic Template - Single Filter Operator](#basic-template---single-filter-operator) -* [Add A Third Filter Operator](#add-a-third-filter-operator) +* `FilterAsync()` - an `async` method that invokes the built-in grid filtering logic (including a handler to [`OnRead`]({%slug components/grid/manual-operations%}) if you use one) so you can call upon it easily from your template (e.g., when a value changes or a button is clicked). +* `ClearFilterAsync()` - an `async` method that invokes the built-in grid clear filtering logic (including a handler to [`OnRead`]({%slug components/grid/manual-operations%}) if you use one) so you can call upon it easily from your template (e.g., when a value is cleared or a button is clicked). -### Basic Template - Single Filter Operator +You can store a reference to each column's context in a field in the view-model, so you can write the handlers in the standard C# code, instead of using lambdas in the markup. You can also pass the context as a Parameter to your own separate filter component to reduce clutter in the main grid markup and code. -In the example below, you can see how to: +### Examples -* Keep only one input (declare only one, and clear the subsequent filter from the composite filter the grid provides). -* Customize the user input experience (set some properties to the numeric textbox or the corresponding editor you use). -* Choose the desired filter operators while using custom text for them (a dropdown list with the desired data source). -* Change the size of the filter popup (defining your own layout with desired size and styles) - which is not mandatory. +The example below shows a custom filter that: -Comments in the code offer more insights into how all the features tie together. +* Implements a min-max filter in the filter cell through two numeric textboxes. +* Filters in the `OnChange` event (only when the user presses Enter or blurs the input) to reduce database calls. +* Shows how you can store a reference to the context or use it inline in the template. +* Showcases building a filter descriptor with two filters and sample logic that always filters the data even if one of the inputs is empty. ->caption Customize Filter Menu operators and value area to use only one operator +You can find more examples in the [Live Demo: Custom Filter Row](https://demos.telerik.com/blazor-ui/grid/custom-filter-row) that is available in your local installation under the `demos` folder. + + +>caption Custom Filter Row Template - Min and Max filters on OnChange ````CSHTML @using Telerik.DataSource - +The custom filter textboxes invoke filtering on Enter or blur through the OnChange event + + - - + + + + @{ - // we step on the built-in filter descriptor of the grid - // and reuse it to populate it from the custom filter input - // the built-in Filter and Clear buttons of the grid remain available - // and in this case we ensure only one filter is used, and customize the way - // filter operators and values are provided to the grid filtering - UnitPriceFilterMenuTemplateContext = context; - - // leave only one filter descriptor (there are two by default) - var descriptor1 = UnitPriceFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.ElementAtOrDefault(0); - UnitPriceFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.Clear(); - UnitPriceFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.Add(descriptor1); + // we store a reference to the filter context to use in the business logic + // you can also use it inline in the template, like with the Clear button below + theFilterContext = context; } - @* you can customize the appearance and size of the template area *@ -
-
- - -
- -
- -
-
-
+ + + + + + + + +
- + + @code { - // sample data for the grid - List GridData { get; set; } = Enumerable.Range(1, 50).Select(x => new SampleData { Id = x, Price = x * 0.5m }).ToList(); - - // stores the default filter context with the default column filter that the Grid has - // this lets you manipulate it and reuse it according to your logic - public FilterMenuTemplateContext UnitPriceFilterMenuTemplateContext { get; set; } + FilterCellTemplateContext theFilterContext { get; set; } + public decimal? MinValue { get; set; } + public decimal? MaxValue { get; set; } - // this references the first built-in filter descriptor so you can easily - // populate its value from the custom filter component - a numeric textbox in this sample - public FilterDescriptor UnitPriceFilterDescriptor + async Task SetupFilterRule() { - get + // set up min value filter - there is one default filter descriptor + // that alredy has the field set up, so we use that for the MIN filter + // and set up a value and operator + var filter1 = theFilterContext.FilterDescriptor.FilterDescriptors[0] as FilterDescriptor; + filter1.Value = MinValue == null ? int.MinValue : MinValue; + filter1.Operator = FilterOperator.IsGreaterThan; + + // set up max value filter - we may have to crete a new filter descriptor + // if there wasn't one already so we prepare it first and check whether we have the second filter + var filter2Val = MaxValue == null ? int.MaxValue : MaxValue; + var filter2 = new FilterDescriptor("Price", FilterOperator.IsLessThan, filter2Val); + filter2.MemberType = typeof(decimal); + + if (theFilterContext.FilterDescriptor.FilterDescriptors.Count > 1) { - var descriptor = UnitPriceFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.ElementAt(0) as FilterDescriptor; - return descriptor; + theFilterContext.FilterDescriptor.FilterDescriptors[1] = filter2; + } + else + { + theFilterContext.FilterDescriptor.FilterDescriptors.Add(filter2); } - } - // the value that is used for the custom filter - // populated with two-way binding of the custom filter component - public decimal? UnitPrice - { - get => (decimal?)(UnitPriceFilterDescriptor.Value); - set => UnitPriceFilterDescriptor.Value = (decimal?)value; - } + // ensure logical operator between the two filters is AND (it is the default, but we showcase the option) + theFilterContext.FilterDescriptor.LogicalOperator = FilterCompositionLogicalOperator.And; - // filter operator field - two-way binding with the custom filter component - FilterOperator SelectedFilterOperator - { - get => (FilterOperator)(UnitPriceFilterDescriptor.Operator); - set => UnitPriceFilterDescriptor.Operator = value; + // invoke filtering through the method the context provides + await theFilterContext.FilterAsync(); } - // the custom list of filter operators - we can change the available ones, the default one and their text as needed - List FilterOperatorsList { get; set; } = new List - { - new FilterOperatorDdlModel { Text = "- LESS THAN -", Value = FilterOperator.IsLessThan }, - new FilterOperatorDdlModel { Text = "- EQUALS -", Value = FilterOperator.IsEqualTo}, - new FilterOperatorDdlModel { Text = "- GREATER THAN -", Value = FilterOperator.IsGreaterThan } - }; - // models for the data - the grid and the custom list of filter operators + // sample grid data + + public List GridData { get; set; } = Enumerable.Range(1, 50).Select(x => new SampleData + { + Id = x, + Price = x * 0.5m, + ProductName = $"Product {x}" + }).ToList(); public class SampleData { public int Id { get; set; } public decimal Price { get; set; } + public string ProductName { get; set; } } +} - public class FilterOperatorDdlModel - { - public Telerik.DataSource.FilterOperator Value { get; set; } - public string Text { get; set; } +@* sample CSS rule to align the custom label elements in the filter cell *@ + ```` ->caption The result from the snippet above after opening the filter menu +>caption The result from the code snippet above after filtering -![Custom filter menu template](images/filter-menu-template-basic.png) +![Custom Filter Cell Template - Min and Max](images/custom-filter-cell-min-max.png) -### Add A Third Filter Operator -In the example below, you can see how to: +## Filter Menu Template -* mimic the default behavior (by implementing the default functionality) -* add a third operator (by adding another instance of the filter operator editor) -* provide custom filter operators lists and texts (through the data sources of the custom dropdowns) +By default, the filter menu contains two filter values that are tied with a logical operator - OR or AND, with filgering being triggered through a dedicated Filter button and a Clear button removes the filter. -Comments in the code offer more insights into how all the features tie together. +To customize the filter menu, use the `` tag of the ``. The `Filter` and `Clear` buttons are still available below the template. ->caption Add a third filter operator +The template receives a `context` of type `FilterMenuTemplateContext` that provides the following members: -````CSHTML -@using Telerik.DataSource +* `FilterDescriptor` - the object that describes the column filter. By default it has two filters with the type and name of the field, and you can add more to its `FilterDescriptors` collection, or change its `LogicalOperator` from the default `AND`. - - - - - @{ - UnitsInStockFilterMenuTemplateContext = context; - - var compositeFilterDescriptor = UnitsInStockFilterMenuTemplateContext.FilterDescriptor as CompositeFilterDescriptor; +You can store a reference to each column's context in a field in the view-model, so you can reference it from event handlers in the standard C# code, instead of passing it as a nargument to lambdas in the markup only. You can also pass the context as a Parameter to your own separate filter component to reduce clutter in the main grid markup and code. - var descriptor1 = compositeFilterDescriptor.FilterDescriptors.ElementAtOrDefault(0) as FilterDescriptor; - - var descriptor3 = new FilterDescriptor() - { - Member = descriptor1.Member, - MemberType = descriptor1.MemberType, - }; - - UnitsInStockFilterMenuTemplateContext.FilterDescriptor.FilterDescriptors.Add(descriptor3); - } +### Examples - @* first filter logic *@ -
- - -
-
- -
- - @* logical operator *@ -
- - -
- - @* second filter logic *@ -
- - -
-
- -
- - @* third filter logic *@ -
- - -
-
- -
-
-
- -
-
+The example below shows a custom filter that: -@code { - public List GridData { get; set; } = Enumerable.Range(1, 50).Select(x => new SampleData { ProductId = x, UnitsInStock = x % 10 }).ToList(); +* Implements a multi checkbox filter that lets the user choose several values from the data source. +* Shows how you can store a reference to the context or use it inline in the template. +* Showcases building multiple filter descriptors for each value the user chooses. - // data sources for the custom filter dropdowns - public List FilterLogicalOperators { get; set; } - public List UnitsInStockFilterOperators { get; set; } +You can find more examples in the [Live Demo: Custom Filter Menu](https://demos.telerik.com/blazor-ui/grid/custom-filter-menu) that is available in your local installation under the `demos` folder. - // the filter template context that lets you customize its filter operators list - public FilterMenuTemplateContext UnitsInStockFilterMenuTemplateContext { get; set; } - // get the filter descriptor list from the context - public CompositeFilterDescriptor UnitsInStockCompositeFilterDescriptor - { - get => UnitsInStockFilterMenuTemplateContext.FilterDescriptor; - } +>caption Custom Filter Menu Template - Multiple Checkboxes - // custom filter operators- they use two-way binding with the customized components in the template - public FilterOperator UnitsInStockFilterOperator1 - { - get => UnitsInStockFilterDescriptor1.Operator; - set => UnitsInStockFilterDescriptor1.Operator = value; - } - - public FilterOperator UnitsInStockFilterOperator2 - { - get => UnitsInStockFilterDescriptor2.Operator; - set => UnitsInStockFilterDescriptor2.Operator = value; - } - - public FilterOperator UnitsInStockFilterOperator3 - { - get => UnitsInStockFilterDescriptor3.Operator; - set => UnitsInStockFilterDescriptor3.Operator = value; - } - - // custom filter values - they use two-way binding with the customized components in the template - public short? UnitsInStockFilterValue1 - { - get => (short?)(UnitsInStockFilterDescriptor1.Value); - set => UnitsInStockFilterDescriptor1.Value = (short?)value; - } - - public short? UnitsInStockFilterValue2 - { - get => (short?)(UnitsInStockFilterDescriptor2.Value); - set => UnitsInStockFilterDescriptor2.Value = (short?)value; - } - - public short? UnitsInStockFilterValue3 - { - get => (short?)(UnitsInStockFilterDescriptor3.Value); - set => UnitsInStockFilterDescriptor3.Value = (short?)value; - } - - // logical operator value - public FilterCompositionLogicalOperator UnitsInStockFilterLogicalOperator1 - { - get => UnitsInStockCompositeFilterDescriptor.LogicalOperator; - set => UnitsInStockCompositeFilterDescriptor.LogicalOperator = value; - } - - // shortcuts to get the filter descriptors - public FilterDescriptor UnitsInStockFilterDescriptor1 => GetUnitsInStockFilterDescriptor(0); - - public FilterDescriptor UnitsInStockFilterDescriptor2 => GetUnitsInStockFilterDescriptor(1); - - public FilterDescriptor UnitsInStockFilterDescriptor3 => GetUnitsInStockFilterDescriptor(2); - - public FilterDescriptor GetUnitsInStockFilterDescriptor(int index) - { - var unitsInStockFilter = UnitsInStockFilterMenuTemplateContext.FilterDescriptor; - var descriptor = unitsInStockFilter.FilterDescriptors.ElementAtOrDefault(index) as FilterDescriptor; - return descriptor; - } - - - // initialize data for the filter operators and logical operators lists - protected override async Task OnInitializedAsync() - { - // filter operators - UnitsInStockFilterOperators = GetNumericFilterOperators(); - // logical operators - FilterLogicalOperators = GetFilterLogicalOperators(); - } +````CSHTML +@using Telerik.DataSource +This custom filter menu lets you choose more than one option to match against the data source + + + - // model class for the custom dropdowns with the filter operators - public class FilterOperatorDescriptor - { - public string Text { get; set; } = "Is equal to"; + + + @{ + // we store a reference to the filter context to use in the business logic to show we can + // we could, alternatively pass it as an argument to the event handler in the lambda expression + // which can be useful if you want to use the same filter for several columns + // you could then pass more arguments to the business logic such as field name and so on + theFilterContext = context; + } - public FilterOperator Operator { get; set; } = FilterOperator.IsEqualTo; - } + @foreach (var size in Sizes) + { +
+ + + +
+ } +
+
- // model class for the dropdowns with logical operators list - public class FilterLogicalOperatorDescriptor - { - public string Text { get; set; } + +
+
- public FilterCompositionLogicalOperator Operator { get; set; } - } +@code { + FilterMenuTemplateContext theFilterContext { get; set; } + public List CheckedSizes { get; set; } = new List(); - // provide a list with the custom logical operators to the template - public List GetFilterLogicalOperators() + public void UpdateCheckedSizes(bool value, string itemValue) { - var data = new List(); - - data.Add(new FilterLogicalOperatorDescriptor() + // update the list of items we want to filter by + var isSizeChecked = CheckedSizes.Contains(itemValue); + if (value && !isSizeChecked) { - Text = "- OR -", - Operator = FilterCompositionLogicalOperator.Or - }); + CheckedSizes.Add(itemValue); + } - data.Add(new FilterLogicalOperatorDescriptor() + if (!value && isSizeChecked) { - Text = "- AND -", - Operator = FilterCompositionLogicalOperator.And - }); + CheckedSizes.Remove(itemValue); + } - return data; - } + // prepare filter descriptor + var filterDescriptor = theFilterContext.FilterDescriptor; - // provide a list with the filter operators to the template - public List GetNumericFilterOperators() - { - var data = new List(); + filterDescriptor.FilterDescriptors.Clear(); + // use the OR logical operator so we include all possible values + filterDescriptor.LogicalOperator = FilterCompositionLogicalOperator.Or; + CheckedSizes.ForEach(s => + // instantiate a filter descriptor for the desired field, and with the desired operator and value + filterDescriptor.FilterDescriptors.Add(new FilterDescriptor("Size", FilterOperator.IsEqualTo, s)) + ); - data.Add(new FilterOperatorDescriptor() + //ensure there is at least one blank filter to avoid null reference exceptions + if (!filterDescriptor.FilterDescriptors.Any()) { - Text = "- DIFFERENT FROM -", - Operator = FilterOperator.IsNotEqualTo - }); + filterDescriptor.FilterDescriptors.Add(new FilterDescriptor()); + } + } - data.Add(new FilterOperatorDescriptor() - { - Text = "- LESS THAN -", - Operator = FilterOperator.IsLessThan - }); + // sample grid data - data.Add(new FilterOperatorDescriptor() - { - Text = "- GREATER THAN -", - Operator = FilterOperator.IsGreaterThan - }); + public List GridData { get; set; } - return data; + protected override void OnInitialized() + { + GridData = Enumerable.Range(1, 70).Select(x => new SampleData + { + Id = x, + Size = Sizes[x % Sizes.Length], + ProductName = $"Product {x}" + }).ToList(); + base.OnInitialized(); } - // sample model for the grid public class SampleData { - public int ProductId { get; set; } - public int UnitsInStock { get; set; } + public int Id { get; set; } + public string Size { get; set; } + public string ProductName { get; set; } } + + public string[] Sizes = new string[] { "XS", "S", "M", "L", "XL" }; } ```` ->caption The result from the code snippet above, after opening the filter menu and applying some filteres - -![Three filteres in the filter menu](images/filter-menu-template-three-operators.png) - - - - -## Filter Row - +>caption The result from the code snippet above, after filtering +![Custom Filter Menu Template with Checkboxes](images/custom-filter-menu-checkboxes.png) ## See Also - * [Live Demo: Grid Custom Filter](https://demos.telerik.com/blazor-ui/grid/custom-filter) + * [Live Demo: Grid Custom Filter Row](https://demos.telerik.com/blazor-ui/grid/custom-filter-row) + * [Live Demo: Grid Custom Filter Menu](https://demos.telerik.com/blazor-ui/grid/custom-filter-menu) diff --git a/components/grid/templates/images/custom-filter-cell-min-max.png b/components/grid/templates/images/custom-filter-cell-min-max.png new file mode 100644 index 0000000000000000000000000000000000000000..f5136d29e1f2762db4429aa04f43d0f29f8c2e55 GIT binary patch literal 19968 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 XlJ2;MiJ2d?`k%qm)z4*}Q$iB}nam(9 literal 0 HcmV?d00001 diff --git a/components/grid/templates/images/filter-menu-template-basic.png b/components/grid/templates/images/filter-menu-template-basic.png deleted file mode 100644 index 5d7cc974532b6e867b62548e0727fb7e4e03b1f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13511 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 QE(lVV*N`iE_A2220Gsd(yZ`_I