1
votes

I want to set defaults for parameters on a third-party component. Say I have this:

myBasePage.cs:

public class MyBasePage : ComponentBase
{
  public IEnumerable MyData { get; set; }
}

myPage.razor:

@inherits MyBasePage
<ThirdPartyComponent Data="@MyData" />

Since Data on ThirdPartyComponent is a [Parameter] with a DataHasChanged() virtual method, by rendering the blazor component like that, I'll get one-way binding, and if I change MyData on my page, programmatically, the component will update. This will work fine.

Now, say I can't modify ThirdPartyComponent, but I want to make some defaults in it based on my base page... like so:

myPage.razor:

@inherits MyBasePage
<MyDerivedComponent PageComponent="@this" />

myDerivedComponent.cs:

public class MyDerivedComponent : ThirdPartyComponent 
{
   [Parameter] public MyBasePage PageComponent { get; set; }
   public override void OnInitialized()
   {
      /* Set other parameter defaults */
      this.OtherParameter = 10;

      /* Bind to Data, as if I was passing it as a parameter in the Razor template */
      this.Data = PageComponent.MyData;
   }
}

This line:

this.Data = PageComponent.MyData;

Doesn't create a binding at all (and if I modify MyData, the blazor component doesn't get updated). Is there any way to programmatically create it?

Note: the real ThirdPartyComponent includes not only tons of parameters but also templates, etc. For many reasons, I'd like MyDerivedComponent to be of a derived type, and not a "parent component" with a child of ThirdPartyComponent, if that's possible at all).

2
I don't think Data="@MyData" will make the page re-render whenever MyData changes. Do you change its value as a response to some events? - Pharaz Fadaei
@PharazFadaei it doesn't automatically, but it does if you do a StateHasChanged or it's an EventCallback. If I set it programatically (not on the razor component template), it does neither. - Jcl
@PharazFadaei that is, if I do <MyDerivedComponent Data="@this.Data">, it works as expected... if I set it via code (<MyDerivedComponent PageComponent="@this">, then this.Data = PageComponent.Data;), it doesn't - Jcl
Do you mean if you only do Data="@this.Data" and then change the value of this.Data the component will automatically re-render? - Pharaz Fadaei
Assuming you call StateHasChanged on MyBasePage whenever the value of Data changes, the MyBasePage component will rerender accordingly. MyDerivedComponent is a child of MyBasePage and has a complex-typed parameter (PageComponent) so its OnParametersSet will be called based on the docs. - Pharaz Fadaei

2 Answers

1
votes

This should work:

public class MyDerivedComponent : ThirdPartyComponent 
{
   [Parameter] public MyBasePage PageComponent { get; set; }
   public override void OnInitialized()
   {
      /* Set other parameter defaults */
      this.OtherParameter = 10;


      //this.Data = PageComponent.MyData;
   }
}

 protected override void OnParametersSet()   
 {
    Data = Data ?? PageComponent?.MyData ;  // determine priority
    base.OnParametersSet();
 }

OnParametersSet() notifies the Component that it has new Parameters. The most-derived class can intervene here.

But there is no easy solution for wwhen this.MyData changes, that's out of sight for Blazor.

1
votes

Is there any way to programmatically create it? Of course, but that doesn't mean that you should.

Parameters should not be set or manipulated within the component code. Parameters are set externally whenever SetParametersAsync is called by the Renderer. If you change them internally you create two versions of the truth.