0

I have a model structured like so:

public int JobID { get; set; }
public int SiteID { get; set; }
public List<AModel> ListAModel { get; set; }

In my main view, I am iterating through the List using a for loop with i as an index. I want to call a partial view from within this main page to avoid repeat code across the system but this partial view needs to be aware of the index number as well as the job id and site id.

I cannot just pass in in Model.ListAModel[i] as this will not be aware of job or site id, and likewise with the other way round.

Any help would be appreciated.

  • You will have to post your code if you need some help – Serge Jun 04 '21 at 10:53
  • Hi @DanielWood, May I know whether the reply has solved the problem or is there any update about this thread? If the answer resolved the issue, kindly accept it - see [What should I do when someone answers my question](https://stackoverflow.com/help/someone-answers). If you have any question about my reply, please let me know freely. – Zhi Lv Jun 21 '21 at 01:10

2 Answers2

0

You can use the ExpandoObject Class that represents an object whose members can be dynamically added and removed at run time. Code below demonstrates how it can be used:

Data model:

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

public class ViewModel
{
    public int JobID { get; set; }
    public int SiteID { get; set; }
    public List<AModel> ListAModel { get; set; }
}

.cshtml:

@model Models.ViewModel
@using System.Dynamic

<div>
    @for (int i=0; i < Model.ListAModel.Count; i++)
    {
        dynamic item = new ExpandoObject();
        item.job = Model.JobID;
        item.site = Model.SiteID;
        item.amodel = Model.ListAModel[i];
        Html.RenderPartial(@"PartialView", (object) item);
    }
</div>

In the partial view:

@using System.Dynamic
@model dynamic
@{
    Models.AModel am = @Model.amodel;
    <div>job id = @Model.job, site id = @Model.site, amodel = @am.Name </div>
}

There are several posts about how to pass parameters to a view dynamically For example:

Dynamic Anonymous type in Razor causes RuntimeBinderException

Jackdaw
  • 7,626
  • 5
  • 15
  • 33
0

In my main view, I am iterating through the List using a for loop with i as an index. I want to call a partial view from within this main page to avoid repeat code across the system but this partial view needs to be aware of the index number as well as the job id and site id.

I cannot just pass in in Model.ListAModel[i] as this will not be aware of job or site id, and likewise with the other way round.

From your description, I assume you want to filter data based on the Job id and site id, then display the AModel via the partial view.

To pass parameters from main page to the partial view, you can use the view-data attribute. Please refer the following sample:

Model:

public class JobViewModel
{
    public int JobID { get; set; }
    public int SiteID { get; set; }
    public List<AModel> ListAModel { get; set; }
}
public class AModel
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int JobID { get; set; }
    public int SiteID { get; set; }
}

Controller:

public IActionResult Index4()
{
    var initialdata = new List<JobViewModel>()
    {
        new JobViewModel(){
        JobID = 1001,
        SiteID = 102,
        ListAModel = new List<AModel>()
            {
                new AModel(){ ID=1, Name="Joe", JobID=1001, SiteID=101},
                new AModel(){ ID=2, Name="Merry", JobID=1001, SiteID=102},
                new AModel(){ ID=3, Name="Henry", JobID=1001, SiteID=103},
                new AModel(){ ID=4, Name="Cody", JobID=1001, SiteID=101},
                new AModel(){ ID=5, Name="Simon", JobID=1001, SiteID=102},
                new AModel(){ ID=6, Name="Leena", JobID=1001, SiteID=103},
                new AModel(){ ID=7, Name="Ode", JobID=1001, SiteID=101},
                new AModel(){ ID=8, Name="Nicky", JobID=1001, SiteID=102},
            }
        }
    };

    return View(initialdata.FirstOrDefault());
}

Main page: using ViewData and view-data attribute to pass parameters.

@model MVCWebApplication.Models.JobViewModel

@{
    ViewData["JobID"] = Model.JobID.ToString();
    ViewData["SiteID"] = Model.SiteID.ToString();
}
<div>
    <h4>JobViewModel</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.JobID)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.JobID)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.SiteID)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.SiteID)
        </dd>
    </dl>
    <div class="form-group">
        <partial name="_AModelPV.cshtml" model="@Model.ListAModel" view-data="ViewData"/>
    </div>
</div>

Partial View (_AModelPV.cshtml): In the partial view, you could also check whether the ViewData exists and contains the value.

@model IEnumerable<MVCWebApplication.Models.AModel>
 
@{ 
    var jobid = Convert.ToInt32(ViewData["JobID"]);
    var siteid = Convert.ToInt32(ViewData["SiteID"]);
}

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.ID)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Name)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.JobID)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.SiteID)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Where(c=>c.JobID == jobid && c.SiteID == siteid).ToList()) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.ID)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.JobID)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.SiteID)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
                @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
                @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
            </td>
        </tr>
}
    </tbody>
</table>

The result like this:

enter image description here

Besides, you could also consider filtering the data before sending data to the main page. For example, in the above action method, filter the data based on the JobID and SiteID, then return the result to the main page. In this scenario, the ListAmodel contains the filtered data, there is no need to do the filter action in the partial view.

    var result = initialdata.Select(c => 
            new JobViewModel { 
            JobID = c.JobID, SiteID = c.SiteID, 
            ListAModel = c.ListAModel.Where(d => d.JobID == c.JobID && d.SiteID == c.SiteID).ToList() })
            .FirstOrDefault();

    return View(result);
Zhi Lv
  • 18,845
  • 1
  • 19
  • 30