Search code examples
blazorblazor-server-sideblazor-client-side

Blazor : How to pass ViewModel from Child Component to Parent Component and vice versa


How to pass ViewModel from Child Component to Parent Component and vice versa in Blazor

I am using MVVM Pattern to Build Blazor App.

Tried Below Code but Not working

[Parameter]
public ViewModel viewModel { get; set; }

Solution

  • I wrote a blog post about Parent Child communication in Blazor.

    https://datajugglerblazor.blogspot.com/2020/01/how-to-use-interfaces-to-communicate.html

    I have a Nuget package I created to make this simple:

    DataJuggler.Blazor.Components

    The way I created parent child communication is by your parent component or page implements this IBlazorComponentParent interface:

    #region using statements
    
    using System.Collections.Generic;
    
    #endregion
    
    namespace DataJuggler.Blazor.Components.Interfaces
    {
    
        #region interface IBlazorComponentParent
        /// <summary>
        /// This interface is used to host IBlazorComponent objects
        /// </summary>
        public interface IBlazorComponentParent
        {
    
            #region Methods
    
                #region FindChildByName(string name)
                /// <summary>
                /// This method is used to find a child component that has registered with the parent.
                /// </summary>
                /// <param name="name"></param>
                /// <returns></returns>
                IBlazorComponent FindChildByName(string name);
                #endregion
    
                #region ReceiveData(Message message)
                /// <summary>
                /// This method is used to send data from a child component to the parent component or page.
                /// </summary>
                /// <param name="data"></param>
                void ReceiveData(Message message);
                #endregion
    
                #region Refresh()
                /// <summary>
                /// This method will call StateHasChanged to refresh the UI
                /// </summary>
                void Refresh();
                #endregion
    
                #region Register(IBlazorComponent component)
                /// <summary>
                /// This method is called by the Sprite to a subscriber so it can register with the subscriber, and 
                /// receiver events after that.
                /// </summary>
                void Register(IBlazorComponent component);    
                #endregion
    
            #endregion
    
            #region Properties
    
                #region Children
                /// <summary>
                /// This property gets or sets the value for Children.
                /// </summary>
                public List<IBlazorComponent> Children { get; set; }
                #endregion
    
            #endregion
    
        }
        #endregion
    
    }
    

    Then your child component implements IBlazorComponent

    #region using statements
    
    using System.Collections.Generic;
    
    #endregion
    
    namespace DataJuggler.Blazor.Components.Interfaces
    {
    
        #region interface IBlazorComponent
        /// <summary>
        /// This interface allows communication between a blazor componetn and a parent component or page.
        /// </summary>
        public interface IBlazorComponent
        {
    
            #region Methods
    
                #region ReceiveData(Message message)
                /// <summary>
                /// This method is used to send data from a child component to the parent component or page.
                /// </summary>
                /// <param name="data"></param>
                void ReceiveData(Message message);
                #endregion
    
            #endregion
    
            #region Properties
    
                #region Name
                /// <summary>
                /// This property gets or sets the Name.
                /// </summary>
                public string Name { get; set; }
                #endregion
    
                #region Parent
                /// <summary>
                /// This property gets or sets the Parent componet or page for this object.
                /// </summary>
                public IBlazorComponentParent Parent { get; set; }
                #endregion
    
            #endregion
    
        }
        #endregion
    
    }
    

    Then when you implement your component, you set the Parent=this:

    <div class="galleryimages">
        @if (SelectedArtist.HasImages)
        { 
            @foreach (Image image in SelectedArtist.Images)
            {  
                <ImageButton Image=image Parent=this></ImageButton>
            }
        }
    </div>
    

    In the setter property for the Parent on my Image component, I Register with the parent:

    private IBlazorComponentParent parent;
    
    [Parameter]
    public IBlazorComponentParent Parent
    {
        get { return parent; }
        set 
        { 
           // store the parent
           parent = value;
    
           // if the value for HasParent is true
           if (HasParent)
           {
               // Register with the parent
               Parent.Register(this);
           }
       }
    

    On my Index page, my Register method looks like this:

    public void Register(IBlazorComponent component)
    {
        // If the component object exists
        if (NullHelper.Exists(component, Children))
        {
            // If this is the Login component
            if (component.Name == "Login")
            {
                // Set the Signup control
                this.Login = component as Login;
            }
    
            // add this child
            Children.Add(component);
        }
    }
    

    Now at this point, both Parent and Child have a ReceiveData method, where you can send what I called a MessageObject.

        // Create a message
        Message message = new Message();
    
        // Send a clear message
        message.Text = "";
    
        // Send data
        NamedParameter parameter = new NamedParameter();
    
        // set the properties and add new parameter
        parameter.Name = "MyData";
        parameter.Value = myData;
        message.Parameters.Add(parameter);
    }
    

    In your receive data method, read your parameters and do the updates.

    Here is an example for my Blazor Image Gallery Sample project, where I read the parameters after a user logs in:

    public void ReceiveData(Message message)
    {
        // If the message object exists
        if (NullHelper.Exists(message))
        {
            // if a NewArtist signed up or Logged In
            if (message.Text == "Artist Logged In"
            {
                // if the parameters collection exists
                if (message.HasParameters)
                {
                    // iterate the parameters                            
                    foreach (NamedParameter parameter in message.Parameters)                                           
                    {
                        // if this is the name
                        if (parameter.Name == "Artist")
                        {
                            // Get the login response
                            LoginResponse loginResponse = parameter.Value as LoginResponse;
    
                            // If the loginResponse object exists
                            if (NullHelper.Exists(loginResponse))
                            {
                                // Update the UI that we have a login
                                LoginComplete(loginResponse);
                            }
                        }
                     }
                  }
                }
                else
                {
                    // Set the message text
                    this.Message = message.Text;
    
                    // Update the UI
                    Refresh();
                }
            }
        }
    

    Here is a full working project if you want to view it: https://github.com/DataJuggler/BlazorImageGallery

    And a video here goes with it if you are bored:

    https://youtu.be/3xKXJQ4qThQ

    Maybe this will give you some ideas.