Hello,
I have a Grid and then a Detail Grid. To edit the record in the Detail Grid, I use EditMode.Dialog. Everything is working as expected except when I try to access the record being edited in the Detail Grid Edit Dialog through OnActionBegin. I get a null reference exception when I try to access the record data. My code is below. I appreciate the help.
<SfGrid TValue="Programs" ToolBar=@Tool RowHeight="70">
<SfDataManager Url="api/programs" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
<GridEvents TValue="Programs" OnActionFailure="ActionFailure" RowDataBound="RowDataBound"/>
<GridEditSettings AllowAdding="true" AllowEditing="true" Mode="EditMode.Dialog">
<HeaderTemplate>
@{
var program = (context as Programs);
<h2><span>Edit @program.ProgramName</span></h2>
}
</HeaderTemplate>
<Template Context="editProgramContext">
@{
var @program = (editProgramContext as Programs);
<div class="form-row">
<div class="form-group col-md-6">
<label class="e-float-text e-label-top">Program ID</label>
<SfNumericTextBox TValue="int" ID="ProgramId" @bind-value="@program.Id" Enabled="false" ShowSpinButton="false"/>
</div>
</div>
<div class="form-row>">
<div class="form-group col-md-8">
<label class="e-float-text e-label-top">Program Name</label>
<SfTextBox ID="ProgramName" @bind-value="@program.ProgramName"/>
<ValidationMessage For="() => program.ProgramName"/>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-8">
<label class="e-float-text e-label-top">Program Description</label>
<SfTextBox ID="ProgramDescription" Multiline="true" @bind-Value="@program.ProgramDescription"/>
<ValidationMessage For="() => program.ProgramDescription"></ValidationMessage>
</div>
</div>
}
</Template>
</GridEditSettings>
<GridTemplates>
<DetailTemplate>
@{
var program = (context as Programs);
<!-- Set private variable programId to the current Program.Id -->
programId = program.Id;
<!-- Create an empty Ranks list if we don't already have one -->
if (program.Ranks == null || program.Ranks.Count() == 0)
{
List<Rank> program_ranks = new List<Rank> { new Rank() };
program.Ranks = new List<Rank>(program_ranks);
}
<SfGrid TValue="Rank" Query=@GetProgramsQuery(program) ToolBar="@RankTool" @ref="RanksGrid" RowHeight="70">
<GridSortSettings>
<GridSortColumns>
<GridSortColumn Field="RankOrder" Direction="SortDirection.Ascending"></GridSortColumn>
</GridSortColumns>
</GridSortSettings>
<SfDataManager Url="api/ranks" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
<GridEvents TValue="Rank" OnActionFailure="@ActionFailure" OnToolbarClick="ToolbarClickHandler"
OnActionComplete="OnActionComplete" OnActionBegin="OnRankActionBegin"/>
<GridEditSettings AllowAdding="true" AllowEditing="true" Mode="EditMode.Dialog" Context="rankContext">
<HeaderTemplate>
@{
var rank = (rankContext as Rank);
<h2><span>Edit @rank.RankName Belt</span></h2>
}
</HeaderTemplate>
<Validator>
<DataAnnotationsValidator></DataAnnotationsValidator>
</Validator>
<Template>
@{
var rank = (rankContext as Rank);
<!-- Set the ProgramId for the current rank from the private variable -->
rank.ProgramId = programId;
<div class="form-row">
<div class="form-group col-md-3">
<label class="e-float-text e-label-top">Program ID</label>
<SfNumericTextBox TValue="int" ID="ProgramId" @bind-value="@rank.ProgramId" Enabled="false" ShowSpinButton="false"></SfNumericTextBox>
</div>
<div class="form-group col-md-6">
<label class="e-float-text e-label-top">Rank Name</label>
<SfTextBox ID="RankName" @bind-value="@rank.RankName"></SfTextBox>
<ValidationMessage For="() => rank.RankName"/>
</div>
<div class="form-group col-md-3">
<label class="e-float-text e-label-top">Uses Belts</label>
<SfCheckBox ID="UsesBelts" @bind-Checked="@rank.UsesBelts" @onchange="OnUsesBeltsChange"/>
</div>
</div>
<div hidden="@(!rank.UsesBelts)"> <!-- Belt configuration section -->
<div class="form-row">
<div class="form-group col-md-3">
<label class="e-float-text e-label-top">Belt</label>
<table @ref=@beltView width:150px height:40px>
<tr class="topStripe" style="background-color: @rank.Color;">
<td style="width: 80px; height: 40px;"></td> <!-- right spacer -->
<td @ref="@stripes[6]" style="width: 10px; height: 40px; border-left: 2px solid @stripeColor[6];"></td>
<td @ref="@stripes[5]" style="width: 10px; height: 40px; border-left: 2px solid @stripeColor[5];"></td>
<td @ref="@stripes[4]" style="width: 10px; height: 40px; border-left: 2px solid @stripeColor[4];"></td>
<td @ref="@stripes[3]" style="width: 10px; height: 40px; border-left: 2px solid @stripeColor[3];"></td>
<td @ref="@stripes[2]" style="width: 10px; height: 40px; border-left: 2px solid @stripeColor[2];"></td>
<td @ref="@stripes[1]" style="width: 10px; height: 40px; border-left: 2px solid @stripeColor[1];"></td>
<td @ref="@stripes[0]" style="width: 10px; height: 40px; border-left: 2px solid @stripeColor[0];"></td>
</tr>
</table>
</div>
<div class="form-group col-md-3">
<label class="e-float-text e-label-top">Belt Color</label>
<SfColorPicker ID="Color" @bind-value="@rank.Color" Mode="ColorPickerMode.Palette" ValueChange="OnColorChange"/>
<ValidationMessage For="() => rank.Color"/>
</div>
<div class="form-group col-md-4">
<label class="e-float-text e-label-top">Use Stripes</label>
<SfCheckBox hidden="UsesStripes" @bind-Checked="@rank.UseStripes"/>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-3">
<label class="e-float-text e-label-top">Stripe Direction</label>
<SfDropDownList TValue="StripeDirection?" TItem="string" Placeholder="Choose..." @bind-Value="@rank.StripeDirection" DataSource="Direction"/>
<ValidationMessage For="() => rank.StripeDirection"/>
</div>
<div class="form-group col-md-3">
<label class="e-float-text e-label-top">Number of Stripes</label>
<SfNumericTextBox TValue="int" ID="NumberOfStripes">
<NumericTextBoxEvents TValue="int" ValueChange="@OnStripesCountChanged"></NumericTextBoxEvents>
</SfNumericTextBox>
<ValidationMessage For="() => rank.NumberOfStripes"/>
</div>
<div class="form-group col-md-3">
<label class="e-float-text e-label-top">Stripe Color</label>
<SfColorPicker ID="StripeColor" @bind-value="@rank.StripeColor" Mode="ColorPickerMode.Palette"/>
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-4">
<label class="e-float-text e-label-top">Required Attendances</label>
<SfNumericTextBox TValue="int?" ID="RankRequiredAttendances" @bind-value="@rank.RankRequiredAttendances"/>
<ValidationMessage For="() => rank.RankRequiredAttendances"/>
</div>
<div class="form-group col-md-4">
<label class="e-float-text e-label-top">Time to Test</label>
<SfNumericTextBox TValue="int?" ID="RankTimeToTest" @bind-value="@rank.RankTimeToTest"/>
<ValidationMessage For="() => rank.RankTimeToTest"/>
</div>
<div class="form-group col-md-4">
<label class="e-float-text e-label-top">Timeframe</label>
<SfDropDownList TValue="CalendarUnits?" TItem="string" Placeholder="Select Period" @bind-value="@rank.RankTimeToTestUnits" DataSource="@Timeframes"/>
<ValidationMessage For="() => rank.RankTimeToTestUnits"/>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label class="e-float-text e-label-top">Rank Test Fee</label>
<SfNumericTextBox TValue="float?" Format="c2" ID="RankTestFee" @bind-value="@rank.RankTestFee"></SfNumericTextBox>
<ValidationMessage For="() => rank.RankTestFee"/>
</div>
<div class="form-group col-md-6">
<label class="e-float-text e-label-top">Rank Test Length</label>
<SfTimePicker TValue="TimeSpan?" Step="15" @bind-Value="@rank.RankTestLength" Format="@("h\\:mm")"></SfTimePicker>
<ValidationMessage For="() => rank.RankTestLength"/>
</div>
</div>
}
</Template>
</GridEditSettings>
<GridColumns>
<GridColumn Type="ColumnType.CheckBox" Width="50"/>
<GridColumn Field="Id" IsPrimaryKey="true" Visible="false" ShowInColumnChooser="false"/>
<GridColumn Field="RankOrder"/>
<GridColumn Field="RankName"/>
<GridColumn Field="UsesBelts" Type="ColumnType.Boolean" DisplayAsCheckBox="true" TextAlign="TextAlign.Center"/>
<GridColumn HeaderText="Belt"></GridColumn>
<GridColumn Field="RankRequiredAttendances"/>
<GridColumn Field="RankTestFee" Format="C2" TextAlign="TextAlign.Right"/>
<GridColumn Field="RankTimeToTest" TextAlign="TextAlign.Right"/>
<GridColumn Field="RankTimeToTestUnits">
<EditTemplate Context="editTimeToTestUnitsContest">
@{
var rttu = (editTimeToTestUnitsContest as Rank);
<SfDropDownList TValue="CalendarUnits?" TItem="string" Placeholder="Select Period" @bind-value="@(rttu.RankTimeToTestUnits)" DataSource="@Timeframes"/>
}
</EditTemplate>
</GridColumn>
<GridColumn Field="RankTestLength">
<Template Context="testlengthcontext">
@{
var r = (testlengthcontext as Rank);
@r.RankTestLength?.ToString("h\\:mm")
}
</Template>
<EditTemplate Context="editTestLengthContext">
@{
var rtl = (editTestLengthContext as Rank);
<SfTimePicker TValue="TimeSpan?" Step="15" @bind-Value="@(rtl.RankTestLength)" EnableMask="true" Format="@("hh:mm")" ShowClearButton="true">
<TimePickerMaskPlaceholder Hour="hh" Minute="mm"></TimePickerMaskPlaceholder>
</SfTimePicker>
}
</EditTemplate>
</GridColumn>
<GridColumn Field="ProgramId" Visible="false"/>
<GridColumn Field="StripeColor" Visible="false"/>
<GridColumn Field="Color" Visible="false"/>
<GridColumn HeaderText="Edit">
<GridCommandColumns>
<GridCommandColumn Type="CommandButtonType.Edit" ButtonOption="@(new CommandButtonOptions() { IconCss = "e-icons e-edit", CssClass = "e-flat" })"/>
</GridCommandColumns>
</GridColumn>
</GridColumns>
</SfGrid>
}
</DetailTemplate>
</GridTemplates>
<GridColumns>
<GridColumn Type="ColumnType.CheckBox" Width="50"/>
<GridColumn Field="Id" IsPrimaryKey="true" Visible="false" ShowInColumnChooser="false"/>
<GridColumn Field="ProgramName"/>
<GridColumn Field="ProgramDescription"/>
<GridColumn Field="UsesRanks" Type="ColumnType.Boolean" DisplayAsCheckBox="true" TextAlign="TextAlign.Center"/>
<GridColumn HeaderText="Edit">
<GridCommandColumns>
<GridCommandColumn Type="CommandButtonType.Edit" ButtonOption="@(new CommandButtonOptions() { IconCss = "e-icons e-edit", CssClass = "e-flat" })"/>
</GridCommandColumns>
</GridColumn>
</GridColumns>
</SfGrid>
<ReorderRanksComponent @ref="reorderRanksDialog" OnDialogClosed="@DialogClosed"></ReorderRanksComponent>
@code {
//TODO Add button in edit dialog to programmatically add another belt or program in the respective edit dialog
[CascadingParameter] public ProcessError Error { get; set; }
List<string> Tool = (new List<string>() {"Add", "Search"});
List<Object> RankTool = (new List<Object>() {"Add", new ItemModel(){Text="Reorder Ranks", TooltipText = "Reorder Ranks", PrefixIcon = "e-line-spacing", Id = "Reorder"}, "Edit", "Delete", "Cancel", "Update", "Search"});
private string[] Timeframes = Enum.GetNames(typeof(CalendarUnits));
private string[] Direction = Enum.GetNames(typeof(StripeDirection));
private SfGrid<Program> ProgramsGrid;
private SfGrid<Rank> RanksGrid;
private int programId;
protected bool _showPopup { get; set; } = false;
private ReorderRanksComponent reorderRanksDialog;
private bool showBeltAttributes { get; set; } = false;
private string rankColor;
private string rankStripeColor;
private bool ShowErrors;
private string Errors;
private Rank rank = new Rank();
private bool buttonsHidden { get; set; } = false;
private bool showDialog { get; set; } = false;
private ElementReference beltView; // holds the reference to the <table> element in the belt configuration section
private ElementReference[] stripes = new ElementReference[7]; // holds the reference to the <td> elements in the belt table
private string[] stripeColor = new string[7]; //sets td:border-left-color either to rank.Stripecolor or none.
protected void OnRankActionBegin(Syncfusion.Blazor.Grids.ActionEventArgs<Rank> args)
{
var name = args.Data.RankName; //null reference exception
Log.Information("Rank {RankName} is being edited", name);
}
private void OnStripesCountChanged(Syncfusion.Blazor.Inputs.ChangeEventArgs<int> args)
{
if (args.Value > 0)
{
for (int i = 0; i <= 7 ; i++)
{
if (i < args.Value)
{
stripeColor[i] = rank.StripeColor;
//stripeColor[i] = "#ffffff";
}
else
{
stripeColor[i] = rank.Color;
}
}
rank.NumberOfStripes = args.Value;
}
StateHasChanged();
}
Hi Judi,
Based on your requirements, you
want to perform some operations when data editing begins. We suggest achieving
this by checking if the condition in the action begin event's argument RequestType is
"BeginEdit". Then, you can perform the customization based on your
requirements. Kindly refer to the code snippet and simple sample below for your
reference:
|
public void ActionBegin(ActionEventArgs<Order> args) { if (args.RequestType == Syncfusion.Blazor.Grids.Action.BeginEdit) { // Triggers before editing operation starts } } |
Sample: https://blazorplayground.syncfusion.com/embed/BXhJZyWJCvQwPAlH?appbar=true&editor=true&result=true&errorlist=true&theme=bootstrap5
Regards,
Prathap s
Tha worked perfectly. Thank you.
Thanks for the update,
We are happy to hear that the provided solution was helpful. We are closing the thread now.