Opened

Dyamically add/removing tab issue

mdwyer commented

This is similar to the issue here: https://github.com/Megabit/Blazorise/issues/1374

My code is slightly different in that it has 2 static tabs and I added a close tab function (all code below).

The adding new tabs work fine and it selects the tab as expected. However, when I close a dynmically added tab, I can not get it to select the static "monitor" tab again. Secondly, the tab does disappear from the screen, however the item still exists in the tabs object list. My main concern for now though is why changing selectedtab to "monitor" is not selecting the correct tab when I remove a tab?

<Tabs  SelectedTab="@selectedTab"  RenderMode="TabsRenderMode.LazyLoad">
        <Items>
            <Tab Name="monitor">Monitor</Tab>
            <Tab Name="positionsummary" >Position Summary</Tab>
        @foreach ( var tab in tabsList )
    {
                <Tab Name="@tab.TabName">@tab.BloombergActionId.ToString()  &nbsp;&nbsp;<CloseButton Clicked="@(async()=>await CloseTab(tab.BloombergActionId))"></CloseButton></Tab>
            }         
        

        </Items>
       
        <Content>

            <TabPanel Name="monitor" >
               
				</TabPanel>
            <TabPanel Name="positionsummary">
              <Trading.Mni.Web.Components.MergerArb.MergerArbListing SecurityList="SecurityList"></Trading.Mni.Web.Components.MergerArb.MergerArbListing>
            </TabPanel>
             @{
                 foreach ( var tab in tabsList )
    {
        <TabPanel Name="@tab.TabName">
            <Trading.Mni.Web.Components.MergerArb.MergerArbDetail MergerArbSecurity="@tab.mergerArbObject"></Trading.Mni.Web.Components.MergerArb.MergerArbDetail>

        </TabPanel>
    }
     selectedTab = "positionsummary";
     }
</Content>
    </Tabs>

And the code to close a tab:

protected async Task CloseTab(long BloombergActionId)
    {

        selectedTab = "monitor"; //THIS DOES NOT WORK
         if (tabs != null) await tabs.SelectTab("monitor"); //THIS DOES NOT WORK
         tabsList.RemoveAll(x => x.BloombergActionId == BloombergActionId);
       
        await InvokeAsync(StateHasChanged);
        


    }
mdwyer commented

The below line can be removed from my above code, that was just me testing stuff and it didn't work either

 selectedTab = "positionsummary";
mdwyer commented

And if I comment out the line that removes the dynamic tab and instead just try and set the selected tab, that does not work either, the screen kind of flashes but the current selected tab stays selected.

 protected async Task CloseTab(long BloombergActionId)
    {

        selectedTab = "monitor";
         if (tabs != null) await tabs.SelectTab("monitor");
        // tabsList.RemoveAll(x => x.BloombergActionId == BloombergActionId);
       
        await InvokeAsync(StateHasChanged);
        


    }
mladenmacanovic commented

Can you try adding a @key to the dynamic tag?

Example

@foreach ( var tab in tabsList )
{
  <Tab @key="@tab.TabName" Name="@tab.TabName">...</Tab>
}
mdwyer commented

Same result, still can't get it to change the selected tab. The tab closes just fine, just won't select one of the static tabs and the screen is basically just white with no selected tab.

@foreach ( var tab in tabsList )
{
            <Tab @key="@tab.TabName" Name="@tab.TabName">@tab.TabTitle.ToString()  &nbsp;&nbsp;<CloseButton   Clicked="@(async()=>await CloseTab(tab.BloombergActionId))"></CloseButton></Tab>
        }         
    
mladenmacanovic commented

I've just noticed you're missing a two-way binding. Try with @bind-SelectedTab="@selectedTab".

mdwyer commented

I tried that earlier, but had the same result. I put it back in to test with the key thing I just added, but still same result.

<Tabs  @bind-SelectedTab="@selectedTab" RenderMode="TabsRenderMode.LazyLoad">
        <Items>
            <Tab Name="monitor">Monitor</Tab>
            <Tab Name="positionsummary" >Position Summary</Tab>
        @foreach ( var tab in tabsList )
    {
                <Tab @key="@tab.TabName" Name="@tab.TabName">@tab.TabTitle.ToString()  &nbsp;&nbsp;<CloseButton   Clicked="@(async()=>await CloseTab(tab.BloombergActionId))"></CloseButton></Tab>
            }         
        

        </Items>
       
        <Content>

            <TabPanel Name="monitor" >
mladenmacanovic commented

Here is the fully working code

<Tabs @ref="@tabs" @bind-SelectedTab="@selectedTab" RenderMode="TabsRenderMode.LazyLoad">
    <Items>
        <Tab Name="monitor">Monitor</Tab>
        <Tab Name="positionsummary">Position Summary</Tab>
        @foreach ( var tab in tabsList )
        {
            <Tab @key="@tab.TabName" Name="@tab.TabName">
                @{
                    var id = @tab.BloombergActionId.ToString();
                        <Span Padding="Padding.Is2.FromEnd">@id</Span>
                }
                <CloseButton @onclick:stopPropagation Clicked="@(async()=>await CloseTab(tab.BloombergActionId))"></CloseButton>
            </Tab>
        }
    </Items>

    <Content>
        <TabPanel Name="monitor">
            <Div Padding="Padding.Is5">
                monitor
            </Div>
        </TabPanel>
        <TabPanel Name="positionsummary">
            <Div Padding="Padding.Is5">
                positionsummary
            </Div>
        </TabPanel>
        @{
            foreach ( var tab in tabsList )
            {
                    <TabPanel @key="@tab.TabName" Name="@tab.TabName">
                        <Div Padding="Padding.Is5">
                            @tab.TabName
                        </Div>
                    </TabPanel>
            }
        }
    </Content>
</Tabs>
@code {
    class TabInfo
    {
        public long BloombergActionId { get; set; }
        public string TabName { get; set; }
    }

    Tabs tabs;
    string selectedTab = "monitor";

    List<TabInfo> tabsList = new List<TabInfo>()
    {
        new TabInfo{ BloombergActionId = 100, TabName = "test 1" },
        new TabInfo{ BloombergActionId = 200,TabName = "test 2" },
        new TabInfo{ BloombergActionId = 300,TabName = "test 3" }
    };

    protected async Task CloseTab( long bloombergActionId )
    {
        tabsList.RemoveAll( x => x.BloombergActionId == bloombergActionId );

        selectedTab = "monitor";

        await InvokeAsync( StateHasChanged );
    }
}

The problem was in CloseButton being propagated up to the Tab and so it would would select the deleting tab and then back to "monitor" and lastly again deleted tab. All before Blazor finish rendering. By stopping propagation we allow Blazor to handle states in the right order.

mdwyer commented

Great find, thanks so much! Plus I now learned about event progation in case I notice similar issues in Blazor. I appreciate the help!

Want to comment on this issue? Log in and write your comment.
Asignee
No assignee
Labels
No Labels