Telerik Forums
UI for ASP.NET Core Forum
1 answer
486 views

I have a grid defined as such:

@(Html.Kendo().Grid<AuditViewModel>()
    .Name("AuditLogGrid")
    .Columns(columns =>
    {
        columns.Bound(c => c.Id).Hidden(true);
        columns.Bound(c => c.UserId).HtmlAttributes(new { @class = "k-text-right", style = "vertical-align: text-top" });
        columns.Bound(c => c.TableName).HtmlAttributes(new { @class = "k-text-right", style = "vertical-align: text-top" });
        columns.Bound(c => c.AuditType).HtmlAttributes(new { @class = "k-text-right", style = "vertical-align: text-top" });
        columns.Bound(c => c.KeyValuesValue).Encoded(false).HtmlAttributes(new { @class = "k-text-right", style = "vertical-align: text-top" });
        columns.Bound(c => c.OldValuesValue).Encoded(false).HtmlAttributes(new { @class = "k-text-right", style = "vertical-align: text-top" });
        columns.Bound(c => c.NewValuesValue).Encoded(false).HtmlAttributes(new { @class = "k-text-right", style = "vertical-align: text-top" });
        columns.Bound(c => c.ChangedColumnsValue).HtmlAttributes(new { @class = "k-text-right", style = "vertical-align: text-top" });
    })
    .Pageable(pager => pager.Refresh(true))
    .Sortable()
    .Filterable()
    .NoRecords()
    .DataSource(dataSource => dataSource
        .Ajax()
        .Batch(true)
        .PageSize(10)
        .ServerOperation(true)
        .Events(events => events.Error("error_handler"))
        .Model(model =>
        {
            model.Id(p => p.Id);
            model.Field(p => p.UserId);
            model.Field(p => p.TableName);
            model.Field(p => p.AuditType);
            model.Field(p => p.KeyValuesValue);
            model.Field(p => p.OldValuesValue);
            model.Field(p => p.NewValuesValue);
            model.Field(p => p.ChangedColumnsValue);
        })
        .Read(read => read.Action("GetAuditLogs", "Audit").Data("forgeryToken"))
    ))

And in my "GetAuditLogs" controller methods, I pass in the "request.Page" and "request.PageSize" to calculate Skip and Take.  The EF query call DOES return records (default is set to 10 records) however when returning from the Controller, the Grid displays "No Records"

My controller method is as follows:


[HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> GetAuditLogsAsync([DataSourceRequest] DataSourceRequest request)
    {
        _logger.LogDebug("GetAuditLogsAsync()");
        try
        {
            var logs = await _auditService.GetAsync(null, q => q.OrderByDescending(x => x.DateTime),
                string.Empty, request.Page, request.PageSize);
            var total = await _auditService.CountAsync(null, string.Empty);
            var models = logs.Select(x => new AuditViewModel
            {
                Id = x.Id,
                UserId = x.UserId,
                DateTime = x.DateTime,
                TableName = x.TableName,
                AuditType = x.Type,
                KeyValues = string.IsNullOrWhiteSpace(x.PrimaryKey) ? new Dictionary<string, object>() :
                    JsonSerializer.Deserialize<Dictionary<string, object>>(x.PrimaryKey),
                OldValues = string.IsNullOrWhiteSpace(x.OldValues) ? new Dictionary<string, object>() :
                    JsonSerializer.Deserialize<Dictionary<string, object>>(x.OldValues),
                NewValues = string.IsNullOrWhiteSpace(x.NewValues) ? new Dictionary<string, object>() :
                    JsonSerializer.Deserialize<Dictionary<string, object>>(x.NewValues),
                ChangedColumns = string.IsNullOrWhiteSpace(x.AffectedColumns) ? new List<string>() :
                    JsonSerializer.Deserialize<List<string>>(x.AffectedColumns)
            });

            var result = await models.ToDataSourceResultAsync(request);
            result.Total = total;
            return Json(result);
        }
        catch (Exception ex)
        {
            _logger.LogError($"GetAuditLogsAsync() | error [{ex}]", ex);
            throw;
        }
    }

And the Audit Service "GetAsync" looks like:


public async Task<IEnumerable<Data.Entities.Audit>> GetAsync(
        Expression<Func<Data.Entities.Audit, bool>>? filter = null,
        Func<IQueryable<Data.Entities.Audit>, IOrderedQueryable<Data.Entities.Audit>>? orderBy = null,
        string includeProperties = "",
        int page = 0,
        int pageSize = 0)
    {
        IQueryable<Data.Entities.Audit> query = _dbSet;
        if (filter != null)
        {
            query = query.Where(filter);
        }

        if (!string.IsNullOrWhiteSpace(includeProperties))
        {
            query = includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                .Aggregate(query, (current, includeProperty) => current.Include(includeProperty));
        }

        var result = orderBy != null
            ? orderBy(query)
            : query;

        if (page > 0 && pageSize > 0)
        {
            result = result.Skip((page - 1) * pageSize).Take(pageSize);
        }

        return await result.ToListAsync();
    }

I have verified that the returned results ARE correct (based on Id's), but the Grid displays "No Records".  I'd rather not return the ENTIRE dataset to the grid as it is quite large (and the models can be large - this is for auditing so it contains EVERYTHING that was modified).  Is there something I'm missing?
Mike
Top achievements
Rank 1
Iron
Iron
 answered on 28 May 2023
1 answer
221 views

I have a grid defined as thus:

@(Html.Kendo().Grid<SubServiceViewModel>()
    .Name("SubServiceGrid")
    .Columns(columns =>
    {
        columns.Bound(c => c.Id).Hidden(true);
        columns.Bound(c => c.Service)
            .ClientTemplate("#=Service.Value#")
            .Filterable(false)
            .Sortable(false);
        columns.Bound(c => c.Value);
        columns.Bound(c => c.Active).Hidden(true);
        columns.Bound(c => c.Deleted).Hidden(true);
        columns.Command(c => c.Destroy());
    })
    .ToolBar(toolbar =>
    {
        toolbar.Create();
        toolbar.Save();
    })
    .Editable(editable => editable.Mode(GridEditMode.InCell))
    .Pageable(pager => pager.Refresh(true))
    .Sortable()
    .Filterable()
    .NoRecords()
    .DataSource(dataSource => dataSource
        .Ajax()
        .Batch(true)
        .PageSize(10)
        .ServerOperation(true)
        .Events(events => events.Error("error_handler").RequestEnd("onRequestEnd('staticNotifications')"))
        .Model(model =>
        {
            model.Id(p => p.Id);
            model.Field(p => p.Service).DefaultValue(ViewData["defaultService"] as ServiceViewModel);
            model.Field(p => p.Value);
            model.Field(p => p.Active).DefaultValue(EntityLiterals.Yes);
            model.Field(p => p.Deleted).DefaultValue(EntityLiterals.No);
        })
        .Read(read => read.Action("GetSubServices", "SubService").Data("forgeryToken"))
        .Create(create => create.Action("CreateSubServices", "SubService").Data("forgeryToken"))
        .Update(update => update.Action("UpdateSubServices", "SubService").Data("forgeryToken"))
        .Destroy(destroy => destroy.Action("DeleteSubServices", "SubService").Data("forgeryToken"))
    ))

And if I remove the 

.Filterable(true)

I get a JS error when I click the column filter button


Uncaught TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at C (kendo.all.js:318535:21)
    at init._createForm (kendo.all.js:318535:21)
    at init._init (kendo.all.js:318535:21)
    at init._click (kendo.all.js:318535:21)
    at HTMLAnchorElement.dispatch (jquery.min.js?v=oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl-cbzUq8:2:43184)
    at y.handle (jquery.min.js?v=oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl-cbzUq8:2:41168)
C @ kendo.all.js:318535
_createForm @ kendo.all.js:318535
_init @ kendo.all.js:318535
_click @ kendo.all.js:318535
dispatch @ jquery.min.js?v=oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl-cbzUq8:2
y.handle @ jquery.min.js?v=oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl-cbzUq8:2
However, because I'm using InCell editing, I have a ViewData object populated with my DropDown items (with the UI Hint), similar to the demo.  Is there any way around this?
Mike
Top achievements
Rank 1
Iron
Iron
 answered on 25 May 2023
1 answer
81 views

 

I'm using Trial for testing. But when the number of items is selected more, the text box displaying the item grows larger, breaking the interface of the page. I just want to show the number of selected items (Checked) to replace checked items, is it possible to process? Please guide how. Displays fine both when the event is selected and the initial default load of items is checked.

 

Example:

Mihaela
Telerik team
 answered on 24 May 2023
1 answer
439 views

I would like to create the following type of chart:

I have set the BaseUnit to weeks but the label prints as 10/31, 11/7, 11/14 etc

   @(Html.Kendo().Chart<FlightLog.Models.Charts.HoursByWeek>()
        .Name("chart")
        .Theme("bootstrap")
        .Title("Monthly Hours")
        .Legend(legend => legend
        .Position(ChartLegendPosition.Bottom)
        )
        .DataSource(ds => ds
        .Read(r => r.Url(Url.Page("./DashBoard", "HoursPerWeek")).Type(HttpVerbs.Post))
        )
        .Series(series =>
        {
            series.Column(model => model.Hours).CategoryField("Date");
        })
        .CategoryAxis(axis => axis.Date()
        .Labels(labels => labels.Rotation(-45))
        .Labels(labels => labels.DateFormats(dateFormat => dateFormat.Months("MMM")))
        .BaseUnit(ChartAxisBaseUnit.Weeks)

        .MajorGridLines(lines => lines.Visible(false))
        )
        .ValueAxis(axis => axis
        .Numeric()
        .Line(line => line.Visible(false))
        .MajorGridLines(lines => lines.Visible(true))
        )
        )

Mihaela
Telerik team
 answered on 24 May 2023
1 answer
204 views

Hi,

I have a use case where a user can click on a link or button in a parent record in a Kendo Grid, which causes a Kendo Window to become visible and display within it another Kendo Grid listing the child records corresponding to the record clicked in the parent page.   In this case, the parent  Grid would display a list of Document records;  When the user clicks on a link or button in the row of a particular Document,  a Window pops up with the Version History records for the Document in another Grid. 

Should the Version History Grid be in a partial view, as suggested in https://stackoverflow.com/questions/28772589/load-kendo-grid-in-kendo-window, and then brought into the Window, which is constructed in JavaScript, or is there a better/more standard approach, preferably one that uses html helpers? 

Also, how do I set  it up so that the Grid in the Window only displays Version History pertaining to the Document that was clicked?

If anybody has links to examples/samples that I can research, or can answer my questions, I'd be most appreciative.  I think that similar use cases just use the Grid Hierarchy, but unfortunately it's not an option for my use case.

Thanks!

Taylor

 

Stoyan
Telerik team
 updated answer on 23 May 2023
1 answer
292 views
I have a request to add SharePoint document management to an existing ASP .NET Core web application and since the project already has Telerik UI in it I'd like to use the File Manager component. I can't find any samples or guidance on how I would attempt to achieve this. Is it even possible? 
Alexander
Telerik team
 answered on 23 May 2023
1 answer
398 views

I have a tab strip with several tabs that contains various input fields for a user to modify and I'd like to show some sort of "edit" icon in the header of those tabs which have been modified to give the user a more visual indication of what has been changed before they save any changes.

I can see from the docs that you can set "ImageUrl" or "SpriteCssClasses" on a tab header when setting it up, but in this case, I'm looking at adding/removing images based on changed events from the widgets contained within the tab and can't seem to find any documented way of doing this.

Playing around with things I can do something like the following (where #TabStrip is the name given to my tab strip widget) to add a pencil icon to the header:

$("#TabStrip-tab-1 .k-link").prepend("<span class=\"k-icon k-i-edit\"></span>")

Which will give the following:

This is what I'm after, but I'm ideally looking for a way that is more "official" and supported rather than having to poke around inside the DOM of the tab strip itself.

Is there anything that could be used here or is that JS snippet above the best way to do this?

Aleksandar
Telerik team
 answered on 22 May 2023
1 answer
104 views

I'm having problem setting culture in a calendar called from Grid.
Below is my sample:

<script>
     kendo.culture("@Model.userSetting.culture");
</script>

....

       @(Html.Kendo().Grid<MyProject.Model.ModelName>()
                        .Name("gTasks")
                        .Columns(columns =>
                        {
                            columns.Bound(p => p.Id).Width(100).Visible(false);
                            columns.Bound(p => p.taskID).Width(100).Visible(false);
                            columns.Bound(p => p.Start).Format("{0:" + Model.userSetting.dateFormat + "}").Sortable(true).Width(100).Title("Start").EditorTemplateName("GridCalendarTemplate");
                            columns.Bound(p => p.End).Format("{0:" + Model.userSetting.dateFormat + "}").Sortable(true).Width(100).Title("End").EditorTemplateName("GridCalendarTemplate");
                         })
)

....



   

 

In Views/Shared/EditorTemplates/GridCalendarTemplate.cshtml


@model DateTime?
@{
    var culture = Context.Session.GetString("culture");

}
<script>
    kendo.culture("@culture");
</script>
@(Html.Kendo().DatePickerFor(m => m)
    .Culture("@culture")
    .HtmlAttributes(new { title = Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName("") }))
Unfortunately, the calendar format does not accept culture "pl-PL"
Jacek
Top achievements
Rank 2
Iron
Iron
Iron
 answered on 21 May 2023
1 answer
93 views

Hi Telerik,

I'm back with the next question :).

I have a Kendo Grid displaying Main Orders. This Grid has 2 levels of hierarchy. Each Main Order has at least one order, but can have multiple orders.
Each of these orders has at least one guy working on the order, but there could be multiple people working an this specific order => this is the 2nd level of hierarchy.

As long as the 2nd level contains more than 1 person, everything is fine, everything is unfolding properly and displaying properly.

But when there is only one person in the 2nd level (no matter how many orders in the 1 level), unfolding the 2nd level removes the column headers from 2nd level, and all data from 1st level (the order).

So:
1 main > 1 order > 1 person > error
1 main > 10 orders > 1 person only per order > error
1 main > x orders > 2+ persons > ok

And to make it even more curious, this is not a static issue. It happens at 80% of the entries, but not at all of them.

When the issue appears, My Grid shows the main order perfectly, but it only shows the column headers from level 1, filled with the data of level 2.....

Attached is a picture of the issue. Surrounded in red you will see the issue, one row below, surrounded in yellow, the proper display.

Grid:


@(
Html.Kendo().Grid<UfaMainOrder>()
        .Name("grid")
        .Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName("MainOrderComment"))
        .Columns(columns =>
        {
            columns.Bound(e => e.MainOrderNumber).Width(300).Title("Hauptauftragsnummer").Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true));
            columns.Bound(e => e.InvoiceDateMainOrder).Format("{0: dd.MM.yyyy}").Width(300).Title("Rechnungsdatum (Hauptauftrag)");
            columns.Bound(e => e.TargetFruSum).Width(200).Title("Summe AW Soll");
            columns.Bound(e => e.ActualFruSumEval).Width(200).Title("Summe AW Ist (Bew)");
            columns.Bound(e => e.FruSumDiffEval).Width(200).Width(200).Title("Δ Summe Soll-Ist (Bew)");
            columns.Bound(e => e.MainOrderResearchComment).Width(200).Title("Recherche-Ergebnis").ClientTemplate("#= MainItems_Databound(MainOrderResearchComment)#");
            columns.Command(command => { command.Edit(); }).Width(150).HtmlAttributes(new { style = "text-align: center" });
            columns.Bound(e => e.MainOrderComment).Width(500).Title("Bemerkung");
        })
        .Pageable(p => p
            .ButtonCount(5)
            .PageSizes(new[] { 10, 25, 50 })
            .Refresh(true)
            .Input(true)
        )
        .ColumnResizeHandleWidth(5)
        .ColumnMenu()
        .Sortable()
        .Resizable(resize => resize.Columns(true))
        .Scrollable(s => s.Height("auto"))
        .Filterable()
        .Reorderable(reorder => reorder.Columns(true))
        .ToolBar(toolbar =>
        {
            toolbar.Custom().Text("Import DMS").IconClass("k-icon k-i-file-excel").HtmlAttributes(new { id = "customCommand" });
            toolbar.Custom().Text("Ansicht speichern").IconClass("k-icon k-i-export").HtmlAttributes(new { id = "save" });
            toolbar.Custom().Text("Ansicht laden").IconClass("k-icon k-i-import").HtmlAttributes(new { id = "load" });
            toolbar.Search();

        })
        .ClientDetailTemplateId("template")
        .HtmlAttributes(new { style = "height:600px;" })
        .DataSource(dataSource => dataSource
            .Ajax()
            .ServerOperation(false)
            .PageSize(50)
            .Model(model => 
            {
                model.Id(o => o.MainOrderNumber);
                model.Field(p => p.MainOrderNumber).Editable(false);
                model.Field(p => p.InvoiceDateMainOrder).Editable(false);
                model.Field(p => p.TargetFruSum).Editable(false);
                model.Field(p => p.ActualFruSumEval).Editable(false);
                model.Field(p => p.FruSumDiffEval).Editable(false);
                model.Field(p => p.MainOrderResearchComment).Editable(false);
                model.Field(p => p.MainOrderComment).Editable(true).DefaultValue("");
            })
            .Read("Read", "UFA")
            .Update("Update", "UFA")
        )
        
)

Level 1:


    @(
        Html.Kendo().Grid<UfaOrder>()
                .Name("grid_#=IdMainOrder#")
                .Columns(columns =>
                {
                    columns.Bound(o => o.OrderNumber).Title("Auftragsnummer");
                    columns.Bound(o => o.OrderType).Title("Auftragsart");
                    columns.Bound(o => o.InvoiceNo).Title("Rechnungsnummer");
                    columns.Bound(o => o.InvoiceDate).Format("{0: dd.MM.yyyy}").Title("Rechnungsdatum");
                    columns.Bound(o => o.TotalTargetFru).Title("Summe AW Soll");
                    columns.Bound(o => o.TotalActualFruEval).Title("Summe AW Ist (Bew)");
                    columns.Bound(o => o.TotalFruDiffEval).Title("Summe Δ Soll-Ist (Bew)");
                    columns.Bound(o => o.ResearchComment).Title("Recherchergebnis bei Faktura").ClientTemplate("\\#= LineItems_Databound(ResearchComment)\\#");
                    columns.Bound(o => o.OalComment).Title("Kommentar aus OAL");
                })
                .ClientDetailTemplateId("template2")
                .DataSource(dataSource => dataSource
                    .Ajax()
                    .PageSize(10)
                    @*.Sort(s => s.Add("OrderNumber").Ascending())*@
                    .Read(read => read.Action("ReadOrders", "UFA", new { idMainOrder = "#=IdMainOrder#" })
                    )
                )

                .ToClientTemplate()
        )

Level 2:


    @(Html.Kendo().Grid<UfaOrderMechanic>()
                    .Name("grid_#=IdOrder#")
                    .Columns(columns =>
                    {
                        columns.Bound(o => o.MechanicId).Title("Mitarbeiternummer");
                        columns.Bound(o => o.MechanicName).Title("Mitarbeitername");
                        columns.Bound(o => o.TargetFru).Title("AW Soll");
                        columns.Bound(o => o.ActualFru).Title("AW Ist");
                        columns.Bound(o => o.EvalMirror).Title("Bewertung");
                        columns.Bound(o => o.ActualFruEval).Title("AW Ist (Bew)");
                        columns.Bound(o => o.FruDiffEval).Title("Δ Soll-Ist (Bew)");
                        })
                    .DataSource(dataSource => dataSource
                        .Ajax()
                        .PageSize(10)
                        .Read(read => read.Action("ReadMechanics", "UFA", new { idOrder = "#=IdOrder#" }))
                    )

                    .ToClientTemplate()
            )

 

 

Did you ever see a behaviour like this? Any tipps how to solve this? :)

Thanks
Thomas

Mihaela
Telerik team
 answered on 18 May 2023
0 answers
171 views

Hi,

I'm posting this in case anybody else has had issues with remote validation + grid custom popupeditor + additional field.

I'm working on a grid with a custom PopUpEditor made up of Kendo TextBoxes.  The viewmodel specifies remote validation with an additional field that is in the PopUpEditor.   To implement remote validation, I am following https://demos.telerik.com/aspnet-mvc/grid/editing-remote-validation, including using the javascript custom validation rule.  This demo works well for remote validation without additional fields, but it appears to not generate the data payload correctly if an additional field is specified. 

The code in the demo for creating the data payload is:

    //adding remote rule to handle validation based on Remote attribute set in the model.
    $(document).ready( function () {
        $.extend(true, kendo.ui.validator, {
            rules: {
                remote: function (input) {
                    if (input.val() == "" || !input.attr("data-val-remote-url")) {
                        return true;
                    }

                    if (input.attr("data-val-remote-recieved")) {
                        input.attr("data-val-remote-recieved", "");
                        return !(input.attr("data-val-remote"));
                    }

                    var url = input.attr("data-val-remote-url");
                    var postData = {};
                    postData[input.attr("data-val-remote-additionalfields").split(".")[1]] = input.val();
...

The last line in the above snippet appears to be the problem, because the attribute value is actually in the form "*.Field1,*.Field2" where Field1 is the name of the field to be validated, and Field2 is the additional field specified in the view model.  The resulting array is ["*", "Field1*," "Field2"], and only "Field1*" gets assigned a value.  It's not clear to me why the fields names are rendered in this manner.

The example in https://docs.telerik.com/aspnet-mvc/html-helpers/data-management/grid/how-to/editing/using-remote-validation-in-grid handles the additional fields, as seen in this snippet from the code:

    (function ($, kendo) {
        $.extend(true, kendo.ui.validator, {
            rules: {
                remote: function (input) {
                    if (input.val() == "" || !input.attr("data-val-remote-url")) {
                        return true;
                    }

                    if (input.attr("data-val-remote-recieved")) {
                        input.attr("data-val-remote-recieved", "");
                        return !(input.attr("data-val-remote"));
                    }

                    var url = input.attr("data-val-remote-url");
                    var postData = {};
                    var addFields = input.attr("data-val-remote-additionalfields").replace(/\*./g, "").split(",");
                    $.each(addFields, function (index, val) {
                        postData[val] = $("input[name='" + val + "']").val();
                    });
...
Here, "*." is stripped out of the field names, and the code iterates through the generated array, assigning values.

 

While this code worked for me, if you encounter issues, you can look at https://www.telerik.com/forums/remote-validation-with-additionalfields-when-editing-the-grid.  It has a rule that handles remote validation for a specific field and a specific additional field:

$.extend(true, kendo.ui.validator, {
  rules: {
    remote: function (input) {
      if (input.is("[name=Code]") && input.val()) {
        var productId = $("input[name='Id']").val();
        var productCode = input.val();
        $.ajax({
          url: '@Url.Action("VerifyCode", "Products")',
          type: "GET",
          async: false,
          data: { "ProductCode": productCode, "id": productId},
...

 

Hopefully this information will help out others.  Please feel free to comment with other details or corrections.

Thanks,

Taylor

Taylor
Top achievements
Rank 1
 asked on 17 May 2023
Narrow your results
Selected tags
Tags
+? more
Top users last month
Edmond
Top achievements
Rank 1
Iron
fabrizio
Top achievements
Rank 2
Iron
Veteran
RobMarz
Top achievements
Rank 2
Iron
Fakhrul
Top achievements
Rank 1
Iron
Tejas
Top achievements
Rank 2
Iron
Iron
Iron
Want to show your ninja superpower to fellow developers?
Top users last month
Edmond
Top achievements
Rank 1
Iron
fabrizio
Top achievements
Rank 2
Iron
Veteran
RobMarz
Top achievements
Rank 2
Iron
Fakhrul
Top achievements
Rank 1
Iron
Tejas
Top achievements
Rank 2
Iron
Iron
Iron
Want to show your ninja superpower to fellow developers?
Want to show your ninja superpower to fellow developers?