GridBlazor supports CRUD forms to add, edit, view and delete items for Blazor client-side projects.
These are the supported features:
You can enable CRUD using the ODataCrud(bool enabled) method of the GridODataClient object:
var client = new GridODataClient<Order>(HttpClient, url, query, false, "ordersGrid",
c => columns(c, NavigationManager.BaseUri), 10, locale, new List<string> { "Employee", "Shipper" })
.ODataCrud(true)
You can also enable CRUD depending on a condition for each row using the ODataCrud(bool createEnabled, Func<T, bool> enabled) method:
var client = new GridODataClient<Order>(HttpClient, url, query, false, "ordersGrid",
c => columns(c, NavigationManager.BaseUri), 10, locale, new List<string> { "Employee", "Shipper" })
.ODataCrud(true, r => r.Customer.IsVip)
The create form can only be enabled using a bool
parameter. But the read, update and delete forms can be enabled using a function that returns a bool
.
Note: All 4 crud forms can be enabled at the same time with the former methods, but you can enable one by one using ODataCrud(bool create, bool read, bool update, bool delete)
or ODataCrud(bool createEnabled, Func<T, bool> readEnabled, Func<T, bool> updateEnabled, Func<T, bool> deleteEnabled)
methods.
You must create actions in the ODataController
for all 4 CRUD operations. This is an example of controller including those 4 actions:
public class OrdersController : ODataController
{
...
[EnableQuery]
public async Task<IActionResult> Get(int key)
{
var repository = new OrdersRepository(_context);
Order order = await repository.GetById(key);
return Ok(order);
}
public async Task<IActionResult> Post([FromBody]Order order)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (order == null)
{
return BadRequest();
}
var repository = new OrdersRepository(_context);
try
{
await repository.Insert(order);
repository.Save();
return Created(order);
}
catch (Exception e)
{
return BadRequest(new
{
message = e.Message.Replace('{', '(').Replace('}', ')')
});
}
}
public async Task<IActionResult> Put([FromODataUri]int key, [FromBody] Order order)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != order.OrderID)
{
return BadRequest();
}
var repository = new OrdersRepository(_context);
await repository.Update(order);
try
{
repository.Save();
}
catch (DbUpdateConcurrencyException)
{
if (!OrderExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(order);
}
public async Task<ActionResult> Delete([FromODataUri] int key)
{
var repository = new OrdersRepository(_context);
Order order = await repository.GetById(key);
if (order == null)
{
return NotFound();
}
repository.Delete(order);
repository.Save();
return StatusCode((int)HttpStatusCode.NoContent);
}
private bool OrderExists(int key)
{
var repository = new OrdersRepository(_context);
return repository.GetAll().Any(x => x.OrderID == key);
}
...
}
The column definition must include the primary keys:
If the grid model includes foreign keys, the column definition should include them using the SetSelectField in order to get the options for the <select>
element.
The SetSelectField method has 3 required parameters:
Parameter | Description |
---|---|
enabled | boolean to configure if the field is shown as a <select> html element |
expression | function to get the selected value for update and delete forms (it must return an string value) |
selectItemExprAsync | async function to get the values and titles to be shown in the drop-down of create and update forms (it must return an Task<IEnumerable<SelectItem>> ) |
The type of fields currently supported as foreign keys are:
This is an example of function to get values and title for a drop-down:
Func<string, Task<IEnumerable<SelectItem>>> GetAllEmployees = async (baseUri) =>
{
string url = baseUri + $"odata/Employees?$select=EmployeeID,FirstName,LastName";
ODataDTO<Employee> response = await new HttpClient().GetFromJsonAsync<ODataDTO<Employee>>(url);
if (response == null || response.Value == null)
{
return new List<SelectItem>();
}
else
{
return response.Value
.Select(r => new SelectItem(r.EmployeeID.ToString(), r.EmployeeID.ToString() + " - " + r.FirstName + " " + r.LastName))
.ToList();
}
};
Other fields that you want to be shown as dropdowns with a closed list can also be configured with the SetSelectField
method.
All fields to be included in the CRUD forms but not in the grid as columns should be configured as hidden (e.g. Add(o => o.RequiredDate, true)
).
All columns required to be included in the Update form as read only should be configured using the SetReadOnlyOnUpdate(true)
method.
If a column is a date that has to be shown as date
, time
, week
, month
or datetime-local
in the CRUD forms, the column definition should use the SetInputType method in order to get the correct format.
If a column is a string that has to be shown as <textarea>
in the CRUD forms, the column definition should use the SetInputType method in order to get the correct html element.
The SetInputType method has 1 required parameter:
Parameter | Description |
---|---|
inputType |
InputType enum. Its value can be InputType.TextArea , InputType.Date , InputType.Time , InputType.Month , InputType.Week or InputType.DateTimeLocal
|
You can also add components on the CRUD forms using the RenderCrudComponentAs<TComponent>
method. You must define these columns as Hidden to show them just on CRUD forms.
And finally all columns included in the grid but not in the CRUD forms should be configured as "CRUD hidden" using the SetCrudHidden(true)
method.
Notes:
SetCrudHidden(bool create, bool read, bool update, bool delete)
method to configure the columns that will be hidden on each type of form.RenderCrudComponentAs<TCreateComponent, TReadComponent, TUpdateComponent, TDeleteComponent>
method to configure the components that will be shown on each type of form. Id you don't want to show any component for a specific type of form you must use NullComponent
This is an example of column definition:
Action<IGridColumnCollection<Order>, string> columns = (c, baseUri) =>
{
c.Add(o => o.OrderID).SetPrimaryKey(true).Titled(SharedResource.Number).SetWidth(100);
c.Add(o => o.CustomerID, true).SetSelectField(true, o => o.Customer.CustomerID + " - " + o.Customer.CompanyName,
() => GetAllCustomers(baseUri));
c.Add(o => o.EmployeeID, true).SetSelectField(true, o => o.Employee.EmployeeID.ToString() + " - " + o.Employee.FirstName
+ " " + o.Employee.LastName, () => GetAllEmployees(baseUri));
c.Add(o => o.ShipVia, true).SetSelectField(true, o => o.Shipper == null ? "" : o.Shipper.ShipperID.ToString() + " - "
+ o.Shipper.CompanyName, () => GetAllShippers(baseUri));
c.Add(o => o.OrderDate, "OrderCustomDate").Titled(SharedResource.OrderCustomDate).Format("{0:yyyy-MM-dd}").SetWidth(120);
c.Add(o => o.Customer.CompanyName).Titled(SharedResource.CompanyName).SetWidth(250).SetCrudHidden(true).SetReadOnlyOnUpdate(true);
c.Add(o => o.Customer.ContactName).Titled(SharedResource.ContactName).SetWidth(250).SetCrudHidden(true);
c.Add(o => o.Freight).Titled(SharedResource.Freight).Format("{0:F}");
c.Add(o => o.Customer.IsVip).Titled(SharedResource.IsVip).SetWidth(70).Css("hidden-xs")
.RenderValueAs(o => o.Customer.IsVip ? Strings.BoolTrueLabel : Strings.BoolFalseLabel).SetCrudHidden(true);
c.Add(o => o.RequiredDate, true).Format("{0:yyyy-MM-dd}");
c.Add(o => o.ShippedDate, true).Format("{0:yyyy-MM-dd}");
c.Add(o => o.ShipName, true);
c.Add(o => o.ShipAddress, true);
c.Add(o => o.ShipCity, true);
c.Add(o => o.ShipPostalCode, true);
c.Add(o => o.ShipRegion, true);
c.Add(o => o.ShipCountry, true);
c.Add(true).Titled("Images").RenderCrudComponentAs<Carousel, Carousel, NullComponent, NullComponent>();
};
This is an example of a grid using CRUD:
And this is an auto-genereated edit form:
If you want to use custom forms you can enable them using the SetCreateComponent, SetReadComponent, SetUpdateComponent and SetDeleteComponent methods of the GridODataClient object:
var client = new GridODataClient<Order>(HttpClient, url, query, false, "ordersGrid",
c => columns(c, NavigationManager.BaseUri), 10, locale, new List<string> { "Employee", "Shipper" })
.ODataCrud(true)
.SetCreateComponent<OrderCreateComponent>()
.SetReadComponent<OrderReadComponent>()
.SetUpdateComponent<OrderUpdateComponent>()
.SetDeleteComponent<OrderDeleteComponent>();
You can define all custom forms or just some of them. If you don't define a custom form for one of the enabled operations an auto-generated form will be used instead.
And finally you will have to create a Blazor component for the custom form. This is an example of edit form:
@using GridBlazor.Resources
@using GridBlazorOData.Shared.Models
@inherits GridUpdateComponentBase<Order>
<h1>@Strings.Add Order</h1>
<EditForm Model="@Item" OnValidSubmit="@UpdateItem">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-horizontal">
<div class="form-group">
<label for="OrderID" class="control-label col-md-2">OrderID: </label>
<div class="col-md-5">
<InputNumber id="OrderID" class="form-control" readonly="readonly" @bind-Value="Item.OrderID" />
</div>
</div>
<div class="form-group">
<label for="CustomerID" class="control-label col-md-2">Customer Id: </label>
<div class="col-md-5">
<InputText id="CustomerID" class="form-control" @bind-Value="Item.CustomerID" />
</div>
</div>
<div class="form-group">
<label for="EmployeeID" class="control-label col-md-2">Employee Id: </label>
<div class="col-md-5">
<InputNumber id="EmployeeID" class="form-control" @bind-Value="Item.EmployeeID" />
</div>
</div>
<div class="form-group">
<label for="ShipVia" class="control-label col-md-2">Ship Via: </label>
<div class="col-md-5">
<InputNumber id="ShipVia" class="form-control" @bind-Value="Item.ShipVia" />
</div>
</div>
<div class="form-group">
<label for="RequiredDate" class="control-label col-md-2">Required Date: </label>
<div class="col-md-5">
<InputDate id="RequiredDate" class="form-control" @bind-Value="Item.RequiredDate" />
</div>
</div>
<div class="form-group">
<label for="ShippedDate" class="control-label col-md-2">Shipped Date: </label>
<div class="col-md-5">
<InputDate id="ShippedDate" class="form-control" @bind-Value="Item.ShippedDate" />
</div>
</div>
<div class="form-group">
<label for="ShipName" class="control-label col-md-2">Ship Name: </label>
<div class="col-md-5">
<InputText id="ShipName" class="form-control" @bind-Value="Item.ShipName" />
</div>
</div>
<div class="form-group">
<label for="ShipAddress" class="control-label col-md-2">Ship Address: </label>
<div class="col-md-5">
<InputText id="ShipAddress" class="form-control" @bind-Value="Item.ShipAddress" />
</div>
</div>
<div class="form-group">
<label for="ShipCity" class="control-label col-md-2">Ship City: </label>
<div class="col-md-5">
<InputText id="ShipCity" class="form-control" @bind-Value="Item.ShipCity" />
</div>
</div>
<div class="form-group">
<label for="ShipPostalCode" class="control-label col-md-2">Ship Postal Code: </label>
<div class="col-md-5">
<InputText id="ShipPostalCode" class="form-control" @bind-Value="Item.ShipPostalCode" />
</div>
</div>
<div class="form-group">
<label for="ShipRegion" class="control-label col-md-2">Ship Region: </label>
<div class="col-md-5">
<InputText id="ShipRegion" class="form-control" @bind-Value="Item.ShipRegion" />
</div>
</div>
<div class="form-group">
<label for="ShipCountry" class="control-label col-md-2">Ship Country: </label>
<div class="col-md-5">
<InputText id="ShipCountry" class="form-control" @bind-Value="Item.ShipCountry" />
</div>
</div>
<div class="form-group">
<label for="Freight" class="control-label col-md-2">Freight: </label>
<div class="col-md-5">
<input id="Freight" name="Freight" class="form-control" @bind="Item.Freight" />
</div>
</div>
<div class="form-group">
<div class="col-md-5">
<button type="submit" class="btn btn-primary btn-md">@Strings.Save</button>
<button type="button" class="btn btn-primary btn-md" @onclick="BackButtonClicked">@Strings.Back</button>
</div>
</div>
</div>
</EditForm>
Note: The Blazor component must be to inherited from the GridUpdateComponentBase class.
If you want to use a drop-down list for a field you have to define it as it was for auto-generated forms.
You can configure a direct route to an specific CRUD form. The first step is to roure alternative routes as follows:
@page "/crud"
@page "/crud/{OrderId}/{Mode}"
Then you have to create and initialize the following parameters:
GridMode
for the type of CRUD formobject[]
for the primary keys of the row to be shown on the formThis is an example of these parameters initialization:
@code
{
...
private object[] _keys;
private GridMode _mode;
...
protected override async Task OnParametersSetAsync()
{
var locale = CultureInfo.CurrentCulture;
var query = new QueryDictionary<StringValues>();
string url = NavigationManager.BaseUri + "odata/Orders";
var client = new GridODataClient<Order>(HttpClient, url, query, false, "ordersGrid", c =>
ColumnCollections.OrderColumnsWithCrud(c, NavigationManager.BaseUri), 10, locale,
new List<string> { "Employee", "Shipper" })
.Sortable()
.Filterable()
.SetStriped(true)
.ODataCrud(true)
.WithMultipleFilters()
.WithGridItemsCount();
_grid = client.Grid;
if (!string.IsNullOrWhiteSpace(OrderId))
{
int orderId;
bool result = int.TryParse(OrderId, out orderId);
if (result)
{
if (Mode.ToLower() == "create")
{
_keys = new object[] { orderId };
_mode = GridMode.Create;
}
else if (Mode.ToLower() == "read")
{
_keys = new object[] { orderId };
_mode = GridMode.Read;
}
else if (Mode.ToLower() == "update")
{
_keys = new object[] { orderId };
_mode = GridMode.Update;
}
else if (Mode.ToLower() == "delete")
{
_keys = new object[] { orderId };
_mode = GridMode.Delete;
}
}
}
// Set new items to grid
_task = client.UpdateGrid();
await _task;
}
...
And finaly you have to pass the paramenters initialized before to the GridComponent
<GridComponent T="Order" Grid="@_grid" Mode="_mode" Keys="_keys"></GridComponent>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。