KendoUI SignalR grid not update if data is posed via ajax in my ASP.NET Core 5 web application

Viewed 88

I have a KendoUI grid which uses SignalR. Whilst the grid itself works fine if you update the data inline or incell, it doesn't work if I update the data in a form which uses ajax to post it to my controller.

It was my understanding that, if I injected my hub into my controller and then called (whichever I needed, create, update or destroy) :

await _fixtureHub.Clients.All.SendAsync("update", model);

or

await _fixtureHub.Clients.All.SendAsync("update", model);

That it would tell the clients that the data had been changed/created and the grid would update to reflect that change. This isn't happening however and I'm wondering what I've done wrong or missing.

To start, here is my signalR bound grid.

$('#fixture_grid').kendoGrid({
    dataSource: {            
        schema: {
            model: {
                id: "Id",
                fields: {
                    Created_Date: {
                        type: "date"
                    },
                    Commencement_Date: {
                        type: "date"
                    } 
                }
            }
        },
        type: "signalr",
        autoSync: true,            
        transport: {
            signalr: {
                promise: fixture_hub_start,
                hub: fixture_hub,
                server: {
                    read: "read",
                    update: "update",
                    create: "create",
                    destroy: "destroy"
                },
                client: {
                    read: "read",
                    update: "update",
                    create: "create",
                    destroy: "destroy"
                }
            }
        }
    },
    autoBind: true,
    sortable: true,
    editable: false,
    scrollable: true,
    columns: [
        {
            field: "Created_Date",
            title: "Created",
            format: "{0:dd/MM/yyyy}"                
        },
        {
            field: "Commencement_Date",
            title: "Commencement",
            format: "{0:dd/MM/yyyy}"                
        },
        {
            field: "Charterer",
            template: "#if(Charterer !=null){# #=Charterer_Name# #} else { #--# }#"
        },
        {
            field: "Region",
            template: "#if(Region !=null){# #=Region_Name# #} else { #--# }#"
        }
    ]
});

Here is the relative hub for that grid:

var fixture_url = "/fixtureHub";

var fixture_hub = new signalR.HubConnectionBuilder().withUrl(fixture_url, {
    transport: signalR.HttpTransportType.LongPolling
}).build();

var fixture_hub_start = fixture_hub.start({
    json: true
});

Here is the KendoUI wizard with form integration which I update the grid with, this form can process either a creation or an update data, this is achieved by checking the Id that is passed in. Whereby 0 equals new and >0 is existing.

function wizard_fixture() {
    let wizard_name = "#wizard-fixture";

    //Load Wizard
    $(wizard_name).kendoWizard({
        pager: true,
        loadOnDemand: true,
        reloadOnSelect: false,
        contentPosition: "right",
        validateForms: true,
        deferred: true,
        actionBar: true,
        stepper: {
            indicator: true,
            label: true,
            linear: true
        },
        steps: [
            {
                title: "Step 01",
                buttons: [                                  
                {
                    name: "custom",
                    text: "Save & Continue",                      
                    click: function () {
                        let wizard = $(wizard_name).data("kendoWizard");
                        var validatable = $(wizard_name).kendoValidator().data("kendoValidator");
                        if (validatable.validate()) {
                            $.ajax({
                                type: "POST",
                                traditional: true,
                                url: "/Home/Process_Fixture",
                                data: $(wizard_name).serialize(),
                                success: function (result) {
                                   ...do stuff                                        
                                },
                                error: function (xhr, status, error) {
                                    console.log("error")
                                }
                            });
                        }                            
                    }
                }
            ],
                form: {
                    formData: {
                        Id: fixtureviewmodel.Id,
                        Created_User: fixtureviewmodel.Created_User,
                        Created_Date: fixtureviewmodel.Created_Date,
                        Connected: fixtureviewmodel.Connected
                    },                   
                    items: [
                    {
                        field: "Fixture_Id",
                        label: "Id",
                        editor: "<input type='text' name='Id' id='Fixture_Id' /> "
                    },
                    {
                        field: "Created_User",
                        label: "Created user",
                        editor: "<input type='text' name='Created_User' id='Created_User_Fixture' />"

                    },
                    {
                        field: "Created_Date",
                        id: 'Created_Date_Fixture',
                        label: "Created date",
                        editor: "DatePicker",            
                        
                    }
               ]
            }
        },
        
    ],

});

I've shortened this to demonstrate the custom button and the ajax posting that happens to Process_Fixture. Here is my controller which handles that:

public async Task<JsonResult> Process_Fixture(Fixture model)
    {
        if (model.Id == 0)
        {
            if (ModelState.IsValid)
            {
              
                var fixture = await _fixture.CreateAsync(model);
                Update connected clients
                await _fixtureHub.Clients.All.SendAsync("create", model);
                return Json(new { success = true, data = fixture.Id, operation = "create" });                    
            }
            return Json(new { success = false });
        }
        else
        {               
            var fixture = await _fixture.UpdateAsync(model);
            await _fixtureHub.Clients.All.SendAsync("update", model);
            return Json(new { success = true, data = fixture.Id, operation = "update" });
        }
    }

As you can see, I have injected my hub and I have called the "create" message to it which I believed would force the grid to update with whatever had changed or been created.

Here is the hub itself:

public class FixtureHub : DynamicHub
{
    private readonly IRepository<Fixture> _fixtures;
    private readonly IRepository<ViewGridFixtures> _viewFixtures;

    public FixtureHub(IRepository<Fixture> fixtures, IRepository<ViewGridFixtures> viewFixtures)
    {
        _fixtures = fixtures;
        _viewFixtures = viewFixtures;
    }
    public override Task OnConnectedAsync()
    {
        Groups.AddToGroupAsync(Context.ConnectionId, GetGroupName());
        return base.OnConnectedAsync();
    }
    public override Task OnDisconnectedAsync(Exception e)
    {
        Groups.RemoveFromGroupAsync(Context.ConnectionId, GetGroupName());
        return base.OnDisconnectedAsync(e);
    }

    public class ReadRequestData
    {
        public int ViewId { get; set; }
    }
    public IQueryable<ViewGridFixtures> Read()
    {
        IQueryable<ViewGridFixtures> data = _viewFixtures.GetAll();
        return data;
    }

    public string GetGroupName()
    {
        return GetRemoteIpAddress();
    }
    public string GetRemoteIpAddress()
    {
        return Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString();
    }
}

I need some help here in understanding how I can tell the hub that the update/create/destroy has been called and it needs to do something. At the moment, I feel like injecting the hub and then calling the clients.all.async isn't the right way. With ajax it seems to ignore it and I wonder if the two technologies are working against each other.

0 Answers
Related