I am working on an ASP.NET Core (.NET 5.0) Server-side Blazor app. I am trying to add/edit users in a modal and assign roles to the user in another modal. So, I have a parent component and two child components.
Parent Component:
@if (ShowPopup)
{
<!-- This is the popup to create or edit user -->
<EditUserModal ClosePopup="ClosePopup" CurrentUserRoles="" DeleteUser="DeleteUser" objUser="objUser" SaveUser="SaveUser" strError="@strError" />
}
@if (ShowUserRolesPopup)
{
<!-- This is the popup to create or edit user roles -->
<EditUserRolesModal AddRoleToUser="AddRoleToUser" AllRoles="AllRoles" ClosePopup="ClosePopup" CurrentUserRoles="@CurrentUserRoles" objUser="objUser" RemoveRoleFromUser="RemoveRoleFromUser" SelectedUserRole="@SelectedUserRole" strError="@strError" _allUsers="_allUsers" _userRoles="UserRoles" />
}
@code {
// Property used to add or edit the currently selected user
ApplicationUser objUser = new ApplicationUser();
// Roles to display in the roles dropdown when adding a role to the user
List<IdentityRole> AllRoles = new List<IdentityRole>();
// Tracks the selected role for the current user
string SelectedUserRole { get; set; }
// To enable showing the Popup
bool ShowPopup = false;
// To enable showing the User Roles Popup
bool ShowUserRolesPopup = false;
......
}
The parent component contains the objects that hold the data objects (state) e.g. objUser
, SelectedUserRole
etc. and the methods that use these objects to implement the business rules e.g. SaveUser
and AddRoleToUser
.
The child component EditUserModal is used to add/edit users. It takes the objUser
as a parameter from the parent component. 'objUser' holds the value of the new/selected user.
<div class="form-group">
<input class="form-control" type="text" placeholder="First Name" @bind="objUser.FirstName" />
</div>
<div class="form-group">
<input class="form-control" type="text" placeholder="Last Name" @bind="objUser.LastName" />
</div>
<div class="form-group">
<input class="form-control" type="text" placeholder="Email" @bind="objUser.Email" />
</div>
<button class="btn btn-primary" @onclick="SaveUser">Save</button>
@code {
[Parameter]
public ApplicationUser objUser { get; set; }
[Parameter]
public EventCallback SaveUser { get; set; }
.......
}
The objUser
object and SaveUser
event callback are parameters in the child component. After entering data in the form of the child component and saving it, the SaveUser
is called in the parent component and the data binding is automatically done with the objUser
object in the parent component. This object holds the currently entered data. This object is then used to call databases services to create/update user data. It runs perfect!
This is how it looks like:
The objUser
object has the entered data and it all works fine.
But the issue is in the EditUserRolesModal component where I am doing somewhat a similar thing with a variable. Code of EditUserRolesModal component:
<h5 class="my-3">Add Role</h5>
<div class="row">
<div class="col-md-10">
<div class="form-group">
<input class="form-control" type="text" @bind="objUser.Email" disabled />
</div>
<div class="form-group">
<select class="form-control" @bind="@SelectedUserRole">
@foreach (var option in AllRoles)
{
<option value="@option.Name">@option.Name</option>
}
</select>
</div>
<button class="btn btn-primary" @onclick="AddRoleToUser">Assign</button>
</div>
</div>
@code {
[Parameter]
public ApplicationUser objUser { get; set; }
[Parameter]
public string SelectedUserRole { get; set; }
[Parameter]
public List<IdentityRole> AllRoles { get; set; }
[Parameter]
public EventCallback AddRoleToUser { get; set; }
........
}
Here the parameter SelectedUserRole
is used to hold the value of the role to be assigned to the user. It is bind to a dropdown list. When I change the value of the dropdown, the debugging shows that the value is updated in the child component (parameter) object. The following images show it:
The value is set to the SelectedUserRole
parameter object in the child component.
Much like, objUser
was being used in EditUserModal
to hold the value of fields FirstName
, LastName
and Email
of the new/selected user, SelectedUserRole
is used in EditUserRolesModal
to hold the value of the selected role to be assigned to the user.
But when the Assign button is pressed and the AddRoleToUser
event is called in the parent component through the child component, the SelectedUserRole
variable contains null in the parent component.
The scenario in both of the child components is the same, where the purpose is that upon the change in the value of the parameters inside the child component, the bound values should be updated and reflected in the parent's state. However, it works in EditUserModal
component and not in EditUserRolesModal
component. Why? What am I doing wrong?
P.S. I am not experienced in Blazor or component-based web programming.
Edit: I have created a public repository for this project. It contains the database script file as well. It can be found here.
ApplicationUser
logic code (CRUD, update roles, etc) into one place - a Data Service object. You can access this one copy of the truth though Dependancy Injection from all your components. If you want to follow this up I'll post some example code as an answer. - MrC aka Shaun Curtis