Resizing a column in the grid causes other columns to resize.

0 Answers 1198 Views
Grid
Jeffrey
Top achievements
Rank 2
Iron
Veteran
Iron
Jeffrey asked on 02 Jul 2021, 08:36 PM | edited on 06 Jul 2021, 01:49 PM

I've implemented code that will save the state of the grid columns and reapply that state when the grid renders.  If a column is rearranged to a new location it seems to cause a problem with the resizing logic.  In my case, I've got a grid with many columns (37).  I rearrange a single column.  This results in the new column state being saved.  (In this example, all I have done is move 1 column from its original position).  I then refresh the page.  On page initialization, the column state is read and applied to the grid.  Next, I resize a single column. (In this example, the first column).  The result is that every column between the original location of the moved column and its new location are resized.

What appears to be happening is that somehow the grid saved the columns widths for each column before the resizing and then after the first column was resized, the rest of the columns had their original column widths reapplied but its ignoring the fact the the column state had changed after loading so that the column widths are being applied to the wrong columns.  (This feels like an awful explanation and is hard to follow I'm sure).  I'm attaching a screenshot of the before/after html that illustrates how the column widths get messed up.  Hopefully the visualization will help.  The image shows the state of the column widths before and after the first column is resized.

Dimo
Telerik team
commented on 06 Jul 2021, 11:35 AM

Hi Jeffrey,

I created a test page and played with it, according to your instructions, but could not observe an issue with the column sizes. Here is the page. Can you check it and confirm if the discussed behavior is reproduced with it? If yes, please provide exact step-by-step instructions and I will dive deeper.

=========================

@page "/t1526467"
@inject LocalStorage LS

<h3>Ticket 1526467</h3>

<ol>
    <li>Reorder column 7 to position 3</li>
    <li>Refresh the page</li>
    <li>Resize column 1</li>
</ol>

<TelerikButton OnClick="@SaveState">Save State</TelerikButton>

<TelerikButton OnClick="@RestoreState">Restore State</TelerikButton>

<TelerikGrid @ref="@MyGrid"
             Data="@Data"
             Pageable="true"
             PageSize="3"
             Sortable="true"
             OnStateInit="((GridStateEventArgs<GridItem> args) => OnStateInit(args))"
             OnStateChanged="((GridStateEventArgs<GridItem> args) => OnStateChanged(args))"
             AutoGenerateColumns="true"
             Resizable="true"
             Reorderable="true">
    <GridColumns>
        @{
            for (int i = 1; i <= 12; i++)
            {
                <GridColumn Field="@("Field" + i)" Title="@("Field" + i)" Width="200px" />
            }
        }
    </GridColumns>
</TelerikGrid>

@code {
    private List<GridItem> Data { get; set; }
    private TelerikGrid<GridItem> MyGrid { get; set; }
    private GridState<GridItem> MyGridState { get; set; }
    private string LocalStorageKey = "GridState1526467";

    private async Task SaveState()
    {
        MyGridState = MyGrid.GetState();
        await LS.SetItem(LocalStorageKey, MyGridState);
    }

    private async Task RestoreState()
    {
        await GetGridState();
        await MyGrid.SetState(MyGridState);
    }

    private async Task GetGridState()
    {
        MyGridState = await LS.GetItem<GridState<GridItem>>(LocalStorageKey);
    }

    private async Task OnStateInit(GridStateEventArgs<GridItem> args)
    {
        try
        {
            await GetGridState();
            if (MyGridState != null)
            {
                args.GridState = MyGridState;
            }
        }
        catch (InvalidOperationException)
        {
            // the JS Interop for the local storage cannot be used during pre-rendering
        }
    }

    private async Task OnStateChanged(GridStateEventArgs<GridItem> args)
    {
        await LS.SetItem(LocalStorageKey, args.GridState);
    }

    protected override async Task OnInitializedAsync()
    {
        Data = new List<GridItem>();

        for (int i = 1; i <= 15; i++)
        {
            Data.Add(new GridItem()
            {
                ID = i,
                Field1 = "Field1 " + i,
                Field2 = "Field2 " + i,
                Field3 = "Field3 " + i,
                Field4 = "Field4 " + i,
                Field5 = "Field5 " + i,
                Field6 = "Field6 " + i,
                Field7 = "Field7 " + i,
                Field8 = "Field8 " + i,
                Field9 = "Field9 " + i,
                Field10 = "Field10 " + i,
                Field11 = "Field11 " + i,
                Field12 = "Field12 " + i
            });
        }
    }

    public class GridItem
    {
        public int ID { get; set; }
        public string Field1 { get; set; }
        public string Field2 { get; set; }
        public string Field3 { get; set; }
        public string Field4 { get; set; }
        public string Field5 { get; set; }
        public string Field6 { get; set; }
        public string Field7 { get; set; }
        public string Field8 { get; set; }
        public string Field9 { get; set; }
        public string Field10 { get; set; }
        public string Field11 { get; set; }
        public string Field12 { get; set; }
    }
}

 

=========================

The LocalStorage class implementation is:

=========================

using Microsoft.JSInterop;
using System.Text.Json;
using System.Threading.Tasks;

namespace TelerikBlazorApp
{
    public class LocalStorage
    {
        protected IJSRuntime JSRuntimeInstance { get; set; }

        public LocalStorage(IJSRuntime jsRuntime)
        {
            JSRuntimeInstance = jsRuntime;
        }

        public ValueTask SetItem(string key, object data)
        {
            return JSRuntimeInstance.InvokeVoidAsync(
                "localStorage.setItem",
                new object[] {
                    key,
                    JsonSerializer.Serialize(data)
                });
        }

        public async Task<T> GetItem<T>(string key)
        {
            var data = await JSRuntimeInstance.InvokeAsync<string>("localStorage.getItem", key);
            if (!string.IsNullOrEmpty(data))
            {
                return JsonSerializer.Deserialize<T>(data);
            }

            return default;
        }

        public ValueTask RemoveItem(string key)
        {
            return JSRuntimeInstance.InvokeVoidAsync("localStorage.removeItem", key);
        }
    }
}

=========================

Jeffrey
Top achievements
Rank 2
Iron
Veteran
Iron
commented on 06 Jul 2021, 01:54 PM | edited

I'm still unable to reproduce the issue with your sample, however, I've identified a related issue. One difference with my project is that I've got the first 3 columns of the grid locked. I did the same on your sample and discovered that when the grid state is restored, things can go awry. In this case, I resized the first column, making it smaller and then saved the state. I reloaded the page and when it restores the saved column width for the first column, the second column doesn't shift to the left so there is a gap between column 1 and 2. I've attached a screen shot to my original question.

NOTE: I switched the grid column definitions from 200px to 10rem and the issue goes away.... with that said, my understanding is that there are rending issues with using "rem" and locked columns together...because of that, I have switched to using "px" in my grid definitions.
Jeffrey
Top achievements
Rank 2
Iron
Veteran
Iron
commented on 06 Jul 2021, 06:51 PM

I was able to reproduce the issue with your sample. Upon continued research I discovered that the problem manifests itself only if the "width" is not set on the <table> element. For reasons I can't explain, in my project the grid is rendered with no width: <table role="grid" style="width: ;">. Once I resize a column, the width is then calculated (I assume by the Telerik grid code) and then set.. e.g <table role="grid" style="width: 3714.21875;">. Once the width is set on the <table> element, the problem is gone. Resizing a single column doesn't affect any other column. Using the developer tools, I can edit the html and remove the width property and the issue comes back.

To recreate the issue with your sample, try these steps:
1. Run project
2. Resize ALL columns..the goal is that none of the columns widths are the same as what's defined in code.
3. Move column 4 to between column 8 and 9.
4. Save the state.
5. Reload the page.
6. Using the developer tools, delete the width in the <table> element.
7. Resize column 4.

You should see one or more of the other columns width adjusted as well.

I realize that I'm asking you to force the issue by removing the width on the <table> but that seems to be the catalyst. It also seems to require that many of the columns widths are different than their default setting in code.... and it seems to require at least one column having been moved. There was one other difference in my project... I have the grid enclosed in a <div> with style="width:calc(100vw - 30px);"

I wouldn't experience this issue at all if the width property were set on the <table> at the time my page renders but for some reason, it's always null on load.

Hopefully this helps.. I really think the key is the width of the <table> element and how it's used in the code that does the column width calculations.
Dimo
Telerik team
commented on 08 Jul 2021, 01:24 PM | edited

Hi Jeffrey,

I was able to reproduce the problem with the gaps between resized frozen columns. I logged the bug here on your behalf:

https://feedback.telerik.com/blazor/1527048

However, I am still unable to observe the problem with the column resizing itself. The test case with a manually removed table width is not valid, so I hope you will be able to provide a sequence that does not need this step.

On a side note, the initial null width that you see looks weird indeed, and I have notified our developers about it. However, the Grid table often has a null width and that does not cause problems by itself. You can verify this in our online demos.

So the question is - how to reproduce the unexpected multi-column resize in a way that a regular user will experience it? By the way, when you say that several columns change size, do you mean that they resize "gradually" while you drag a single column, or they just snap to a new size and then maintain it? If it is the latter, this may be due to the disappearing gaps between the resized frozen columns. This problem will be fixed when the above logged bug is fixed.

Jeffrey
Top achievements
Rank 2
Iron
Veteran
Iron
commented on 08 Jul 2021, 01:53 PM

Sadly I can't spend any more time on this so I'm just having to disable the ability to rearrange the columns. Thanks for looking into it. With regard to your last question, the columns resize after I finish dragging the single column...and I could recreate the issue even without the "gap" bug. That said, it still requires me to remove the width value in the html to force the problem. Another piece of info you may want to pass on to the developers... I tried manually setting the width in the html immediately after the page rendered to see if that would prevent the issue... but it didn't.
Jeffrey
Top achievements
Rank 2
Iron
Veteran
Iron
commented on 09 Aug 2021, 07:41 PM

I just wanted to comment that the issue I was having with errant columns resizing when other columns where resized has been fixed in the latest version 2.26.0. Whatever fix that was put in place to address the issue with gaps in between frozen columns also fixed the other issue I was having.
Dimo
Telerik team
commented on 10 Aug 2021, 07:01 AM

Jeffrey, thanks for the follow up! I am happy that column resizing is working as expected for you now.

No answers yet. Maybe you can help?

Tags
Grid
Asked by
Jeffrey
Top achievements
Rank 2
Iron
Veteran
Iron
Share this question
or