1

I'm trying to pass values from a select control on a blazor layout as they change to the current page. i.e. I have a dropdown that when the values is changed it needs to tell the page (via an event, parameter or cascasding parameter I'm not sure):

So far I have this:

_layout.razor

<div class="page">
     <select onchange="OnSiteChanged">
         <option value="1">Site 1</option>
         <option value="2">Site 2</option>
     </select>
</div>

@code{
    [Parameter]
    public EventHandler SiteChanged{ get; set; }

     private void OnSiteChanged(object sender, EventArgs e)
     {
         SiteChanged.Invoke(this, e);
     }
}

and pass it to the underlying page:

pagewithlayout.razor

@code{
    [Parameter]
    public EventCallback SiteChanged { get; set; }

     public async Task OnSiteChanged(EventArgs e){
         /do something
     }
}

However the event on the page never fires. Any ideas?

6
  • 1
    Like this stackoverflow.com/questions/70900179/…? Commented Apr 4, 2022 at 3:11
  • 1
    It's unclear what you are actually trying to do. I don't want to hurt your progress by telling you the right way to do the wrong thing. Why do you have a dropdown in your layout page, and what actually are Site 1 and Site 2? Could you please explain the real-life goal you're trying to achieve? Commented Apr 4, 2022 at 3:47
  • Thanks @Bennyboy1973. Your patience is appreciated. I want a dropdown on every page so I've put it in the layout. The dropdown contains a list of clients sites (physical locations) and as the user changes the site each page will show data/functionality for that site. For example, we have many reports that are site specific. Commented Apr 4, 2022 at 3:51
  • @JeremyLakeman yes something like that although it seems rather complicated for something that would be trivial in something like javascript on the client side. Commented Apr 4, 2022 at 3:57
  • 1
    learn.microsoft.com/en-us/dotnet/api/… "Alternatively, components may implement IComponent directly and declare their own parameter named Body." So what if all your page components @inherits a common base type, matching the layout Body property type... ? (I haven't worked with blazor at all though, so I don't know if that idea would work). Commented Apr 4, 2022 at 4:56

1 Answer 1

2

Thanks for @JeremyLakeman for the help that lead to this answer. This answer is specific to layouts publishing data to their pages.

Notification Service

First, I had to create a service to encapsulate the event:

public class NotifiySiteChangedService
{
    public EventHandler? SiteChanged;

    public void OnSiteChanged(object sender, SiteIdChangeEventArgs e)
    {
        if (this.SiteChanged != null)
        {
            this.SiteChanged(this, e);
        }
    }
}

public class SiteIdChangeEventArgs : EventArgs
{
    public int SiteId { get; set; }

    public SiteIdChangeEventArgs(int siteId) : base()
    {
        SiteId = siteId;
    }
}

Program.cs

Then to make it available in the app I had to register it in Program.cs:

builder.Services.AddScoped<NotifiySiteChangedService>();

MainLayout.razor

Then in the layout:

<select onchange="@SiteIdChanged">
    <option value="1">Site 1</option>
    <option value="2">Site 2</option>
</select>

@code{
    [Inject] private NotifiySiteChangedService? service { get; set; }
    private NotifiySiteChangedService Service => service!;

    public int SiteId { get; set; }

    void SiteIdChanged(ChangeEventArgs e)
    {
        if (e.Value != null)
        {
            SiteId = int.Parse(e.Value.ToString());
            Service.OnSiteChanged(this, new SiteIdChangeEventArgs(SiteId));
        }
    }
}

Index.razor

@code {
    [Inject] private NotifiySiteChangedService? service { get; set; }
    private NotifiySiteChangedService Service => service!;

    public int SiteId{get;set;}
    void SiteIdChanged(object? sender, EventArgs e)
    {
        SiteId = ((SiteIdChangeEventArgs)e).SiteId;
    } 

    protected override void OnInitialized()
    {
        this.Service.SiteChanged += this.SiteIdChanged;
        base.OnInitialized();
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

You got it. Commonly known as a Notification Service.
Thanks @MrCakaShaunCurtis I've updated the answer with the usual name.
[Politely put] @MrCakaShaunCurtis, Sorry, the service created here is definitley not Commonly known as a Notification Service. A Notification Service is something different altogether. I, at least, defined it as follows: You may define a class service that implements the State pattern` and the Notifier pattern to handle the state of your objects, pass state to objects, and notify subscriber objects of changes.` in stackoverflow.com/a/62042629/6152891 Incidentally, Guy Lowe, I believe that it is more appropriate to use cascading parameter rather than a service in this case.
Thanks @enet I trie d cascading parameters but couldn't get it to work. I'm potentially over engineering it in this case I guess.
@GuyLowe, I've added a second answer to demonstarte how to do that...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.