Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to return objects from tab buttons #525

Merged

Conversation

MarvinKlein1508
Copy link

This PR adds a new feature to tabs which allows the user to return a custom object when the nav button of a tab has been clicked.

This is for use-cases where tabs are being used to render content for a list of objects. It's important to know which object is currently selected to adjust some logic on your blazor page.

I've added a short demo as well.

In my case I need this functionality to show a list of positions. Depending on the selected position I display additional information outside of the Tabs control.

Implementation might not be perfect but it works fine in my case. Feel free to suggest changes.

@gvreddy04 gvreddy04 added this to the 1.11.0 milestone Jan 25, 2024
@gvreddy04 gvreddy04 merged commit 50265b4 into vikramlearning:master Jan 25, 2024
2 of 3 checks passed
@MarvinKlein1508
Copy link
Author

@gvreddy04 There is one thing left todo here. I've noticed that the property IsShown does not trigger a a tab activation when the property is changed from outside.

@MarvinKlein1508
Copy link
Author

MarvinKlein1508 commented Jan 25, 2024

To reproduce:

<Tabs>
    @foreach (var customer in customers)
    {
        <Tab IsActive="selectedCustomer == customer" OnTabClicked="async () => await OnTabClickedAsync(customer)" Title="@customer.CustomerName">
            <Content>
                <div class="mt-3">
                    This is the placeholder content for the <b>@customer.CustomerName</b> tab.
                </div>
            </Content>
        </Tab>
    }
</Tabs>

@if (selectedCustomer is not null)
{
    <div class="mt-3">Selected customer: <b>@selectedCustomer.CustomerName</b></div>
}

<Button Color="ButtonColor.Success">Add customer</Button>

@code {
    private List<Customer> customers = new()
                                       {
                                           new Customer(1, "Marvin Klein"),
                                           new Customer(2, "Vikram Reddy"),
                                           new Customer(3, "Bandita PA"),
                                           new Customer(4, "Daina JJ")
                                       };



    private Customer? selectedCustomer;

    protected override void OnInitialized()
    {
        selectedCustomer = customers.First();
    }

    private Task AddCustomerAsync()
    {
        var customer = new Customer(5, "Hello World");

        customers.Add(customer);

        selectedCustomer = customer;

        return Task.CompletedTask;
    }

    private Task OnTabClickedAsync(Customer customer)
    {
        selectedCustomer = customer;
        return Task.CompletedTask;
    }
}

Notice how active tab does not change when selectedCustomer changes outside of the tab control. This also applies for all other tab demos.

gvreddy04 referenced this pull request in MarvinKlein1508/blazorbootstrap Jan 26, 2024
gvreddy04 added a commit that referenced this pull request Jan 26, 2024
* Add vertical tabs

* Code Format

* Tabs - Vertical enhancements

* #525 - Tabs - aria-orientation attribute updates

---------

Co-authored-by: Vikram Reddy <gvreddy04@gmail.com>
@MarvinKlein1508 MarvinKlein1508 deleted the return-objects-in-tabs branch January 28, 2024 11:58
@MarvinKlein1508
Copy link
Author

@gvreddy04 did you consider my last comment here?

@gvreddy04
Copy link
Contributor

@MarvinKlein1508 I missed the scenario. I think a few people asked for dynamic tabs. I'll check.

@gvreddy04
Copy link
Contributor

Dynamically adding tabs #480

@gvreddy04
Copy link
Contributor

@MarvinKlein1508
Copy link
Author

MarvinKlein1508 commented Jan 31, 2024

@gvreddy04 that's still not what I mentioned above.

I have use-cases where I set selectedCustomer for example from outside.

For example:

<Tabs @ref="tabs">
    @foreach (var customer in customers)
    {
        <Tab Title="@customer.CustomerName"
             OnTabClicked="() => OnTabClicked(customer)"
             IsActive="selectedCustomer == customer">
            <Content>
                <div class="mt-3">
                    This is the placeholder content for the <b>@customer.CustomerName</b> tab.
                </div>
            </Content>
        </Tab>
    }
</Tabs>

@if (selectedCustomer is not null)
{
    <div class="mt-3">Selected customer: <b>@selectedCustomer.CustomerName</b></div>
}

<Button Color="ButtonColor.Success" Class="mt-3" @onclick="AddCustomer">Add customer</Button>
<Button Color="ButtonColor.Success" Class="mt-3" @onclick="Select2ndCustomer">Select 2nd customer</Button>

@code {
    Tabs tabs = default!;

    private List<Customer> customers = new() { new(1, "Marvin Klein"), new(2, "Vikram Reddy"), new(3, "Bandita PA"), new(4, "Daina JJ") };

    private Customer selectedCustomer = default!;

    protected override void OnInitialized() => selectedCustomer = customers.Last();

    private void AddCustomer()
    {
        var count = customers.Count;
        var customer = new Customer(count + 1, $"Customer {count + 1}");
        customers.Add(customer);
        //selectedCustomer = customer; NOTE: this line is not required
        tabs.InitializeRecentTab(showTab: true);
    }

    private void Select2ndCustomer()
    {
        selectedCustomer = customers[1];
    }

    private void OnTabClicked(Customer customer) => selectedCustomer = customer;
}

What I expect now is tab for customer Vikran Reddy to be shown.

In my use-case this is triggered when running validation for an object within the list. If the validation has failed I want the tab to open automatically so the user can see the error messages at a glance.

To achieve this IsActive needs to trigger the tab to be shown/hidden when the provided parameter changes it's value.

@MarvinKlein1508
Copy link
Author

See this gif for an example:
tabs

@MarvinKlein1508
Copy link
Author

BTW. is there any reason for the control to rely on JavaScript in the first place? Wouldn't it be easier to implement it with vanilla HTML and C#?

What I did in previous projects was someting like this:

<div class="row">
    <div class="col-md-2 mb-3">
        <div class="nav flex-column nav-pills" role="tablist" aria-orientation="vertical">
            @foreach (var pos in Input.Positions)
            {
                <button type="button" role="tab" @onclick="() => SelectedPosition = pos" class="@GetTabNavLinkClass(SelectedPosition == pos)" id="pos-tab-@pos.GetHashCode()" data-bs-toggle="pill">(@pos.Id) @pos.Name</button>
            }
        </div>
    </div>
    <div class="col-md-10">
        <div class="tab-content">
            @foreach (var pos in Input.Positions)
            {
                int posHash = pos.GetHashCode();
                <div class="@GetTabClass(SelectedPosition == pos)" id="pos-@posHash" role="tabpanel" aria-labelledby="pos-tab-@posHash">

                    <p>Content for tab</p>

                </div>
            }

        </div>
    </div>
</div>
public string GetTabNavLinkClass(bool active) => active ? "nav-link active" : "nav-link";
public string GetTabClass(bool active) => active ? "tab-pane fade active show" : "tab-pane fade";

@MarvinKlein1508
Copy link
Author

ping @gvreddy04

@gvreddy04
Copy link
Contributor

See this gif for an example: tabs tabs

I understand the scenario. The IsActive property is currently used in the OnInitialized stage, which is why it's not working as expected. For now, please use @ref to reference the tabs and then call the appropriate methods. I'll address this issue in version 1.11.0. However, the caveat is that we cannot use both IsActive and the methods to activate any of the tabs simultaneously.

@MarvinKlein1508
Copy link
Author

@gvreddy04 I don't think this is a problem. I think you are either using the activation via tabs or the attribute itself. The attribute might be used more frequently for dynamic tabs though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants