Search code examples
blazorblazor-component

Blazor - how to remove a child component


BackGround

I have a component MainComponent with multiple buttons which will make a new SubComponent appear (<TaskList AreaId="@SelectedAreaId" IsVisible="@IsVisible"></TaskList>).

Problem

The problem appears when I wanted to put a close button on the SubComponent: I tried creating a button on it and make: IsVisible = !IsVisible. While this does work to some extent (it makes the component disappear from the view), it has the problem that if I click on the button from MainComponent with the same SubComponent it will not appear (I assume because the component is still "alive").

What's the best solution to this? I was thinking of using IDisposable on the SubComponent, but ComponentName.Dispose() is not defined.

Edit1: Added example of what I'm currently doing

MainComponent (TaskList.razor)

    <div class="col-12 outer-div row">
        <TaskDetails TaskId="@SelectedTaskId" IsVisible="@IsTaskDetailsVisible"></TaskDetails>
    </div>
    ...
            <ul>
                @for (int i = 0; i < MondayTasks.Count(); i++)
                {
                    var myIndex = i;
                    <li class="btn" @onclick="@(() => LoadTaskDetailsForTask(MondayTasks[myIndex].Id))">
                        <a role="button">
                            <h4>@MondayTasks[i].Name</h4>
                            <p>@MondayTasks[i].DeadlineDate.Date.ToShortDateString()</p>
                        </a>
                    </li>
                }
            </ul>
    ...

private async Task LoadTaskDetailsForTask(int taskId)
{
    SelectedTaskId = taskId;
    IsTaskDetailsVisible = true;
    await JSRuntime.InvokeVoidAsync("onScrollEvent");
}

SubComponent (TaskDetails.razor)

@if (IsVisible)
{
    ...
            <div class="row">
                <h2 class="inner-div title">@taskDetails.Name</h2>
                <span class="closebtn" @onclick="()=> ToggleVisibility()">&times;</span>
            </div>

    //Display Information
}

...
protected async override void OnParametersSet()
{
    taskDetails = await _dbTasks.GetTasksDetails(TaskId);
    TaskItems = await _dbTasks.GetTasksItems(TaskId);
    this.StateHasChanged();
}

private void ToggleVisibility()
{
    IsVisible = !IsVisible;
}

Edit2: Added Working Code

MainComponent (TaskList.razor)

    <CascadingValue Value="this">
    <div class="col-12 outer-div row">
        <TaskDetails TaskId="@SelectedTaskId" IsVisible="@IsTaskDetailsVisible"></TaskDetails>
    </div>
    </CascadingValue>
    ...
            <ul>
                @for (int i = 0; i < MondayTasks.Count(); i++)
                {
                    var myIndex = i;
                    <li class="btn" @onclick="@(() => LoadTaskDetailsForTask(MondayTasks[myIndex].Id))">
                        <a role="button">
                            <h4>@MondayTasks[i].Name</h4>
                            <p>@MondayTasks[i].DeadlineDate.Date.ToShortDateString()</p>
                        </a>
                    </li>
                }
            </ul>
    ...

private async Task LoadTaskDetailsForTask(int taskId)
{
    SelectedTaskId = taskId;
    IsTaskDetailsVisible = true;
    await JSRuntime.InvokeVoidAsync("onScrollEvent");
}
public void RemoveTaskDetails()
{
    IsTaskDetailsVisible = false;
    StateHasChanged();
}

SubComponent (TaskDetails.razor)

@if (IsVisible)
{
    ...
            <div class="row">
                <h2 class="inner-div title">@taskDetails.Name</h2>
                <span class="closebtn" @onclick="()=> ToggleVisibility()">&times;</span>
            </div>

    //Display Information
}

...
[CascadingParameter]
public TaskList _Parent { get; set; }

protected async override void OnParametersSet()
{
    taskDetails = await _dbTasks.GetTasksDetails(TaskId);
    TaskItems = await _dbTasks.GetTasksItems(TaskId);
    this.StateHasChanged();
}

private void ToggleVisibility()
{
    _Parent.RemoveTaskDetails();
}

Solution

  • You have

    [Parameter] bool IsVisible  {get; set; }
    private void ToggleVisibility()
    {
        IsVisible = !IsVisible;
    }
    

    This is a pattern to avoid: Do not change a parameter from inside the Component.

    You will have to add an EventCallback and change the IsTaskDetailsVisible on the main component.