最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - I think the detail page is remembering the scroll position of the list page - Stack Overflow

programmeradmin5浏览0评论

Here's a weird one:

I have a Blazor contact list page and when I scroll down and click a contact to go to detail page the detail page is scrolled to the bottom. If I pick the first record on the contact list and go to detail page it is at the top of detail. it seems like when I scroll down a little on the contact list page it scrolls all way the down on the detail page. Does that sound weird or what?

I haven't put in any state to hold scroll position or anything.

Contacts List Page

@page "/contact-list"
@rendermode InteractiveServer
@using AutoMapper
@inject ContactService ContactService
@inject IMapper Mapper
@inject NavigationManager Navigation
@inject IJSRuntime JS

<PageTitle>Contacts</PageTitle>

<div class="container mt-1">
    <h3>Contacts</h3>

    <div class="d-flex justify-content-between mb-3 align-items-center">
        <button class="border-0" style="background-color: transparent;" @onclick="AddContact">
            <span style="color: green;" class="bi bi-plus-circle-fill"> New</span>
        </button>
        <div class="input-group" style="width: 70%;">
            <input type="text" placeholder="Search..." @bind="searchTerm" @bind:event="oninput" class="form-control" />
            <span class="input-group-text" style="cursor: pointer;" @onclick="ClearSearch">✖</span>
        </div>
    </div>


    <table class="table table-striped">
        <thead>
            <tr>
                <th @onclick='() => SortContacts("FirstName")' style="cursor: pointer;">
                    First @if (currentSortField == "FirstName")
                    {
                        <span>@(isAscending ? "↑" : "↓")</span>
                    }
                </th>
                <th @onclick='() => SortContacts("LastName")' style="cursor: pointer;">
                    Last @if (currentSortField == "LastName")
                    {
                        <span>@(isAscending ? "↑" : "↓")</span>
                    }
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @if (isAdding)
            {
                <tr>
                    <td colspan="3">
                        <EditForm Model="newContact" OnValidSubmit="HandleValidSubmit">
                            <DataAnnotationsValidator />
                            <ValidationSummary />

                            <div class="d-flex justify-content-between mb-3">
                                <div>
                                    <button class="btn btn-outline-secondary" @onclick="CancelAdd">Cancel</button>
                                    <button type="submit" class="btn btn-primary">Save</button>
                                </div>
                            </div>

                            <div class="form-group">
                                <label for="firstName">First Name</label>
                                <InputText id="firstName" class="form-control" @bind-Value="newContact.FirstName" />
                            </div>
                            <div class="form-group">
                                <label for="lastName">Last Name</label>
                                <InputText id="lastName" class="form-control" @bind-Value="newContact.LastName" />
                            </div>

                        </EditForm>
                    </td>
                </tr>
            }

            @foreach (var contact in PagedContacts)
            {
                <tr @key="contact.Id">
                    <td>@contact.FirstName</td>
                    <td>@contact.LastName</td>
                    <td>
                        <button class="me-1 border-0" style="background-color: transparent;" @onclick="() => EditContact(contact.Id)">
                            <span style="color: dimgrey;" class="bi bi-pencil"></span>
                        </button>
                        <button class="me-1 border-0" style="background-color: transparent;" @onclick="() => ConfirmDelete(contact.Id)">
                            <span style="color: red;" class="bi bi-x-circle-fill"></span>
                        </button>
                    </td>
                </tr>
            }
        </tbody>
    </table>

    @if (totalPages > 1)
    {
        <div class="d-flex justify-content-between mt-3">
            <button class="btn btn-outline-secondary" @onclick="PrevPage" disabled="@(!CanPrevPage)">Previous</button>
            <span>Page @currentPage of @totalPages</span>
            <button class="btn btn-outline-secondary" @onclick="NextPage" disabled="@(!CanNextPage)">Next</button>
        </div>
    }
</div>

@code {
    private List<Contact> contacts = new();
    private string searchTerm = string.Empty;
    private const int PageSize = 1000;
    private int currentPage = 1;
    private int totalPages => (int)Math.Ceiling((double)contacts.Count / PageSize);
    private string currentSortField = "FirstName";
    private bool isAscending = true;
    private Timer _debounceTimer;

    private List<Contact> PagedContacts => contacts
        .Where(c => string.IsNullOrEmpty(searchTerm) || c.FirstName.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) || c.LastName.Contains(searchTerm, StringComparison.OrdinalIgnoreCase))
        .OrderByDynamic(currentSortField, isAscending)
        .Skip((currentPage - 1) * PageSize)
        .Take(PageSize)
        .ToList();

    private Contact newContact = new();
    private bool isAdding = false;

    private bool CanPrevPage => currentPage > 1;
    private bool CanNextPage => currentPage < totalPages;

    protected override async Task OnInitializedAsync()
    {
        contacts = await ContactService.GetContactsAsync();
    }

    private void EditContact(Guid id)
    {
        Navigation.NavigateTo($"/contact-detail/{id}");
    }

    private void AddContact()
    {
        isAdding = true;
    }

    private void CancelAdd()
    {
        isAdding = false;
        newContact = new();
    }

    private async Task HandleValidSubmit()
    {
        await ContactService.AddContactAsync(newContact);
        contacts = await ContactService.GetContactsAsync(); // Refresh the contact list
        newContact = new(); // Reset the form
        isAdding = false; // Exit the add mode
    }

    private async Task ConfirmDelete(Guid id)
    {
        bool confirmed = await JS.InvokeAsync<bool>("confirm", $"Are you sure you want to delete this contact?");
        if (confirmed)
        {
            await ContactService.DeleteContactAsync(id);
            contacts = await ContactService.GetContactsAsync(); // Refresh the contact list
        }
    }

    private void PrevPage()
    {
        if (CanPrevPage)
        {
            currentPage--;
        }
    }

    private void NextPage()
    {
        if (CanNextPage)
        {
            currentPage++;
        }
    }

    private void SortContacts(string field)
    {
        if (currentSortField == field)
        {
            isAscending = !isAscending; // Toggle sorting order
        }
        else
        {
            currentSortField = field;
            isAscending = true; // Default to ascending order when field changes
        }
    }

    private void SearchChanged(ChangeEventArgs e)
    {
        searchTerm = e.Value.ToString();
        _debounceTimer?.Dispose();
        _debounceTimer = new Timer(_ => InvokeAsync(StateHasChanged), null, 500, Timeout.Infinite); // 500ms delay
    }

    private void ClearSearch()
    {
        searchTerm = string.Empty;
        InvokeAsync(StateHasChanged);
    }
}

Details Page

@page "/contact-detail/{id:guid}"
@rendermode InteractiveServer
@using AutoMapper
@inject ContactService ContactService
@inject IMapper Mapper
@inject NavigationManager Navigation

<PageTitle>Edit Contact</PageTitle>

<div class="container mt-5">

    <h3>Edit Contact</h3>
    <EditForm Model="contact" OnValidSubmit="HandleValidSubmit">
        <DataAnnotationsValidator />
        <ValidationSummary />

        <div class="d-flex justify-content-between mb-3">
            <div>
                <button type="button" class="btn btn-outline-secondary" @onclick="Cancel">Cancel</button>
                <button type="submit" class="btn btn-primary">Save</button>
            </div>
        </div>

        <div class="form-group">
            <label for="firstName">First Name:</label>
            <InputText id="firstName" class="form-control" @bind-Value="contact.FirstName" />
        </div>
        <div class="form-group">
            <label for="middleName">Middle Name:</label>
            <InputText id="middleName" class="form-control" @bind-Value="contact.MiddleName" />
        </div>
        <div class="form-group">
            <label for="lastName">Last Name:</label>
            <InputText id="lastName" class="form-control" @bind-Value="contact.LastName" />
        </div>
        <div class="form-group">
            <label for="nickName">Nick Name:</label>
            <InputText id="nickName" class="form-control" @bind-Value="contact.NickName" />
        </div>
        <div class="form-group">
            <label for="birthDate">Birth Date:</label>
            <InputDate id="birthDate" class="form-control" @bind-Value="contact.BirthDate" />
        </div>
        <div class="form-group">
            <label for="publishPermission">Publish Permission:</label>
            <InputText id="publishPermission" class="form-control" @bind-Value="contact.PublishPermission" />
        </div>
    </EditForm>

    <div class="mt-4 mb-4">
        <AddressList ContactId="@Id" />
    </div>

    <div class="mt-4 mb-4">
        <ContactInfoList ContactId="@Id" />
    </div>
</div>

@code {
    [Parameter]
    public Guid Id { get; set; }

    private Contact contact = new();

    protected override async Task OnInitializedAsync()
    {
        contact = await ContactService.GetContactByIdAsync(Id);
    }

    private async Task HandleValidSubmit()
    {
        await ContactService.UpdateContactAsync(contact);
        Navigation.NavigateTo("/contact-list");
    }

    private void Cancel()
    {
        Navigation.NavigateTo("/contact-list");
    }
}

Here's a weird one:

I have a Blazor contact list page and when I scroll down and click a contact to go to detail page the detail page is scrolled to the bottom. If I pick the first record on the contact list and go to detail page it is at the top of detail. it seems like when I scroll down a little on the contact list page it scrolls all way the down on the detail page. Does that sound weird or what?

I haven't put in any state to hold scroll position or anything.

Contacts List Page

@page "/contact-list"
@rendermode InteractiveServer
@using AutoMapper
@inject ContactService ContactService
@inject IMapper Mapper
@inject NavigationManager Navigation
@inject IJSRuntime JS

<PageTitle>Contacts</PageTitle>

<div class="container mt-1">
    <h3>Contacts</h3>

    <div class="d-flex justify-content-between mb-3 align-items-center">
        <button class="border-0" style="background-color: transparent;" @onclick="AddContact">
            <span style="color: green;" class="bi bi-plus-circle-fill"> New</span>
        </button>
        <div class="input-group" style="width: 70%;">
            <input type="text" placeholder="Search..." @bind="searchTerm" @bind:event="oninput" class="form-control" />
            <span class="input-group-text" style="cursor: pointer;" @onclick="ClearSearch">✖</span>
        </div>
    </div>


    <table class="table table-striped">
        <thead>
            <tr>
                <th @onclick='() => SortContacts("FirstName")' style="cursor: pointer;">
                    First @if (currentSortField == "FirstName")
                    {
                        <span>@(isAscending ? "↑" : "↓")</span>
                    }
                </th>
                <th @onclick='() => SortContacts("LastName")' style="cursor: pointer;">
                    Last @if (currentSortField == "LastName")
                    {
                        <span>@(isAscending ? "↑" : "↓")</span>
                    }
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @if (isAdding)
            {
                <tr>
                    <td colspan="3">
                        <EditForm Model="newContact" OnValidSubmit="HandleValidSubmit">
                            <DataAnnotationsValidator />
                            <ValidationSummary />

                            <div class="d-flex justify-content-between mb-3">
                                <div>
                                    <button class="btn btn-outline-secondary" @onclick="CancelAdd">Cancel</button>
                                    <button type="submit" class="btn btn-primary">Save</button>
                                </div>
                            </div>

                            <div class="form-group">
                                <label for="firstName">First Name</label>
                                <InputText id="firstName" class="form-control" @bind-Value="newContact.FirstName" />
                            </div>
                            <div class="form-group">
                                <label for="lastName">Last Name</label>
                                <InputText id="lastName" class="form-control" @bind-Value="newContact.LastName" />
                            </div>

                        </EditForm>
                    </td>
                </tr>
            }

            @foreach (var contact in PagedContacts)
            {
                <tr @key="contact.Id">
                    <td>@contact.FirstName</td>
                    <td>@contact.LastName</td>
                    <td>
                        <button class="me-1 border-0" style="background-color: transparent;" @onclick="() => EditContact(contact.Id)">
                            <span style="color: dimgrey;" class="bi bi-pencil"></span>
                        </button>
                        <button class="me-1 border-0" style="background-color: transparent;" @onclick="() => ConfirmDelete(contact.Id)">
                            <span style="color: red;" class="bi bi-x-circle-fill"></span>
                        </button>
                    </td>
                </tr>
            }
        </tbody>
    </table>

    @if (totalPages > 1)
    {
        <div class="d-flex justify-content-between mt-3">
            <button class="btn btn-outline-secondary" @onclick="PrevPage" disabled="@(!CanPrevPage)">Previous</button>
            <span>Page @currentPage of @totalPages</span>
            <button class="btn btn-outline-secondary" @onclick="NextPage" disabled="@(!CanNextPage)">Next</button>
        </div>
    }
</div>

@code {
    private List<Contact> contacts = new();
    private string searchTerm = string.Empty;
    private const int PageSize = 1000;
    private int currentPage = 1;
    private int totalPages => (int)Math.Ceiling((double)contacts.Count / PageSize);
    private string currentSortField = "FirstName";
    private bool isAscending = true;
    private Timer _debounceTimer;

    private List<Contact> PagedContacts => contacts
        .Where(c => string.IsNullOrEmpty(searchTerm) || c.FirstName.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) || c.LastName.Contains(searchTerm, StringComparison.OrdinalIgnoreCase))
        .OrderByDynamic(currentSortField, isAscending)
        .Skip((currentPage - 1) * PageSize)
        .Take(PageSize)
        .ToList();

    private Contact newContact = new();
    private bool isAdding = false;

    private bool CanPrevPage => currentPage > 1;
    private bool CanNextPage => currentPage < totalPages;

    protected override async Task OnInitializedAsync()
    {
        contacts = await ContactService.GetContactsAsync();
    }

    private void EditContact(Guid id)
    {
        Navigation.NavigateTo($"/contact-detail/{id}");
    }

    private void AddContact()
    {
        isAdding = true;
    }

    private void CancelAdd()
    {
        isAdding = false;
        newContact = new();
    }

    private async Task HandleValidSubmit()
    {
        await ContactService.AddContactAsync(newContact);
        contacts = await ContactService.GetContactsAsync(); // Refresh the contact list
        newContact = new(); // Reset the form
        isAdding = false; // Exit the add mode
    }

    private async Task ConfirmDelete(Guid id)
    {
        bool confirmed = await JS.InvokeAsync<bool>("confirm", $"Are you sure you want to delete this contact?");
        if (confirmed)
        {
            await ContactService.DeleteContactAsync(id);
            contacts = await ContactService.GetContactsAsync(); // Refresh the contact list
        }
    }

    private void PrevPage()
    {
        if (CanPrevPage)
        {
            currentPage--;
        }
    }

    private void NextPage()
    {
        if (CanNextPage)
        {
            currentPage++;
        }
    }

    private void SortContacts(string field)
    {
        if (currentSortField == field)
        {
            isAscending = !isAscending; // Toggle sorting order
        }
        else
        {
            currentSortField = field;
            isAscending = true; // Default to ascending order when field changes
        }
    }

    private void SearchChanged(ChangeEventArgs e)
    {
        searchTerm = e.Value.ToString();
        _debounceTimer?.Dispose();
        _debounceTimer = new Timer(_ => InvokeAsync(StateHasChanged), null, 500, Timeout.Infinite); // 500ms delay
    }

    private void ClearSearch()
    {
        searchTerm = string.Empty;
        InvokeAsync(StateHasChanged);
    }
}

Details Page

@page "/contact-detail/{id:guid}"
@rendermode InteractiveServer
@using AutoMapper
@inject ContactService ContactService
@inject IMapper Mapper
@inject NavigationManager Navigation

<PageTitle>Edit Contact</PageTitle>

<div class="container mt-5">

    <h3>Edit Contact</h3>
    <EditForm Model="contact" OnValidSubmit="HandleValidSubmit">
        <DataAnnotationsValidator />
        <ValidationSummary />

        <div class="d-flex justify-content-between mb-3">
            <div>
                <button type="button" class="btn btn-outline-secondary" @onclick="Cancel">Cancel</button>
                <button type="submit" class="btn btn-primary">Save</button>
            </div>
        </div>

        <div class="form-group">
            <label for="firstName">First Name:</label>
            <InputText id="firstName" class="form-control" @bind-Value="contact.FirstName" />
        </div>
        <div class="form-group">
            <label for="middleName">Middle Name:</label>
            <InputText id="middleName" class="form-control" @bind-Value="contact.MiddleName" />
        </div>
        <div class="form-group">
            <label for="lastName">Last Name:</label>
            <InputText id="lastName" class="form-control" @bind-Value="contact.LastName" />
        </div>
        <div class="form-group">
            <label for="nickName">Nick Name:</label>
            <InputText id="nickName" class="form-control" @bind-Value="contact.NickName" />
        </div>
        <div class="form-group">
            <label for="birthDate">Birth Date:</label>
            <InputDate id="birthDate" class="form-control" @bind-Value="contact.BirthDate" />
        </div>
        <div class="form-group">
            <label for="publishPermission">Publish Permission:</label>
            <InputText id="publishPermission" class="form-control" @bind-Value="contact.PublishPermission" />
        </div>
    </EditForm>

    <div class="mt-4 mb-4">
        <AddressList ContactId="@Id" />
    </div>

    <div class="mt-4 mb-4">
        <ContactInfoList ContactId="@Id" />
    </div>
</div>

@code {
    [Parameter]
    public Guid Id { get; set; }

    private Contact contact = new();

    protected override async Task OnInitializedAsync()
    {
        contact = await ContactService.GetContactByIdAsync(Id);
    }

    private async Task HandleValidSubmit()
    {
        await ContactService.UpdateContactAsync(contact);
        Navigation.NavigateTo("/contact-list");
    }

    private void Cancel()
    {
        Navigation.NavigateTo("/contact-list");
    }
}

Share edited Mar 13 at 14:05 phuclv 42.3k15 gold badges184 silver badges527 bronze badges asked Mar 11 at 0:55 RodRod 15.5k35 gold badges134 silver badges264 bronze badges 1
  • [Polite] Are you sure you're describing the Edit behaviour? I can see you have a new inline form for adding that would work as you describe, but the edit navigates to a new route so I don't see how you can preserve a scrolled position in a edit form where the content probably fits on the page. Can you provide a screen shot or two? – MrC aka Shaun Curtis Commented Mar 11 at 8:54
Add a comment  | 

1 Answer 1

Reset to default 0

You could add the js codes in app.razor:

 Blazor.addEventListener('enhancedload', () => {
            
    console.log("enhancedload")
    window.scrollTo({ top: 0, left: 0, behavior: 'instant' });
});

check the console if enhancedload is triggered and scroll to the position you want

发布评论

评论列表(0)

  1. 暂无评论