The code looks like MVC ASP.NET Framework. In MVC 2+ The child action solves this problem.
https://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx/
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
I have an asp.net mvc View Report.cshtml that is a report and displays info from many classes. For most of the report I put info into arrays then do loops on the page to get the values from the arrays. There are two sections that I thought I would try to use partial views on because each one loops 16 times and each section has similar layout but different info. I need to pass a parameter so that I can call a method to get the data for each iteration. I tried to use partial views and pass the value of the parameter to the view by using
var model = new Competency
{ Dimension = i };
@Html.Partial("CompPage",model)
This never hits the controller so it always comes back empty.
Then I tried Html.Action
@Html.Action("CompPage", "CareerCompetency", new { Dimension = i, HideScores, CompStanine = CompStanine[i], NarrativeIcon = NarrativeIcon[i] })
and also Html.RenderAction.
{Html.RenderAction("CompPage", "CareerCompetency", new { Dimension = i, HideScores, CompStanine = CompStanine[i], NarrativeIcon = NarrativeIcon[i] });}
While I can see the value being passed to the controller with both Html.Action and Html.RenderAction, it comes back as 404 when it tries to display the parent view.
Is there a way to do this with partial views or do I just go back to getting the info on calling controller and putting into arrays?
Here is the PartialView CompPage
@model VHRC.Models.Competency
@{
bool HideScores = (bool)ViewData["HideScores"];
string Stanine = ViewData["CompStanine"].ToString();
string NarrativeIcon = ViewData["NarrativeIcon"].ToString();
}
<div class="section-divider">
<div class="section Med20">
<div class="row">
<div class="section-name">@Html.DisplayFor(model => model.CompetencyText)</div>
</div>
</div>
</div>
<div class="row section">
<div class="dimension-image">
<img src="~/Images/ReportGraphics/V2/CarComp/@NarrativeIcon" alt="">
</div>
<div class="competency-text">
@Html.DisplayFor(model => Model.Narrative)
</div>
</div>
<div class="row section">
<div class="Med2024">Key Behaviors</div>
<div class="behaviors">
<ul>
@foreach (var behavior in Model.Behaviors)
{
<li><strong>@Html.Raw(behavior.BehaviorHeading)</strong>
<ul>
@foreach (var item in behavior.BehaviorItem)
{
<li>@Html.Raw(item.BehaviorText)</li>
}
</ul>
</li>
}
</ul>
</div>
<div class="narrative-score">
@if (!HideScores)
{
<img src="~/Images/ReportGraphics/V2/Narratives/Scores/blue_score_@(Stanine).png" alt="">
}
</div>
</div>
Here is the controller for that (after I tried using Action and RenderAction)
public PartialViewResult CompPage(int? Dimension, bool HideScores, int CompStanine, string NarrativeIcon)
{
try
{
Competency comp = new Competency();
if (Dimension == null)
{
return null;
}
Competency model = comp.GetCompetency((int)Dimension);
ViewData["CompStanine"] = CompStanine;
ViewData["NarrativeIcon"] = NarrativeIcon;
ViewData["HideScores"] = HideScores;
return PartialView(model);
}
catch (Exception ex)
{
Errors.ErrorOccured(ex);
}
return null;
}
The code looks like MVC ASP.NET Framework. In MVC 2+ The child action solves this problem.
https://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx/
Issue: You're trying to use partial views in your ASP.NET MVC Report.cshtml
to handle repetitive sections. While using Html.Partial
doesn't invoke the controller (resulting in empty data), Html.Action
leads to a 404 error.
Solution: Use Html.Partial
by preparing all necessary data in your main view's model. This approach avoids extra controller calls and prevents the 404 error.
Steps:
Update Your ViewModel:
Create a main ReportViewModel
that includes all data needed for the partial views.
public class ReportViewModel
{
public bool HideScores { get; set; }
public List<int> CompStanine { get; set; }
public List<string> NarrativeIcon { get; set; }
public List<CompetencyPartialViewModel> Competencies { get; set; }
}
public class CompetencyPartialViewModel
{
public Competency Competency { get; set; }
public int CompStanine { get; set; }
public string NarrativeIcon { get; set; }
public bool HideScores { get; set; }
}
Populate ViewModel in Controller:
In your controller action, populate the ReportViewModel
with all necessary data.
public ActionResult Report()
{
var model = new ReportViewModel
{
HideScores = /* your logic */,
CompStanine = /* populate list */,
NarrativeIcon = /* populate list */,
Competencies = new List<CompetencyPartialViewModel>()
};
for (int i = 0; i < 16; i++)
{
var competency = Competency.GetCompetency(i);
model.Competencies.Add(new CompetencyPartialViewModel
{
Competency = competency,
CompStanine = model.CompStanine[i],
NarrativeIcon = model.NarrativeIcon[i],
HideScores = model.HideScores
});
}
return View(model);
}
Use Html.Partial
in Your Main View (Report.cshtml
):
Loop through the Competencies
and render the partial view with the prepared data.
@model YourNamespace.ViewModels.ReportViewModel
@foreach (var comp in Model.Competencies)
{
@Html.Partial("CompPage", comp)
}
Update Partial View (CompPage.cshtml
):
Modify the partial view to use the CompetencyPartialViewModel
.
@model YourNamespace.ViewModels.CompetencyPartialViewModel
<div class="section-divider">
<div class="section Med20">
<div class="row">
<div class="section-name">@Html.DisplayFor(m => m.Competency.CompetencyText)</div>
</div>
</div>
</div>
<div class="row section">
<div class="dimension-image">
<img src="~/Images/ReportGraphics/V2/CarComp/@Model.NarrativeIcon" alt="">
</div>
<div class="competency-text">
@Html.DisplayFor(m => m.Competency.Narrative)
</div>
</div>
<div class="row section">
<div class="Med2024">Key Behaviors</div>
<div class="behaviors">
<ul>
@foreach (var behavior in Model.Competency.Behaviors)
{
<li>
<strong>@Html.Raw(behavior.BehaviorHeading)</strong>
<ul>
@foreach (var item in behavior.BehaviorItem)
{
<li>@Html.Raw(item.BehaviorText)</li>
}
</ul>
</li>
}
</ul>
</div>
<div class="narrative-score">
@if (!Model.HideScores)
{
<img src="~/Images/ReportGraphics/V2/Narratives/Scores/blue_score_@Model.CompStanine.png" alt="">
}
</div>
</div>
Benefits of Using Html.Partial
:
Alternative (If Controller Logic Is Needed): Ensure your CareerCompetencyController
and CompPage
action are correctly named and accessible.
public class CareerCompetencyController : Controller
{
public PartialViewResult CompPage(int Dimension, bool HideScores, int CompStanine, string NarrativeIcon)
{
var model = Competency.GetCompetency(Dimension);
ViewData["CompStanine"] = CompStanine;
ViewData["NarrativeIcon"] = NarrativeIcon;
ViewData["HideScores"] = HideScores;
return PartialView(model);
}
}
Controller
.CompPage.cshtml
is in Views/CareerCompetency/
or Views/Shared/
.Conclusion: Using Html.Partial
with a well-structured view model is the most efficient way to render partial views without encountering controller-related issues. This approach ensures better performance and easier maintenance.Issue:
You're trying to use partial views in your ASP.NET MVC Report.cshtml
to handle repetitive sections. While using Html.Partial
doesn't invoke the controller (resulting in empty data), Html.Action
leads to a 404 error.
Solution:
Use Html.Partial
by preparing all necessary data in your main view's model. This approach avoids extra controller calls and prevents the 404 error.
Steps:
Update Your ViewModel:
Create a main ReportViewModel
that includes all data needed for the partial views.
public class ReportViewModel
{
public bool HideScores { get; set; }
public List<int> CompStanine { get; set; }
public List<string> NarrativeIcon { get; set; }
public List<CompetencyPartialViewModel> Competencies { get; set; }
}
public class CompetencyPartialViewModel
{
public Competency Competency { get; set; }
public int CompStanine { get; set; }
public string NarrativeIcon { get; set; }
public bool HideScores { get; set; }
}
Populate ViewModel in Controller:
In your controller action, populate the ReportViewModel
with all necessary data.
public ActionResult Report()
{
var model = new ReportViewModel
{
HideScores = /* your logic */,
CompStanine = /* populate list */,
NarrativeIcon = /* populate list */,
Competencies = new List<CompetencyPartialViewModel>()
};
for (int i = 0; i < 16; i++)
{
var competency = Competency.GetCompetency(i);
model.Competencies.Add(new CompetencyPartialViewModel
{
Competency = competency,
CompStanine = model.CompStanine[i],
NarrativeIcon = model.NarrativeIcon[i],
HideScores = model.HideScores
});
}
return View(model);
}
Use Html.Partial
in Your Main View (Report.cshtml
):
Loop through the Competencies
and render the partial view with the prepared data.
@model YourNamespace.ViewModels.ReportViewModel
@foreach (var comp in Model.Competencies)
{
@Html.Partial("CompPage", comp)
}
Update Partial View (CompPage.cshtml
):
Modify the partial view to use the CompetencyPartialViewModel
.
@model YourNamespace.ViewModels.CompetencyPartialViewModel
<div class="section-divider">
<div class="section Med20">
<div class="row">
<div class="section-name">@Html.DisplayFor(m => m.Competency.CompetencyText)</div>
</div>
</div>
</div>
<div class="row section">
<div class="dimension-image">
<img src="~/Images/ReportGraphics/V2/CarComp/@Model.NarrativeIcon" alt="">
</div>
<div class="competency-text">
@Html.DisplayFor(m => m.Competency.Narrative)
</div>
</div>
<div class="row section">
<div class="Med2024">Key Behaviors</div>
<div class="behaviors">
<ul>
@foreach (var behavior in Model.Competency.Behaviors)
{
<li>
<strong>@Html.Raw(behavior.BehaviorHeading)</strong>
<ul>
@foreach (var item in behavior.BehaviorItem)
{
<li>@Html.Raw(item.BehaviorText)</li>
}
</ul>
</li>
}
</ul>
</div>
<div class="narrative-score">
@if (!Model.HideScores)
{
<img src="~/Images/ReportGraphics/V2/Narratives/Scores/blue_score_@Model.CompStanine.png" alt="">
}
</div>
</div>
Benefits of Using Html.Partial
:
Alternative (If Controller Logic Is Needed): Ensure your CareerCompetencyController
and CompPage
action are correctly named and accessible.
public class CareerCompetencyController : Controller
{
public PartialViewResult CompPage(int Dimension, bool HideScores, int CompStanine, string NarrativeIcon)
{
var model = Competency.GetCompetency(Dimension);
ViewData["CompStanine"] = CompStanine;
ViewData["NarrativeIcon"] = NarrativeIcon;
ViewData["HideScores"] = HideScores;
return PartialView(model);
}
}
Controller
.CompPage.cshtml
is in Views/CareerCompetency/
or Views/Shared/
.