Reputation: 958
Problem
User select list of items from ComponentA
and then to review the list of selected items. User is redirected to ComponentB
where the user finds the list of the selected items.
In MVC
It's straight forward because we can simply post the list of data from View to the Post method of Controller
and from that controller we can render the required new view.
How can we accomplish the same in the Blazor Server?
Please let me know if more details need to be added.
Upvotes: 0
Views: 204
Reputation: 45754
You can do that in various ways depending on whether ComponentA and ComponentB are both routable components or not.
If ComponentB is a child component of ComponentA; that is, ComponentB, which is not routable, is embedded within ComponentA, you can pass values from ComponentA to ComponentB as Component parameters... The following code snippet creates a parent component and a child component, and demonstrate how to pass values from the parent component to the child component:
@page "/parent"
<Child Age="age" Country="country" />
@code
{
private int age = 21;
private string country = "Thailand";
}
@ No @page directive here as the child component is not routable @
<p>Country: @Country</p>
@code
{
[Parameter]
Public int Age {get; set;}
[Parameter]
Public string Country {get; set;}
}
As you can see, we pass age and country values from the parent component to it's child component. In real life code, you may pass collections of objects, do various manipulations, etc. The above is a basic outline of how a parent can communicate with it's child and pass it values. The other way around, that is, to pass values from the child component to its parent is done via event delegates.
When both components are Component pages; that is, both are routable, you usually need a mediator object to perform passing values from one component to another.
Suppose you want to redirect your user from the current page, say ComponentA, where he has filled a form with lots of data items, to ComponentB, which gets the data, process it, etc. Here's the code how to navigate from ComponentA to Navigate to ComponentB:
<button type="button" @onclick="ShowList">Show list of women</button>
@code
{
private void ShowList()
{
NavigateManager.NavigateTo("/ComponentB");
}
}
As you can see, the code above redirects the user from one page to another, but how to pass the data ? To achieve this you have to define a service class that can be injected into both components to perform the passing of data from one to another. The following link is to an answer of mine where I speak in details about this mechanism.
Hope this helps...
Upvotes: 2
Reputation: 3073
You might try wrapping both components in an outer component and then using the outer as a state container.
Container
<div>
<ComponentA @ref="_componentA" ListItems="ListA"/>
<ComponentB @ref="_componentb" ListItems="ListB"/>
</div>
@code {
Public List<T> ListA { get; set; }
Public List<T> ListB => ListA.Where(x => x.IsSelected).ToList();
ComponentA _componentA;
ComponentB _componentB;
}
Now you have your lists separated from the rendering details, and ListB is just deriving from ListA and giving you a list filtered by a boolean you will need to set up. As a matter of keeping concerns in the right places, all functions against the list(s) should also live in the Container component. You also have references to the 2 components set up so you can act on their public methods externally.
To access the components, set them up with an IsVisible property and a starting value, and methods to show and hide, and an EventCallBack
property so calling code can set methods. You will also need a control (button?) for the callback.
Component A
<div style="display: @(IsVisible ? "flex" : "none")">
@foreach (var item in Items)
{
//Do something awesome
}
<button @onclick="@(() => ToggleToB.InvokeAsync())">Toggle to Component B</button>
</div>
@code {
[Parameter]
public List<T> Items { get; set; }
[Parameter]
public EventCallBack ToggleToB { get; set; }
private bool IsVisible { get; set } = true
public void Show()
{
IsVisible = true;
}
public void Hide()
{
IsVisible = false;
}
... other component details
}
Component B will have the same setup, but the initial value of IsVisible will be false
since you don't want to see it initially.
Now you can set up methods from the Container
that act on the component methods, so your container looks like below. Note the callback methods in the <Component>
tags:
Container updated
<div>
<ComponentA @ref="_componentA" ListItems="ListA" ToggleToB="@ShowComponentB"/>
<ComponentB @ref="_componentb" ListItems="ListB" ToggleToA="@ShowComponentA"/>
</div>
@code {
Public List<T> ListA { get; set; }
Public List<T> ListB => ListA.Where(x => x.IsSelected).ToList();
public ComponentA _componentA;
ComponentB _componentB;
public void ShowComponentA()
{
_componentA.Show();
_componentB.Hide();
}
public void ShowComponentB()
{
_componentB.Show();
_componentA.Hide();
}
public void ListBConfirmed()
{
// Do whatever you do once you go through Component B
ShowComponentA();
}
}
Lastly, remember that neither Component A or B needs an @page
listed, do it in the Container
for your routing instead as each component in the container is now designed to be wrapped in a container to capture the reference, and get it's list.
And that's it, now you have Component A and B to render lists from another source, and all the plumbing needed to act on methods from the external source to update the lists as required. Just add more EventCallBack
parameters as needed, and if you have parameters to pass to the container methods remember to use EventCallBack<T>
.
Upvotes: 2