Home > Mobile >  Pass complex object to component page
Pass complex object to component page

Time:09-26

I have a razor component called projects that has a list of projects with different properties.

I have them listed in a table with something like this:

<table>
    <thead>
    <tr>
        <th>Project Number</th>
        <th>Project Name</th>
        <th>Status</th>
    </tr>
    </thead>
    <tbody>
    @foreach (var p in projects)
    {
        <tr>
            <td>@p.ProjectId</td>
            <td>@p.Name</td>
            <td>@p.ProjectStatus</td>
        </tr>
    }
    </tbody>
</table>

now, I want that when the user clicks on the "projectId" it navigates to another page that will have the detailed information for this particular project, which I understand is done like this:

<button @onclick="() => ButtonHandler(p.ProjectId)">@p.ProjectId</button>

@code
{

    private void ButtonHandler(int projectId)
    {

        Project = projects.First(x => x.ProjectId == projectId);
        navigationManager.NavigateTo($"/projectdetail/{projectId}");

    }
}

this projectId I'm passing is because I want to filter the project list into a single object "Project" that I want to pass to my "projectDetail" component.

in my projectDetail.razor I have the following:

@page "/projectdetail/{ProjectId:int}"

@code {

    [Parameter]
    public Project Project { get; set; } = null!;
}

however this doesn't seem to work, the Project property is null when I reach to it.

Can I get some help about how to properly pass the object from "ProjectList" to "ProjectDetail"?

I have tried with the component passing as well by doing

<td>@project.ProjectId <ProjectDetail Project="Project"></ProjectDetail></td>

but it seems that as this being inside the foreach loop is doing it every time instead of just the one I need when the users clicks on it.

CodePudding user response:

You are passing a ProjectId route parameter to the ProjectDetail.razor page which you should use to fetch the Project:

@page "/projectdetail/{ProjectId:int}"

@code {
    [Parameter]
    public int ProjectId { get; set; }

    private Project project;

    protected override void OnInitialized()
    {
        project = ProjectService.GetProjectById(ProjectId);
    }
}

Edit:

Only way to pass the entire Project object to the ProjectDetails page would be to serialize it to JSON string and pass it using a string route parameter.

ProjectDetails.razor:

@page "/productdetails/{ProjectJson}"
@using System.Text.Json

@code {
    [Parameter]
    public string ProjectJson { get; set; }

    private Project project { get; set; }

    protected override void OnInitialized()
    {
        project = JsonSerializer.Deserialize<Project>(ProjectJson);
    }
}

ProjectList.razor:

<button @onclick="() => ButtonHandler(p.ProjectId)">@p.ProjectId</button>

@code {
    private void ButtonHandler(int projectId)
    {
        Project = projects.First(x => x.ProjectId == projectId);
        navigationManager.NavigateTo($"projectdetail/{JsonSerializer.Serialize(Project)}");
    }
}

CodePudding user response:

From the point of view of UI design, it's better to have the list of projects in a tabular element at the top of the page, and the project detail below it. This allows you to view the project's detail instantly, as you select a project in the list of project. This means that your project detail is no longer a routable component, and it is embedded within the projects component. And now, you can query Project = projects.First(x => x.ProjectId == projectId);, in the ButtonHandler method, the projects list in order to get the selected project, and pass it as a parameter to the embedded component.

Note that the above suggested design is also more efficient and fast, as Blazor does not destroy the elements in the Detail component, and recreate them a new. It uses the same objects to dispaly the new data.

But if you insist on creating a dedicted page for the project's detail, you should pass only the ProjectId to the Detail component:

@page "/projectdetail/{ProjectId:int}"
@inject ProjectsService projectsService

@code {
    [Parameter]
    public int ProjectId { get; set; }

    private Project project;

    protected override void OnInitialized()
    {
        project = ProjectsService.GetProjectById(ProjectId);
    }
}

Note: Your ProjectsService should implement the state pattern. There shouldn't be any issue of querying the database again and again. Its life time should span the duration of the app. Thus when you call the GetProjectById method, it accesses the collection of projects stored in a variable defined in the service, and returns the selected project. No database call. See here how it is done

  • Related