@@ -27,7 +27,8 @@ With the `FormTemplate` feature, you can customize the appearance and content of
2727## Specifics
2828
2929When using the template, the default Popup form is replaced by the declared content within the ` FormTemplate ` tag. This introduces the following specifics:
30- * The default ** Update** and ** Cancel** buttons are removed. This means that the [ ` OnUpdate ` and ` OnCancel ` ] ( slug:grid-editing-overview#events ) events cannot be triggered. To modify or cancel the update of a record, you need to include custom controls to manage these actions.
30+
31+ * The default ** Update** and ** Cancel** buttons are removed. This means that the [ ` OnUpdate ` and ` OnCancel ` ] ( slug:grid-editing-overview#events ) events do not fire. To modify or cancel the update of a record, you need to include custom components to manage these actions.
3132* The popup footer remains empty by design. You can [ either hide it or place your custom buttons in it] ( slug:grid-kb-handle-empty-popup-footer ) .
3233* The ` FormTemplate ` disables the [ built-in validation] ( slug:grid-editing-validation ) of the Grid. Implement a [ Form Validation] ( slug:form-validation ) instead.
3334* The [ ` <GridPopupEditFormSettings> ` parameters] ( slug:grid-editing-popup#form-layout ) do not apply to a custom ` TelerikForm ` that you may render inside the ` <FormTemplate> ` tag. Set the desired Form configurations such as ` Columns ` , ` Orientation ` , and more on the [ Form component] ( slug:form-overview#form-parameters ) .
@@ -37,200 +38,238 @@ When using the template, the default Popup form is replaced by the declared cont
3738Using a ` FormTemplate ` to modify the Edit/Create Popup window.
3839
3940```` RAZOR
40- @using System.Collections.Generic;
41+ @using System.ComponentModel.DataAnnotations
4142@using Telerik.DataSource
4243@using Telerik.DataSource.Extensions
4344
4445<TelerikGrid @ref="@GridRef"
45- Data="@GridData"
46+ OnRead="@OnGridRead"
47+ TItem="@Product"
4648 EditMode="@GridEditMode.Popup"
47- Pageable="true"
48- Width="950px"
49- PageSize="5"
50- OnDelete="@DeleteItem">
49+ OnDelete="@OnGridDelete">
5150 <GridToolBarTemplate>
52- <GridCommandButton Command="Add" Icon="@SvgIcon.Plus" >Add Employee </GridCommandButton>
51+ <GridCommandButton Command="Add">Add Item </GridCommandButton>
5352 </GridToolBarTemplate>
5453 <GridSettings>
5554 <GridPopupEditSettings Width="550px" MaxHeight="95vh" MaxWidth="95vw"></GridPopupEditSettings>
56- <GridPopupEditFormSettings Context="FormContext ">
55+ <GridPopupEditFormSettings Context="formContext ">
5756 <FormTemplate>
5857 @{
59- EditItem = FormContext.Item as Person;
60-
61- <TelerikForm Model="@EditItem"
58+ if (GridEditItem is null)
59+ {
60+ // Setting GridEditItem unconditionally may
61+ // reset the modified and unsaved values after re-render.
62+ // Nullify GridEditItem when editing completes.
63+ GridEditItem = (Product)formContext.Item;
64+ }
65+
66+ <TelerikForm Model="@GridEditItem"
6267 ColumnSpacing="20px"
6368 Columns="2"
6469 ButtonsLayout="@FormButtonsLayout.Stretch"
65- OnValidSubmit="@OnValidSubmit ">
70+ OnValidSubmit="@OnFormValidSubmit ">
6671 <FormItems>
67- <FormItem Field="EmployeeId" Enabled="false"></FormItem>
68- <FormItem Field="Name">
69- </FormItem>
70- <FormItem Field="HireDate" LabelText="Custom Hire Date Label"></FormItem>
71- <FormItem>
72+ <FormItem Field="@nameof(Product.Id)" Enabled="false" />
73+ <FormItem Field="@nameof(Product.Name)" />
74+ <FormItem Field="@nameof(Product.Description)"
75+ ColSpan="2"
76+ EditorType="@FormEditorType.TextArea" />
77+ <FormItem Field="@nameof(Product.Price)">
7278 <Template>
73- <label for="position">Custom Position Label</label>
74- <TelerikDropDownList Data="@PositionsData"
75- @bind-Value="@EditItem.Position"
76- Id="position">
77- </TelerikDropDownList>
79+ <label class="k-label k-form-label">Price</label>
80+ <div class="k-form-field-wrap">
81+ <TelerikNumericTextBox @bind-Value="@GridEditItem.Price"
82+ DebounceDelay="0" />
83+ <TelerikValidationMessage For="@( () => GridEditItem.Price)" />
84+ </div>
7885 </Template>
7986 </FormItem>
80- </FormItems>
81- <FormButtons>
82- <TelerikButton Icon="@nameof(SvgIcon.Save)">Save</TelerikButton>
83- <TelerikButton Icon="@nameof(SvgIcon.Cancel)" ButtonType="@ButtonType.Button" OnClick="@OnCancel">Cancel</TelerikButton>
84- </FormButtons>
85- </TelerikForm>
87+ <FormItem Field="@nameof(Product.Quantity)" />
88+ <FormItem Field="@nameof(Product.ReleaseDate)" />
89+ <FormItem Field="@nameof(Product.Discontinued)" />
90+ </FormItems>
91+ <FormButtons>
92+ <TelerikButton Icon="@nameof(SvgIcon.Save)">Save</TelerikButton>
93+ <TelerikButton Icon="@nameof(SvgIcon.Cancel)"
94+ ButtonType="@ButtonType.Button"
95+ OnClick="@ExitGridEditMode">Cancel</TelerikButton>
96+ </FormButtons>
97+ </TelerikForm>
8698 }
8799 </FormTemplate>
88100 </GridPopupEditFormSettings>
89101 </GridSettings>
90102 <GridColumns>
91- <GridColumn Field=@nameof(Person.EmployeeId) Editable="false" />
92- <GridColumn Field=@nameof(Person.Name) />
93- <GridColumn Field=@nameof(Person.HireDate) Title="Hire Date" />
94- <GridColumn Field=@nameof(Person.Position) Title="Position" />
95- <GridCommandColumn>
96- <GridCommandButton Command="Edit" Icon="@SvgIcon.Pencil">Edit</GridCommandButton>
97- <GridCommandButton Command="Delete" Icon="@SvgIcon.Trash">Delete</GridCommandButton>
103+ <GridColumn Field="@nameof(Product.Name)" />
104+ <GridColumn Field="@nameof(Product.Price)" DisplayFormat="{0:C2}" />
105+ <GridColumn Field="@nameof(Product.Quantity)" DisplayFormat="{0:N0}" />
106+ <GridColumn Field="@nameof(Product.ReleaseDate)" DisplayFormat="{0:d}" />
107+ <GridColumn Field="@nameof(Product.Discontinued)" Width="120px" />
108+ <GridCommandColumn Width="180px">
109+ <GridCommandButton Command="Edit">Edit</GridCommandButton>
110+ <GridCommandButton Command="Delete">Delete</GridCommandButton>
98111 </GridCommandColumn>
99112 </GridColumns>
100113</TelerikGrid>
101114
102115@code {
103- private List<string> PositionsData { get; set; } = new List<string>()
104- {
105- "Manager", "Developer", "QA"
106- };
116+ private ProductService GridProductService { get; set; } = new();
107117
108- private TelerikGrid<Person> GridRef { get; set; }
109- private List<Person> GridData { get; set; }
110- private Person EditItem { get; set; }
111- private List<Person> _people;
118+ private TelerikGrid<Product>? GridRef { get; set; }
112119
113- public class Person
114- {
115- public int EmployeeId { get; set; }
116- public string Name { get; set; }
117- public DateTime HireDate { get; set; }
118- public string Position { get; set; }
119- }
120+ private Product? GridEditItem { get; set; }
120121
121- public List<Person> People
122+ private async Task OnFormValidSubmit()
122123 {
123- get
124+ if (GridEditItem is null)
124125 {
125- if (_people == null)
126- {
127- _people = GeneratePeople(30);
128- }
126+ return;
127+ }
129128
130- return _people;
129+ if (GridEditItem.Id != default)
130+ {
131+ await GridProductService.Update(GridEditItem);
132+ }
133+ else
134+ {
135+ await GridProductService.Create(GridEditItem);
131136 }
137+
138+ await ExitGridEditMode();
132139 }
133140
134- protected override void OnInitialized ()
141+ private async Task ExitGridEditMode ()
135142 {
136- LoadData();
143+ if (GridRef is null)
144+ {
145+ return;
146+ }
147+
148+ var state = GridRef.GetState();
149+ state.OriginalEditItem = null!;
150+ state.EditItem = null!;
151+ state.InsertedItem = null!;
152+
153+ await GridRef.SetStateAsync(state);
154+
155+ GridEditItem = default;
137156 }
138157
139- private void LoadData( )
158+ private async Task OnGridDelete(GridCommandEventArgs args )
140159 {
141- GridData = GetPeople();
160+ var deletedItem = (Product)args.Item;
161+
162+ await GridProductService.Delete(deletedItem);
142163 }
143164
144- private void DeleteItem(GridCommandEventArgs args)
165+ private async Task OnGridRead(GridReadEventArgs args)
145166 {
146- DeletePerson (args.Item as Person );
167+ DataSourceResult result = await GridProductService.Read (args.Request );
147168
148- LoadData();
169+ args.Data = result.Data;
170+ args.Total = result.Total;
171+ args.AggregateResults = result.AggregateResults;
149172 }
150173
151- private async Task OnValidSubmit()
174+ public class Product
152175 {
176+ public int Id { get; set; }
177+ [Required]
178+ public string Name { get; set; } = string.Empty;
179+ public string Description { get; set; } = string.Empty;
180+ public decimal? Price { get; set; }
181+ public int Quantity { get; set; }
182+ [Required]
183+ public DateTime? ReleaseDate { get; set; }
184+ public bool Discontinued { get; set; }
185+ }
153186
154- if (EditItem.EmployeeId != default)
155- {
156- UpdatePerson(EditItem);
157- }
158- else
187+ #region Data Service
188+
189+ public class ProductService
190+ {
191+ private List<Product> Items { get; set; } = new();
192+
193+ private int LastId { get; set; }
194+
195+ public async Task<int> Create(Product product)
159196 {
160- CreatePerson(EditItem);
161- }
197+ await SimulateAsyncOperation();
162198
163- await ExitEditAsync() ;
199+ product.Id = ++LastId ;
164200
165- LoadData();
166- }
201+ Items.Insert(0, product);
167202
168- private async Task OnCancel()
169- {
170- await ExitEditAsync();
171- }
203+ return LastId;
204+ }
172205
173- private async Task ExitEditAsync()
174- {
175- var state = GridRef?.GetState();
176- state.OriginalEditItem = null;
177- state.EditItem = null;
178- state.InsertedItem = null;
206+ public async Task<bool> Delete(Product product)
207+ {
208+ await SimulateAsyncOperation();
179209
180- await GridRef?.SetStateAsync(state);
181- }
210+ if (Items.Contains(product))
211+ {
212+ Items.Remove(product);
182213
183- #region Service Methods
184- private List<Person> GetPeople()
185- {
186- return People;
187- }
214+ return true;
215+ }
188216
189- private DataSourceResult GetPeople(DataSourceRequest request)
190- {
191- return People.ToDataSourceResult(request);
192- }
217+ return false;
218+ }
193219
194- private void DeletePerson(Person person)
195- {
196- People.Remove(person);
197- }
220+ public async Task<List<Product>> Read()
221+ {
222+ await SimulateAsyncOperation();
198223
199- private void UpdatePerson(Person person)
200- {
201- var index = People.FindIndex(i => i.EmployeeId == person.EmployeeId);
202- if (index != -1 )
224+ return Items;
225+ }
226+
227+ public async Task<DataSourceResult> Read(DataSourceRequest request )
203228 {
204- People[index] = person ;
229+ return await Items.ToDataSourceResultAsync(request) ;
205230 }
206- }
207231
208- private void CreatePerson(Person person )
209- {
210- person.EmployeeId = People.Max(x => x.EmployeeId) + 1 ;
232+ public async Task<bool> Update(Product product )
233+ {
234+ await SimulateAsyncOperation() ;
211235
212- People.Insert(0, person);
213- }
236+ int originalItemIndex = Items.FindIndex(x => x.Id == product.Id);
214237
215- private List<Person> GeneratePeople(int count, int startIndex = 0)
216- {
217- List<Person> result = new List<Person>();
238+ if (originalItemIndex != -1)
239+ {
240+ Items[originalItemIndex] = product;
241+ return true;
242+ }
243+
244+ return false;
245+ }
218246
219- for (int i = startIndex; i < startIndex + count; i++ )
247+ private async Task SimulateAsyncOperation( )
220248 {
221- result.Add(new Person()
222- {
223- EmployeeId = i,
224- Name = "Employee " + i.ToString(),
225- HireDate = new DateTime(2020, 6, 1).Date.AddDays(count - (i % 7)),
226- Position = i % 3 <= 2 ? PositionsData[i % 3] : PositionsData.FirstOrDefault()
249+ await Task.Delay(100);
250+ }
251+
252+ public ProductService(int itemCount = 5)
253+ {
254+ Random rnd = Random.Shared;
227255
256+ for (int i = 1; i <= itemCount; i++)
257+ {
258+ Items.Add(new Product()
259+ {
260+ Id = ++LastId,
261+ Name = $"Product {LastId}",
262+ Description = $"Multi-line\ndescription {LastId}",
263+ Price = LastId % 2 == 0 ? null : rnd.Next(0, 100) * 1.23m,
264+ Quantity = LastId % 2 == 0 ? 0 : rnd.Next(0, 3000),
265+ ReleaseDate = DateTime.Today.AddDays(-rnd.Next(365, 3650)),
266+ Discontinued = LastId % 2 == 0
228267 });
268+ }
229269 }
230-
231- return result;
232270 }
233- #endregion
271+
272+ #endregion Data Service
234273}
235274````
236275
0 commit comments