title: Insert component into existing dom tree
body: <p>I have a component called <code>SelectPeopleModal</code>. I want append it to dom tree programmatically.</p>
  <p>Then I can make a help method like this:</p>
  <pre><code>public static SelectUtils {
      public static void SelectPeople(Action&lt;People&gt; callback) {
          // I know this is not correct in blazor.
          // But I think it is helpful to express my intention.
          var modal = new SelectPeopleModal(callback); 
      }
  }
  </code></pre>
  <p>This can make it easier to select people, I don't need to write the component in razor component every time but just call a method.</p>
  <p>Can anyone help me ? Thank you.</p>
  <hr />
  <p>I do have a solution that I don't satisfied with. I posted it below.
  It's not a good one, it requires rendering the component in the razor file before using it.
  And I have to create many select modals, It's bad to render every modal in the root component.</p>
  <p>I want something just like <a href="https://reactjs.org/docs/portals.html" rel="nofollow noreferrer">React.createPortal</a>. In winform, it's easy to do this too, just <code>new SelectPeopleForm().OpenDialog()</code>. I wonder whether I can do something similarly in blazor.</p>
  <h1>Step 1: Create Select Container And Service</h1>
  <p>SelectContainer.razor</p>
  <pre class="lang-cs prettyprint-override"><code>&lt;SelectPeopleModal Value=&quot;OldValue&quot;
                      Visible=&quot;ShowModal&quot;
                      OnCancel=&quot;HandleCancel&quot;
                      OnOk=&quot;HandleOk&quot;/&gt;
  
  </code></pre>
  <p>SelectContainer.razor.cs</p>
  <pre class="lang-cs prettyprint-override"><code>public partial class SelectContainer
      {
          [Inject]
          private SelectService SelectService { get; set; }
  
          private People OldValue { get; set; }
          private bool ShowModal { get; set; }
          private Action&lt;People&gt; OnOk { get; set; }
          private Action OnCancel { get; set; }
  
          private void OpenSelectModal(SelectPayload payload)
          {
              var options = payload.Options as SelectOptions&lt;People&gt;;
  
              OnOk = payload.OnOk;
              OnCancel = payload.OnCancel;
              ShowModal = true;
              OldValue = options.OldValue;
  
              StateHasChanged();
          }
          
          private void HandleOk(People data)
          {
              OnOk?.Invoke(data);
          }
  
          private void HandleCancel()
          {
              ShowModal = false;
              OnCancel?.Invoke();
          }
  
          protected override void OnInitialized()
          {
              SelectService.OnSelectEvent += OpenSelectModal;
              base.OnInitialized();
          }
      }
  </code></pre>
  <p>SelectService.cs</p>
  <pre class="lang-cs prettyprint-override"><code>public class SelectService
      {
          internal event Action&lt;SelectPayload&gt; OnSelectEvent;
          public Task&lt;(bool, People)&gt; SelectPeople(SelectOptions&lt;People&gt; options)
          {
              var promise = new TaskCompletionSource&lt;(bool, People)&gt;(null);
              OnSelectEvent?.Invoke(new SelectPayload(typeof(People))
              {
                  Options = options,
                  OnOk = people =&gt; {
                      promise.SetResult((true, people as People));
                  },
                  OnCancel = () =&gt; {
                      promise.TrySetResult((false, null));
                  },
              });
  
              return promise.Task;
          }
      }
  
      public class SelectOptions&lt;T&gt;
      {
          public string Title { get; set; }
          public T OldValue { get; set; }
      }
      
      public class SelectPayload
      {
          public Type ValueType { get; init; }
          public object Options { get; set; }
          public Action&lt;object&gt; OnOk { get; set; }
          public Action OnCancel { get; set; }
  
          public SelectPayload(Type valueType)
          {
              ValueType = valueType;
          }
      }
  </code></pre>
  <h1>Step 2: Render the container and register the select service</h1>
  <p>App.razor</p>
  <pre class="lang-cs prettyprint-override"><code>...route things
  &lt;SelectContainer /&gt;
  </code></pre>
  <p>Program.cs</p>
  <pre class="lang-cs prettyprint-override"><code>public class Program
      {
          public static async Task Main(string[] args)
          {
              var builder = WebAssemblyHostBuilder.CreateDefault(args);
              builder.RootComponents.Add&lt;App&gt;(&quot;#app&quot;);
  
              builder.Services
                  .AddScoped&lt;SelectService&gt;();
  
              var host = builder.Build();
  
              await host.RunAsync();
          }
      }
  </code></pre>
  <h1>Step 3: Inject select service and use it</h1>
  <p>WhereIUsing.razor.cs</p>
  <pre class="lang-cs prettyprint-override"><code>public class WhereIUsing {
      [Inject]
      private SelectService SelectService { get; set; }
  
      private People currentPeople { get; set; }
      private async Task DoSomething() {
          var (ok, result) = await SelectService.SelectPeople(new SelectOptions&lt;People&gt;
          {
              OldValue = currentPeople,
              AllowNull = true,
          });
          currentPeople = result;
      }
  }
  </code></pre>