Telerik Forums
UI for Blazor Forum
1 answer
48 views
The CSS in the travel template works perfectly fine, however in VS2022, I am not getting any intellisense from the CSS at all. When I do class="" and whether I hit the space bar to load intellisense for suggestions, or do CTRL+SPACE I don't get anything. I am usually getting "dismiss" but that is about it. Nothing from reset.css in the wwwroot/common folder or the styles.css from wwwroot/landing/travel are showing either. I am noticing that the CSS in the App.razor file are being received from the unpkg.com link instead of everything being downloaded right to the project and referenced directly. How do I get this all to work? Can I download these files and reference them directly or can I only use unpkg? Does this even work with unpkg?
Dimo
Telerik team
 answered on 11 Dec 2024
1 answer
80 views

I was following this example here.

                    <GridColumn Field=@nameof(BookingEquipmentModel.FirstRequestedEquipmentType) Title="1st Requested" Editable="true" Filterable="false" Width="7rem">
                        <EditorTemplate>
                            @{
                                _currentBookingEquipmentModel = context as BookingEquipmentModel;
                                <TelerikDropDownList Data="@_equipmentTypeList"
                                                     @bind-Value="@_currentBookingEquipmentModel.FirstRequestedEquipmentTypeId"
                                                     TextField="@nameof(EquipmentTypeModel.Code)"
                                                     ValueField="@nameof(EquipmentTypeModel.EquipmentTypeId)"
                                                     DefaultText="Select Type">
                                    <DropDownListSettings>
                                        <DropDownListPopupSettings Height="auto" />
                                    </DropDownListSettings>
                                </TelerikDropDownList>
                            }
                        </EditorTemplate>
                    </GridColumn>

Grid EditMode set to GridEditMode.Inline and Column is Editable = True.  _equipmentTypeList is populated in OnAfterRenderAsync.  It's behaving as if it's just a normal read only column?

Rob.

Rob
Top achievements
Rank 3
Iron
Iron
Iron
 updated answer on 11 Dec 2024
1 answer
51 views
Unable to execute events on the TelerikSvgIcon control?
                   <FormItem Field="@nameof(User.Password)">
                       <Template>
                           <TelerikTextBox @bind-Value="@user.Password"
                                           Size="@ThemeConstants.TextBox.Size.Large"
                                           Placeholder="ContraseƱa"
                                           ShowSuffixSeparator="false"
                                           Password="@IsPasswordHidden">
                               <TextBoxSuffixTemplate>
                                   <TelerikSvgIcon 
                                       Icon="@SvgIcon.Eye" 
                                       Size="@ThemeConstants.SvgIcon.Size.Medium"
                                       onmousedown="@(() => MostrarPassword())"
                                       onmouseup="@(() => OcultarPassword())"
                                       onmouseleave="@(() => OcultarPassword())">
                                   </TelerikSvgIcon>
                                </TextBoxSuffixTemplate>
                           </TelerikTextBox>
                       </Template>
                   </FormItem>
Thanks
Hristian Stefanov
Telerik team
 answered on 09 Dec 2024
0 answers
107 views

I am trying to use Telerik Blazor Scheduler to display a Google Calendar.  Need to be able to add, edit, delete events from Scheduler.  Need to be able to manage recurrence events.  I am new to Telerik Scheduler and running into a few issues that might be easily spotted to someone else.

The code will connect to the Google Calendar API and access the data.  There is issues with recurrence event as they do not stop when the "UNTIL" directs the event to stop.  They go on forever.  Also issues when it comes when updating and adding new events that need to be set as recurring.

- There is one recurring event in the Google Calendar that is set for Wed Dec 4 2024  1:15PM to 2:15PM.  Set to repeat on Wednesdays  and set to stop on 12/12/24.  So it is really only 2 Wednesdays 12/4 and 12/11.  Scheduler is showing this event every Wednesday forever.
- Also, based on the Console output, it looks like it is pulling the information twice upon page load.
- In Postman, the api seems to show the output correctly.

- If you try to create a new event or update an event with recurrence settings, you get an error.  You can add/update a non-recurring event just fine.

Below is the code.  (You may see some trial code and debuging items as I have been trying to figure out why)

Any help you can provide would be greatly appriciated.


RAZOR PAGE: 

@page "/gscheduler"
@rendermode RenderMode.InteractiveServer
@using Telerik.Blazor
@using Telerik.Blazor.Components
@using Telerik.Blazor.Components.Scheduler
@inject GSchedulerService GSchedulerService

<TelerikRootComponent>
    <TelerikScheduler Height="600px"
                      @bind-Date="@StartDate"
                      @bind-View="@CurrView"
                      Data="@GSchedulerService.Appointments"
                      OnUpdate="OnUpdateHandler"
                      OnCreate="OnCreateHandler"
                      OnDelete="OnDeleteHandler"
                      AllowCreate="true"
                      AllowDelete="true"
                      AllowUpdate="true"
                      IdField="@(nameof(GSchedulerDto.Id))"
                      RecurrenceRuleField="@(nameof(GSchedulerDto.RecurrenceRule))"
                      RecurrenceExceptionsField="@(nameof(GSchedulerDto.RecurrenceExceptions))"
                      RecurrenceIdField="@(nameof(GSchedulerDto.RecurrenceId))">
        <SchedulerViews>
            <SchedulerDayView StartTime="@DayStart" />
            <SchedulerWeekView StartTime="@DayStart" />
            <SchedulerMultiDayView StartTime="@DayStart" />
            <SchedulerMonthView></SchedulerMonthView>
            <SchedulerTimelineView StartTime="@DayStart" />
            <SchedulerAgendaView></SchedulerAgendaView>
        </SchedulerViews>
    </TelerikScheduler>
</TelerikRootComponent>

@code {
    private DateTime StartDate { get; set; } = DateTime.Today;
    private SchedulerView CurrView { get; set; } = SchedulerView.Week;
    private DateTime DayStart { get; set; } = new DateTime(2000, 1, 1, 7, 0, 0);

   // Initialize Scheduler Data
    protected override async Task OnInitializedAsync()
   {
        await GSchedulerService.InitializeAppointmentsAsync();

   }

    // Create Event Handler
    private async Task OnCreateHandler(SchedulerCreateEventArgs args)
    {
        if (args?.Item is GSchedulerDto newItem)
        {
            await GSchedulerService.CreateEventAsync(newItem);
        }
    }

    // Update Event Handler
    private async Task OnUpdateHandler(SchedulerUpdateEventArgs args)
    {
        if (args?.Item is GSchedulerDto updatedItem)
        {
            await GSchedulerService.UpdateEventAsync(updatedItem);
        }
    }

    // Delete Event Handler
    private async Task OnDeleteHandler(SchedulerDeleteEventArgs args)
    {
        if (args?.Item is GSchedulerDto itemToDelete && await GSchedulerService.ConfirmDeletionAsync())
        {
            await GSchedulerService.DeleteEventAsync(itemToDelete.Id);
        }
    }
}

 

CS file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Configuration;
using Microsoft.JSInterop;
using Telerik.SvgIcons;

public class GSchedulerService
{
    private readonly IConfiguration _configuration;
    private readonly IJSRuntime _jsRuntime;

    public List<GSchedulerDto> Appointments { get; private set; } = new();

    public GSchedulerService(IConfiguration configuration, IJSRuntime jsRuntime)
    {
        _configuration = configuration;
        _jsRuntime = jsRuntime;
    }


    public async Task InitializeAppointmentsAsync()
    {
        await LoadEventsAsync();
        // await PrintEventsAsync();
    }



    public async Task LoadEventsAsync()
    {

        var service = await GetCalendarServiceAsync();
        var events = await service.Events.List(_configuration["Google:CalendarId"]).ExecuteAsync();

        foreach (var e in events.Items)
        {
            Console.WriteLine($"Event: {e.Summary}");
            Console.WriteLine($"Start: {e.Start.DateTime ?? DateTime.Parse(e.Start.Date)}");
            Console.WriteLine($"End: {e.End.DateTime ?? DateTime.Parse(e.End.Date)}");
            Console.WriteLine($"Recurrence Rule: {e.Recurrence?.FirstOrDefault()}");
            Console.WriteLine($"Recurrence ID: {e.RecurringEventId}");
            Console.WriteLine($"Description: {e.Description}");
            Console.WriteLine(new string('-', 40));
        }

        Appointments = events.Items.Select(e => new GSchedulerDto
        {
            Id = e.Id,
            Title = e.Summary,
            Description = e.Description,
            Start = e.Start.DateTime ?? DateTime.Parse(e.Start.Date),
            End = e.End.DateTime ?? DateTime.Parse(e.End.Date),
            RecurrenceRule = FormatRecurrenceRuleForDisplay(e.Recurrence?.FirstOrDefault()),
            RecurrenceId = e.RecurringEventId // Make sure to assign RecurrenceId
        }).ToList();



    }


    public async Task PrintEventsAsync()
    {
        var service = await GetCalendarServiceAsync();
        var events = await service.Events.List(_configuration["Google:CalendarId"]).ExecuteAsync();

        foreach (var e in events.Items)
        {
            Console.WriteLine($"Event: {e.Summary}");
            Console.WriteLine($"Start: {e.Start.DateTime ?? DateTime.Parse(e.Start.Date)}");
            Console.WriteLine($"End: {e.End.DateTime ?? DateTime.Parse(e.End.Date)}");
            Console.WriteLine($"Recurrence Rule: {e.Recurrence?.FirstOrDefault()}");
            Console.WriteLine($"Recurrence ID: {e.RecurringEventId}");
            Console.WriteLine($"Description: {e.Description}");
            Console.WriteLine(new string('-', 40));
        }
    }


    public async Task CreateEventAsync(GSchedulerDto appointment)
    {
        var service = await GetCalendarServiceAsync();

        var newEvent = new Event
        {
            Summary = appointment.Title,
            Description = appointment.Description,
            Start = new EventDateTime
            {
                DateTime = appointment.Start,
                TimeZone = "UTC"
            },
            End = new EventDateTime
            {
                DateTime = appointment.End,
                TimeZone = "UTC"
            },
            Recurrence = !string.IsNullOrEmpty(appointment.RecurrenceRule)
                ? new List<string> { SanitizeRecurrenceRule(appointment.RecurrenceRule) }
                : null
        };

        Console.WriteLine($"Creating event with recurrence rule: {newEvent.Recurrence?.FirstOrDefault()}");

        await service.Events.Insert(newEvent, _configuration["Google:CalendarId"]).ExecuteAsync();
        await LoadEventsAsync();
    }

    public async Task UpdateEventAsync(GSchedulerDto appointment)
    {
        var service = await GetCalendarServiceAsync();

        var existingEvent = await service.Events.Get(_configuration["Google:CalendarId"], appointment.Id).ExecuteAsync();
        existingEvent.Summary = appointment.Title;
        existingEvent.Description = appointment.Description;
        existingEvent.Start = new EventDateTime
        {
            DateTime = appointment.Start,
            TimeZone = "UTC"
        };
        existingEvent.End = new EventDateTime
        {
            DateTime = appointment.End,
            TimeZone = "UTC"
        };
        existingEvent.Recurrence = !string.IsNullOrEmpty(appointment.RecurrenceRule)
            ? new List<string> { SanitizeRecurrenceRule(appointment.RecurrenceRule) }
            : null;

        Console.WriteLine($"Updating event with recurrence rule: {existingEvent.Recurrence?.FirstOrDefault()}");

        await service.Events.Update(existingEvent, _configuration["Google:CalendarId"], appointment.Id).ExecuteAsync();
        await LoadEventsAsync();
    }



    public async Task DeleteEventAsync(string eventId)
    {
        var service = await GetCalendarServiceAsync();
        await service.Events.Delete(_configuration["Google:CalendarId"], eventId).ExecuteAsync();
        await LoadEventsAsync();
    }

    public async Task<bool> ConfirmDeletionAsync()
    {
        return await _jsRuntime.InvokeAsync<bool>("confirm", "Are you sure you want to delete this event?");
    }

    private async Task<CalendarService> GetCalendarServiceAsync()
    {
        var initializer = new ClientSecrets
        {
            ClientId = _configuration["Google:ClientId"],
            ClientSecret = _configuration["Google:ClientSecret"]
        };

        var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
            initializer,
            new[] { CalendarService.Scope.Calendar },
            _configuration["Google:User"],
            CancellationToken.None);

        return new CalendarService(new BaseClientService.Initializer
        {
            HttpClientInitializer = credential,
            ApplicationName = _configuration["Google:ApplicationName"]
        });
    }

    private string SanitizeRecurrenceRule(string rule)
    {
        if (string.IsNullOrEmpty(rule))
            return null;

        // Normalize case and remove extra spaces
        rule = rule.ToUpperInvariant().Trim();
        rule = Regex.Replace(rule, @"\s+", " "); // Remove extra spaces

        // Ensure the rule starts with "RRULE:"
        if (!rule.StartsWith("RRULE:"))
            rule = "RRULE:" + rule;

        // Handle UNTIL formatting
        var untilMatch = Regex.Match(rule, @"UNTIL=(\d{8}T\d{6}Z)");

        if (untilMatch.Success)
        {
            // If UNTIL exists, ensure it is correctly formatted
            var untilValue = untilMatch.Groups[1].Value;
            if (!DateTime.TryParseExact(untilValue, "yyyyMMdd'T'HHmmss'Z'", null, System.Globalization.DateTimeStyles.AdjustToUniversal, out _))
            {
                throw new FormatException($"Invalid UNTIL format: {untilValue}. Expected format is 'YYYYMMDDTHHMMSSZ'.");
            }
        }
        else if (!rule.Contains("COUNT=")) // If neither UNTIL nor COUNT is present, add a default UNTIL
        {
            var defaultUntil = DateTime.UtcNow.AddYears(1).ToString("yyyyMMdd'T'HHmmss'Z'");
            rule += $";UNTIL={defaultUntil}";
        }

        // Optionally validate additional fields like FREQ, INTERVAL, COUNT, etc.
        return rule;
    }

    private string FormatRecurrenceRuleForDisplay(string rule)
    {
        if (string.IsNullOrEmpty(rule))
            return string.Empty;

        // Remove the "RRULE:" prefix for display purposes
        rule = rule.StartsWith("RRULE:") ? rule.Substring(6) : rule;

        // Convert the UNTIL field to a human-readable format
        var untilMatch = Regex.Match(rule, @"UNTIL=(\d{8}T\d{6}Z)");
        if (untilMatch.Success)
        {
            var untilValue = untilMatch.Groups[1].Value;
            if (DateTime.TryParseExact(untilValue, "yyyyMMdd'T'HHmmss'Z'", null, System.Globalization.DateTimeStyles.AdjustToUniversal, out var untilDate))
            {
                // Replace the UNTIL field with a readable format
                rule = rule.Replace($"UNTIL={untilValue}", $"UNTIL={untilDate:yyyyMMddTHHmmssZ}");
            }
        }

        Console.WriteLine($"Formatted Recurrence Rule: {rule}");
        return rule;
    }





}
public class GSchedulerDto
{
    public string Id { get; set; }
    public string Title { get; set; }

    public string Description { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public bool IsAllDay { get; set; }
    public string RecurrenceRule { get; set; }
    public string RecurrenceId { get; set; }
    public string RecurrenceExceptions { get; set; }

    //  public List<DateTime>? RecurrenceExceptions { get; set; }
    public string RecurrenceType { get; set; } // Recurrence type: Daily, Weekly, Monthly, Yearly
    public int Interval { get; set; }          // Interval for recurrence (e.g., every X days/weeks)
    public int? Count { get; set; }            // Number of occurrences (optional)
    public DateTime? Until { get; set; }       // End date for recurrence (optional)

    public string ByDay { get; set; } // Optional: Specific days (e.g., "MO,WE,FR")
    public int? ByMonthDay { get; set; } // Optional: Specific day of the month
    public int? ByMonth { get; set; } // Optional: Specific month

}

 

CONSOLE OUTPUT:

Event: test
Start: 12/4/2024 1:15:00 PM
End: 12/4/2024 2:15:00 PM
Recurrence Rule: RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20241212T045959Z;BYDAY=WE
Recurrence ID:
Description:
----------------------------------------
Formatted Recurrence Rule: FREQ=WEEKLY;WKST=SU;UNTIL=20241212T045959Z;BYDAY=WE
Event: test
Start: 12/4/2024 1:15:00 PM
End: 12/4/2024 2:15:00 PM
Recurrence Rule: RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20241212T045959Z;BYDAY=WE
Recurrence ID:
Description:
----------------------------------------
Formatted Recurrence Rule: FREQ=WEEKLY;WKST=SU;UNTIL=20241212T045959Z;BYDAY=WE

                            
Rob
Top achievements
Rank 1
 asked on 07 Dec 2024
1 answer
488 views

Hi!

I have a Grid inside a Tile. Sometimes, the rows increase making the Grid taller than that Tile's height. There is no visual cue when that happens. How to get scrollbars to appear in this case? The Grid doesn't sense the limitation of parent's (Tile) height and keeps increasing its heigh without showing scroll bars. In case of over-sized content, Tile should show scroll bars.

Dimo
Telerik team
 updated answer on 06 Dec 2024
1 answer
75 views

Hello

We are looking for ways to export the UI Blazor TreeList to Excel. I don't see it in Demos and Documentation. Do you have any suggestions on how to accomplish this? Any code examples you can provide?

 

Thank you!

Min-Jie

Hristian Stefanov
Telerik team
 answered on 03 Dec 2024
1 answer
70 views

On the Telerik website, more specifically on Blazor Charts and Graphs - Overview, you can find a nice example of how to change the theme of the charts displayed. We would like to implement something like this in our project. However, a change in the theme affects the entire project. However, we would like the entire project not to be changed and the change in the theme only affects the Telerik chart.

I would like to know if anyone has a good idea for us.

Hristian Stefanov
Telerik team
 answered on 02 Dec 2024
1 answer
56 views

Hi,

Is there a way to set the Y-axis culture directly within the chart? I prefer not to apply the culture globally.

Thank you,
Omar

Hristian Stefanov
Telerik team
 answered on 02 Dec 2024
1 answer
52 views

Hi,

I have chart within child component, the chart is create dynamically.

After populating the chart, I would like to clear it. How to clear the chart? 

Thanks,

Omar


<TelerikChart  @ref="GNChart">

    <ChartSeriesItems>
        @{
            var swedishCulture = new CultureInfo("sv-SE");
        }
        @foreach(var group in ChartData.Select(c=>c.text).Distinct().ToList())
        {
            <ChartSeries Type="ChartSeriesType.Line"
            Data="@ChartData.Where(c=>c.text==group)"
            Name="@group"
            Field="@nameof(ChartDataClass.value)"
            CategoryField="@nameof(ChartDataClass.month)">

                <ChartSeriesTooltip Visible="true">
                    <Template>
                        <TelerikSvgIcon Icon="SvgIcon.InfoCircle" />
                        @((context.DataItem as ChartDataClass).value.ToString("N0", swedishCulture)) |   @((context.DataItem as ChartDataClass).text)
                    </Template>
                </ChartSeriesTooltip>

            </ChartSeries>
        }

        <ChartValueAxes>
            <ChartValueAxis Color="purple">
                <ChartValueAxisLabels Format="{0:N0}"></ChartValueAxisLabels>
            </ChartValueAxis>
        </ChartValueAxes>


    </ChartSeriesItems>

    <ChartTitle Text="Quarterly revenue per product" Visible="false"></ChartTitle>

    <ChartLegend Position="ChartLegendPosition.Bottom">
    </ChartLegend>
</TelerikChart>

Hristian Stefanov
Telerik team
 answered on 02 Dec 2024
1 answer
166 views

I have a Telerik Grid and it freezes when it has almost 3k rows. I have identified two reasons for that.

One: I have put custom margin and padding on cell-level. Suggest me some efficient way to achieve this style without hitting the performance issues

Second: I have a TelerikSplitButton in one of my columns which makes it more slower.


But even removing above two things, plain TelerikGrid still takes about 2-3 seconds to load only 3k rows.

I have pagination on my grid but pagination sizes cannot be very smaller. I need to show Datasets in thousands or more.

Suggest me some best approaches to achieve this with custom design and template.

Hristian Stefanov
Telerik team
 answered on 02 Dec 2024
Narrow your results
Selected tags
Tags
+? more
Top users last month
Rob
Top achievements
Rank 3
Iron
Iron
Iron
Atul
Top achievements
Rank 1
Iron
Iron
Alexander
Top achievements
Rank 1
Veteran
Iron
Serkan
Top achievements
Rank 1
Iron
Shawn
Top achievements
Rank 1
Iron
Iron
Want to show your ninja superpower to fellow developers?
Top users last month
Rob
Top achievements
Rank 3
Iron
Iron
Iron
Atul
Top achievements
Rank 1
Iron
Iron
Alexander
Top achievements
Rank 1
Veteran
Iron
Serkan
Top achievements
Rank 1
Iron
Shawn
Top achievements
Rank 1
Iron
Iron
Want to show your ninja superpower to fellow developers?
Want to show your ninja superpower to fellow developers?