ListView Model Items Not Populate

2 Answers 27 Views
Grid ListView
Mehmet
Top achievements
Rank 1
Iron
Mehmet asked on 12 Mar 2024, 11:21 AM

Hi There,

I have a complex model in view.  But, i sended simple example for subject.

 

Main View Model : 

public class ErpProductModel
{
    public string Title { get; set; }
    public string Code { get; set; }
    public string ShortCode { get; set; }
    public int MinStock { get; set; }
    public int ShelfLife { get; set; }
    public int CategoryId { get; set; }
    public int TaxCategoryId { get; set; }
    public decimal AmountInProduct { get; set; }
    public int MeasureWeightId { get; set; }
    public int CountryId { get; set; }
    public int StatusId { get; set; }
    public List<ErpProductPackageTypeModel>? PackageTypes { get; set; } = [];
}

PackageTypes Model : 

public record ErpProductPackageTypeModel 
{
    public int? ProductId { get; set; }
    public string Barcode { get; set; }
    public int Quantity { get; set; }
    public string? PackageType { get; set; }
    public int PackageTypeId { get; set; }

    public List<SelectListItem> AvailablePackageTypes { get; set; } = [];
}

View Source :


<script type="text/x-kendo-tmpl" id="packageTypeTemplate">
         <div class="card widget widget-info">
             <div class="card-body">
                 <div class="widget-info-container">
                     <div class="widget-info-image" style="background: url('@Url.Content("/Assets/Images/barcode_mock.png")')"></div>
                     <h5 class="widget-info-title">#=Barcode#</h5>
                     <p class="widget-info-text">#=PackageType# / #=Quantity# PCS</p>
                 </div>
             </div>
         </div>
</script>

@(Html.Kendo().ListView<ErpProductPackageTypeModel>()
            .Name("package-types")
            .BindTo((IEnumerable<ErpProductPackageTypeModel>)Model.PackageTypes)
            .TagName("div")
            .Bordered(false)
            .Layout("grid")
            .Grid(p=> p.Cols(4).Gutter(20))
            .ClientTemplateId("packageTypeTemplate")
            .HtmlAttributes(new { @class= "rubi-listview package-types" })
            .DataSource(dataSource => 
                dataSource.Ajax()
                .Batch(true)
                .ServerOperation(false))
            )

 

Controller Post Method :


[HttpPost]
public virtual async Task<IActionResult> EditAsync(ErpProductModel model)
{
    var erpProduct = await _erpProductService.GetErpProductAsync(model.Id);
    if (erpProduct == null)
        return RedirectToAction("List");
    erpProduct = model.ToEntity(erpProduct);

    await _erpProductService.UpdateErpProductAsync(erpProduct);

    return RedirectToAction("Edit", new { id = erpProduct.Id });
}
When the page is first opened, data is filled into the listview control. No problem here. But when I do a post operation again, the PackageTypes in the model are not filled. In fact, it does not even appear in the first data that arrives. I couldn't figure out why. I only want a Client Side transaction.

My scenario is simple;
I have a product save screen. There are package types depending on this product. If all I want is to fill the package types, I will make various updates, additions or deletions on this data.

Thank you in advance for your help.
Mehmet
Top achievements
Rank 1
Iron
commented on 15 Mar 2024, 09:19 AM

Why do we need to get a telerik license? No support, no community!

2 Answers, 1 is accepted

Sort by
0
Mehmet
Top achievements
Rank 1
Iron
answered on 15 Mar 2024, 09:38 AM
Thank you for the answer. But what you say prevents us from creating a flexible structure.

Why would I need a telerik component if I can't connect a list within the model to a listview or grid?

It's a simple request. It's not a very complicated or abnormal situation. A model with a 1 to many relationship.

If I were to detail the scenario:
I want to receive dynamically created records used as Model.XXXXX[i].Item when posting.

I studied a lot of the examples you sent. They are not enough.

I'm waiting for your help. Thanks.
Alexander
Telerik team
commented on 18 Mar 2024, 09:15 AM

Hi Mehmet,

Since you have instantiated a separate support thread that could not be shared with the community. I am sending over my reply here so that the discussion is more transparent and is potentially helpful to people as well:

"

If the Grid is the main parent component and the ListView/Grid resides within a template, then the binding process would be more intricate, as you would have to manually map the corresponding collections field.

Regardless, I would recommend employing a custom approach with the Grid component being the main operand for the collections field. Please allow me to go through the approach in a more decoupled manner:

  • Within the Parent Grid create a custom PopUp partial view that will be the nested Grid. The Editor Template follows the "~/Views/Shared/EditorTemplates" folder convention, so it has to be stored there:
.Editable(editable=>editable // Parent Grid
      .Mode(GridEditMode.PopUp)
      .TemplateName("CustomPopup")
      .Window(window => window.Width(1000))
)
  • Subscribe to the Parent Grid's Edit event and store the to-be-edited model within a global flag variable. This operation is of utmost importance, as we will use this variable later on for programmatically updating the collection:
.Events(events => events.Edit("onEdit")) // Parent Grid

<script type="text/javascript">
    var model;

    function onEdit(e) {
        model = e.model;
        ...
    }
</script>
  • Within the EditorTemplate, declare a Grid that will be held responsible for storing the collections field. During the declaration, make sure to provide a .Data() API configuration to the read method for passing meta-information. In the case of your scenario, this would be the parent Grid's primary key identifier:
@model ErpProductModel

...

<div class="k-edit-field">

    @(Html.Kendo().Grid<ErpProductPackageTypeModel>()
         .Name("packageTypes")
         ...
         .AutoBind(false) // Make sure that the Grid is not automatically bound.
         ...
         .Events(events => events.Save("onSave"))
         .DataSource(dataSource => dataSource
             .Ajax()
             .Read(read => read.Action("Get_ProductTypes", "Home").Data("additionalData"))
             .PageSize(10)
             .Model(model=>
             {
                 model.Id(p => p.ProductId);
                 model.Field(p => p.ProductId).Editable(false);
             })
         )
         .ToClientTemplate()
)
</div>
  • Within the previously defined parent edit handler, programmatically read the child Grid's data by using the dataSource.read() method of the child Grid:
.Read(read => read.Action("Get_ProductTypes", "Home").Data("additionalData")) // Child Grid.

			 
<script>
    function onEdit(e) {
        model = e.model;

        setTimeout(function(){ // Ensure the Popup Window is fully rendered.
            $("#packageTypes").getKendoGrid().dataSource.read(); // Will invoke the additionalData handler declared for the Child Grid.
        })
    }
	
	
	function additionalData(e) {
        return {
            parentId: model.ProductId // Pass the parent Grid Id as meta-information.
        }
    }
</script>
  • Subscribe to the child Grid's Save event and manually update the "PackageTypes" field of the parent Grid:
.Events(events => events.Save("onSave")) // Child Grid.

			 
<script>
    function onSave(e){
        model.set("PackageTypes", e.sender.dataSource._data);
    }
</script>
  • Within the parent Grid, ensure that the "PackageTypes" field is displayed in a convenient manner. This can be achieved via the Columns.Bound.ClientTemplate() API configuration:
<script>
    function packagesTypes(packages) {
        var template = "<ul>";
        for (var i = 0; i < packages.length; i++) {
            template += "<li>" + packages[i].Barcode + "</li>";
        }
        template += "</ul>";
        return template;
    }
</script>

.Columns(columns =>
{
      columns.Bound(e => e.PackageTypes).ClientTemplate("#=packagesTypes(PackageTypes)#"); 
})

The aforementioned result would then supplement the collections field to the remote endpoint of its predecessor:

Where the updated changes will also be reflected in the UI as well:

"

For the benefit of the community, I am also attaching the sample application, where the scenario can be examined in a more runnable manner.

-1
Alexander
Telerik team
answered on 15 Mar 2024, 09:26 AM

Hi Mehmet,

Thank you for reaching out.

I noticed that the Grid is also marked as one of the target components you currently have employed on your side. Could you please verify this?

Regardless, generally speaking, the DataSource supports flat data as it strives to follow conventional normalization principles such as:

  • Atomicity
  • Data Integrity
  • Functional dependencies

To some extent, it aims to further reduce data redundancy and eliminate undesirable characteristics. In terms of your scenario, I see that you have set up a One-To-Many relationship between the different entities.

With that in mind, if the Grid will be the main resident from which will perform the CRUD operations, the mapping will not be done automatically due to the aforementioned design of the DataSource.

Instead, here it would be to appropriate to consider incorporating CRUD operations for the ListView as a separate logic unit. We have an existing demo which showcases such a scenario that I personally think you might find insightful in this regard:

ListView Editing (Demo) - open the "View Source" tab to observe the ListView's configuration.

From there, since you already have knowledge of the parent field, you can map the changes on the server-side based on your requirements.

However, my personal recommendation here would be to consider leveraging the Grid's Hierarchy capabilities, as it is accustomed to such a scenario as well:

Grid Hierarchy (Demo) - open the "View Source" tab to observe the utilized Grid configuration.

We have an available Hierarchy CRUD operations scenario within our GitHub repository dedicated to such examples:

GitHub Repository - https://github.com/telerik/ui-for-aspnet-core-examples

To spare you some time, here are the established code compartments for the example:

Please let me know if these options prove suitable.

Kind Regards,
Alexander
Progress Telerik

Stay tuned by visiting our public roadmap and feedback portal pages. If you're new to the Telerik family, be sure to check out our getting started resources, as well as the only REPL playground for creating, saving, running, and sharing server-side code.
Mehmet
Top achievements
Rank 1
Iron
commented on 15 Mar 2024, 09:41 AM

Thank you for the answer. But what you say prevents us from creating a flexible structure.

Why would I need a telerik component if I can't connect a list within the model to a listview or grid?

It's a simple request. It's not a very complicated or abnormal situation. A model with a 1 to many relationship.

If I were to detail the scenario:
I want to receive dynamically created records used as Model.XXXXX[i].Item when posting.

I studied a lot of the examples you sent. They are not enough.

I'm waiting for your help. Thanks.
Tags
Grid ListView
Asked by
Mehmet
Top achievements
Rank 1
Iron
Answers by
Mehmet
Top achievements
Rank 1
Iron
Alexander
Telerik team
Share this question
or