Telerik Forums
UI for Blazor Forum
2 answers
322 views

Is there a way that I can change attributes on the rendered elements of the Menu and PanelBar components?  I am testing them out of the box with NVDA and JAWS screen readers, and running into issues with how they are read.  I believe part of the issue is how the aria-attributes are being rendered on the controls.

I've been looking at the aria best practices for Menubars (menu equivalent) and TreeViews (PanelBar equivalent), and their recommended approaches for implementation differ from the Telerik component implementations.  For example, on the menu, the the menuitem role is added to an <a> within the <li> tags, and the role of the <li> tags is is set to none.  This seems to work a lot better with NVDA interpreting the component.

The same thing can be said with the PanelBar, setting the <li> role to none when the node contains the <a> element, and the <a> gets a role of treeitem.

Here are the 2 best practices examples I'm referring to:

https://www.w3.org/TR/wai-aria-practices-1.1/examples/treeview/treeview-2/treeview-2a.html

https://www.w3.org/TR/wai-aria-practices-1.1/examples/menubar/menubar-1/menubar-1.html

All that being said, is there some way for me to change these attributes on the component when rendering? I know that there are templates, for me to handle the individual items, and that would take care of the <a>, but I don't see a way to adjust the <ul> and <li> elements rendered automatically by the control.

Also, all of the demos for keyboard support use an ALT-W hotkey.  I can't see where that is set up in the demos, so I could change to a different key if I would like to.  How would I do that?

Hristian Stefanov
Telerik team
 answered on 28 Sep 2021
1 answer
642 views

I've created a generic TelerikGrid component that can handle any model is pass onto it. However, because of this, I cannot enable AutoGenerateColumns, since the model is not specified when the grid is being initialized. Instead, I have to manually define the columns using a variation of the example provided here: https://github.com/telerik/blazor-ui/blob/master/grid/binding-to-expando-object/BindingToExpandoObject/Pages/AutoGeneratedColumns.razor

@inject LocalStorageService _localStorage
@inject GenericHttpEntityService _entityService

@typeparam TItem

<div style="position: relative; width: 100%; min-height: 400px;">
    <TelerikLoaderContainer OverlayThemeColor="light" Visible="@(!IsDoneLoading)"
                            Text="@null" Class="initial-data-loader">
        <Template>
            <TelerikLoader Type="LoaderType.Pulsing" Size="LoaderSize.Large"></TelerikLoader>
        </Template>
    </TelerikLoaderContainer>

    <TelerikGrid Data="@GridData"
                 @ref="@Grid"
                 Height="460px"
                 RowHeight="60"
                 PageSize="10"
                 Pageable="true"
                 Sortable="true"
                 Resizable="true"
                 FilterMode="GridFilterMode.FilterMenu"
                 EditMode="GridEditMode.Popup"
                 OnRead="@ReadEntity"
                 OnStateInit="@((GridStateEventArgs<object> args) => OnStateInitHandler(args))"
                 OnStateChanged="@((GridStateEventArgs<object> args) => OnStateChangedHandler(args))">
        <GridColumns>
            @if (GridData != null && GridData.Any())
            {
                var firstItem = GridData.First();
                var dictionary = firstItem.GetType().GetProperties().ToDictionary(prop => prop.Name, prop => prop.GetValue(firstItem, null));

                foreach (var (key, value) in dictionary)
                {
                    if (value == null)
                    {
                        continue;
                    }

                    <GridColumn Field="@key" FieldType="@value.GetType()"></GridColumn>
                }
            }
        </GridColumns>
    </TelerikGrid>
</div>


@code {
    // Grid data
    private List<object> GridData { get; set; } = new();
    private int Total { get; set; }

    // Loading
    bool IsDoneLoading { get; set; }

    // Grid state
    TelerikGrid<object> Grid { get; set; }
    string StorageKey { get; set; }

    // Parameters
    [Parameter]
    public bool MaintainState { get; set; }
    [Parameter]
    public TItem Entity { get; set; }

    protected override void OnInitialized()
    {
        StorageKey = $"{typeof(TItem).Name}GridState";
    }

    private async Task ReadEntity(GridReadEventArgs args)
    {
        var data = await _entityService.GetAll<TItem>(args.Request);

        GridData = data.Records.Cast<object>().ToList();
        Total = data.Total;

        IsDoneLoading = true;
    }

    async Task OnStateInitHandler(GridStateEventArgs<object> args)
    {
        if (!MaintainState) return;

        try
        {
            var state = await _localStorage.GetItem<GridState<object>>(StorageKey);
            if (state != null)
            {
                args.GridState = state;
            }
        }
        catch (InvalidOperationException)
        {
    // The JS Interop for the local storage cannot be used during pre-rendering
    // so the code above will throw. Once the app initializes, it will work fine.
        }
    }

    async void OnStateChangedHandler(GridStateEventArgs<object> args)
    {
        if (!MaintainState) return;

        await _localStorage.SetItem(StorageKey, args.GridState);
    }
}

The problem with this is that the visibility of the columns can't be defined in the model with annotations like [Display(AutoGenerated = false)]. Is there any way to do what I want to achieve here?

Nadezhda Tacheva
Telerik team
 answered on 28 Sep 2021
2 answers
434 views

I have built my own component, GenericGrid, which under the hood uses a TelerikGrid. The GenericGrid takes TItem as typeparam which gets passed onto a generic HTTP method that retrieves records from an OData API based on the TItem that gets passed on.

GenericGridTest.razor:

@page "/GenericGrid" @using IndiciaStage.Domain.Entities <GenericGrid TItem="Employee"></GenericGrid> @code { }

 

GenericGrid.razor:

@using Indicia.Grid.Services
@using System.Collections.ObjectModel
@using IndiciaStage.Domain.Entities

@inject LocalStorageService _localStorage
@inject GenericHttpEntityService _entityService

@typeparam TItem

<TelerikGrid @ref="@Grid"
             AutoGenerateColumns="true"
             Height="460px"
             RowHeight="60"
             PageSize="10"
             Pageable="true"
             Sortable="true"
             Resizable="true"
             FilterMode="GridFilterMode.FilterMenu"
             EditMode="GridEditMode.Popup"
             OnRead="@ReadEntity"
             OnStateInit="@((GridStateEventArgs<object> args) => OnStateInitHandler(args))"
             OnStateChanged="@((GridStateEventArgs<object> args) => OnStateChangedHandler(args))">
    <GridColumns>
        <GridAutoGeneratedColumns />
    </GridColumns>
</TelerikGrid>


@code {
    // Grid data
    private List<TItem> GridData { get; set; } = new();
    private int Total { get; set; }
    
    // Parameters
    [Parameter]
    public TItem Entity { get; set; }

    private async Task ReadEntity(GridReadEventArgs args)
    {
        var data = await _entityService.GetAll<TItem>(args.Request);

        GridData = data.Records;
        Total = data.Total;

        StateHasChanged();
    }

 

EntityListResponse.cs (based on the OData Grid sample on GitHub, made generic):

    public class EntityListResponse<T>
    {
        [System.Text.Json.Serialization.JsonPropertyName("value")]
        public List<T> Records { get; set; }
        
        [System.Text.Json.Serialization.JsonPropertyName("@odata.count")]
        public int Total { get; set; }
    }

 

GetAll method in GenericHttpEntityService.cs:

        public async Task<EntityListResponse<T>> GetAll<T>(DataSourceRequest request)
        {
            var name = typeof(T).Name;
            var baseUrl = $"{name}s?";

            var requestUrl = $"{baseUrl}{request.ToODataString()}";

            var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl);
            requestMessage.Headers.Add("Accept", "application/json");
            var client = HttpClient.CreateClient("IndiciaStageApi");
            var response = await client.SendAsync(requestMessage);

            if (response.IsSuccessStatusCode)
            {
                var body = await response.Content.ReadAsStringAsync();

                var options = new JsonSerializerOptions();
                options.Converters.Add(new JsonStringEnumConverter());
                var oDataResponse = JsonSerializer.Deserialize<EntityListResponse<T>>(body, options);

                return oDataResponse;
            }
            else
            {
                throw new HttpRequestException(
                    "Request failed. I need better error handling, e.g. returning empty data.");
            }
        }

 

What I want to achieve is for the grid columns to be generated automatically based on the object type, Employee in this case, and the retrieved data to be bound to the grid. Sadly, this doesn't seem to work

As you can see, the JSON is deserialized correctly into an EntityListResponse of type Employee. However, I don't know how to bind the data to the grid and autogenerate its corresponding columns. I tried adding Data="@GridData" to the TelerikGrid, but that returns an error because the type of GridData is List<TItem>.

Is there any way to implement what I'm trying to achieve?

Radko
Telerik team
 answered on 28 Sep 2021
1 answer
1.5K+ views

Hi,

I was wondering what is the best approach to strip out the HTML of a text field that is displayed in a Blazor Datagrid.

I tried using the Template feature along with MarkupString as shown below but it just returns the name of the field rather than the contents of it.

<TelerikGrid Data="Model.CurrentPageData" TotalCount="Model.TotalItemCount" OnRead="ReadItems" Pageable="true" PageSize="10" Groupable="true" Sortable="false">
    <GridColumns>
        <GridColumn Field="@(nameof(Escalation.EscalationId))" Title="Escalation ID" Width="120px" />
        <GridColumn Field="@(nameof(Escalation.CaseType))" Title="Type" Width="120px" />
        <GridColumn Field="@(nameof(Escalation.SummaryOfRequest))" Title="Request Summary" Width="120px" />
            <Template>
                    @((MarkupString)(nameof(Escalation.SummaryOfRequest)))               
            </Template>
        </GridColumn>
        <GridColumn Field="@(nameof(Escalation.PrimaryBu))" Title="Primary BU" Width="120px" />
        <GridColumn Field="@(nameof(Escalation.CreatedDate))" Title="Created" DisplayFormat="{0:dddd, dd MMM yyyy}" Width="120px" />
    </GridColumns>
</TelerikGrid>


Matthias
Top achievements
Rank 5
Bronze
Bronze
Iron
 answered on 28 Sep 2021
2 answers
1.2K+ views

 

Currently, I am using Listview for binding, Whereas I couldn't able to bind the selected Value in the list.

Hence, I need Dual ListBox for moving data from one listbox to another one.

Could you please on this.

 

 

Thanks

Vishnu

Nadezhda Tacheva
Telerik team
 answered on 27 Sep 2021
1 answer
1.6K+ views

Hello, 

I have the following data model which I want to display in TelerikGrid.

The columns should be Name, Price (which is easy), but I also want to display the topping columns, where each caption is the key of the dicionary entry and the displayed value should be the value from the dictionary entry:

Expected result:

Name     |    Price      |      Tomato       |    Cheese       |     Bacon

Cheese  |   8.99         |     low               |   very much   |   no

Tomato  |   5.99        |     very much   |  not so much  |   no

Bacon     |   10.99      |     low               |  not so much  |   three pieces

 

Is that possible by using the TelerikGrid and how should the data binding look like ?

I took the sample code from the expando sample to create the columns based on the dictionary entries

but I didn't get the values from the dictionary to display each value in the rows.

 

public class Pizza
    {
        public string Name { get; set; }

        public decimal Price { get; set; }

        public IDictionary<string, string> Toppings { get; set; }


        public static IList<Pizza> PizzaRecipies()
        {
            return new List<Pizza>()
            {
                new Pizza()
                {
                    Name = "Cheese",
                    Price = 8.99M,
                    Toppings = new Dictionary<string, string>()
                    {
                        {"Tomato","low"},
                        {"Cheese", "very much"},
                        {"Bacon", "no"}
                    }
                },
                new Pizza()
                {
                    Name = "Tomato",
                    Price = 5.99M,
                    Toppings = new Dictionary<string, string>()
                    {
                        {"Tomato","very much"},
                        {"Cheese", "not so much"},
                        {"Bacon", "no"}
                    }
                },
                new Pizza()
                {
                    Name = "Bacon",
                    Price = 10.99M,
                    Toppings = new Dictionary<string, string>()
                    {
                        {"Tomato","low"},
                        {"Cheese", "not so much"},
                        {"Bacon", "three pieces"}
                    }
                }

            };
        }
    }


Radko
Telerik team
 answered on 27 Sep 2021
1 answer
304 views

Great to see the new Gantt feature in update 2.26.  We immediately starting implementation for tracking our publishing stages at Microsoft for shipping software updates to show the parallelism of the processes and easily identify the relative time each stage takes.  This is a great improvement over a list in a table.   

Sadly, the current implementation of Gantt only supports days whilst our publishing stages take only a few minutes or hours.

I'm hoping additional support for a minutes view is coming soon as we had to shelve implementation of a Gantt view of publishing stages using your Gantt chart for the time being.  If it's not coming, an announcement of it's in the road map plan or not coming would be greatly appreciated by your marketing team.

Nadezhda Tacheva
Telerik team
 answered on 27 Sep 2021
1 answer
251 views

Where a DropDownList is populated dynamically, and mandatory, it makes sense for there to be an option to automatically default to the first item in the list.  Especially as there may only be one item in the list, or the first item may account for 99% of cases.

It would be great if this could be done via a simple property:  DefaultToFirst="true".

Svetoslav Dimitrov
Telerik team
 answered on 27 Sep 2021
1 answer
332 views
I have a project with a grid and a context menu.  When I right click on a grid cell, I create a contextual menu based on the name in the grid row.  Then when I run the await ContextMenuRef.ShowAsync(mouseEventArgs.ClientX, mouseEventArgs.ClientY); command, the menu is from the previous right click and previous row.  The actions performed based on the menu choice happen for the right row but the menu itself, it shows previous values.  I have included my mock project for your perusal.  Click on Invoices to get to the page with the problem.
Radko
Telerik team
 answered on 24 Sep 2021
1 answer
230 views

Hi everybody,

What I would like to achieve is to split a container in 2 halfs, then after selecting one of the two halfs to have the posibility to split the selected half agin in other two halfs, and so on.

I was thinking to use the Splitter component for this kind of things having two buttons: one for splitting vertically, and one for splitting horizontally which when one is pressed do the split of the selected container, but I can't understand how can I do this because in all your examples the splitters are already defined. How can this be done dynamically?

Can anyone help me?

Best regards.
Cipri

Nadezhda Tacheva
Telerik team
 answered on 24 Sep 2021
Narrow your results
Selected tags
Tags
+? more
Top users last month
Chester
Top achievements
Rank 1
Iron
Simon
Top achievements
Rank 1
Iron
Douglas
Top achievements
Rank 2
Iron
Iron
SUNIL
Top achievements
Rank 3
Iron
Iron
Iron
Marco
Top achievements
Rank 3
Iron
Iron
Iron
Want to show your ninja superpower to fellow developers?
Top users last month
Chester
Top achievements
Rank 1
Iron
Simon
Top achievements
Rank 1
Iron
Douglas
Top achievements
Rank 2
Iron
Iron
SUNIL
Top achievements
Rank 3
Iron
Iron
Iron
Marco
Top achievements
Rank 3
Iron
Iron
Iron
Want to show your ninja superpower to fellow developers?
Want to show your ninja superpower to fellow developers?