I'm trying to get to grips with ViewComponents but having trouble trying to get the ViewComponent to reload on a button click. Whats the correct way to handle this?
Initially on the page loading it looks OK like this
In my controller I have
public IActionResult ReloadViewComponent(int characterRegionId, int materialTypeId)
{
return ViewComponent("MarketOrderComponent", new { characterRegionId, materialTypeId});
}
and in my razor view I'm passing parameters to the ReloadViewComponent method
<td><button class="btn btn-sm btn-outline-primary" value="@material.MaterialTypeID" onclick="location.href='@Url.Action("ReloadViewComponent", "BlueprintBreakdown", new { Model.CharacterRegionId, material.MaterialTypeID })'">View</button></td>
full razor view
<body>
<div class="row" style="margin-top:5px;">
<div class="col-lg-4 col-md-12">
<div class="card" style="margin-bottom:0; ">
<div class="header" style="margin-bottom:55px;">
<h2 class="text-primary">Blueprint Breakdown</h2>
</div>
<div class="body">
<div>
<h5 class="text-center">@Model.BlueprintName</h5>
</div>
<div class="row text-center">
<div class="col-6 border-right pb-4 pt-4" style="padding-top:0px !important; padding-bottom:0px !important;">
<img src="@Model.ImageUrl" alt="@Model.BlueprintName">
</div>
<div class="col-6 pb-4 pt-4" style="padding-top:0px !important; padding-bottom:0px !important;">
<img src="@Model.ProductImageUrl" alt="@Model.BlueprintName">
</div>
</div>
<div class="text-center" style="margin-top:5px;">
<text style="font-size:small;">Material Quantity Based on Manufacturing Efficiency</text>
<br />
<text style="font-size:small;">Price Based on Lowest Region Market Sell Orders</text>
<br />
<text style="font-size:small;">Current Region is <span class="text-green">@Model.CharacterRegionName</span></text>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover table-custom spacing5">
<thead>
<tr>
<th></th>
<th>Material</th>
<th>Quantity</th>
<th>Price</th>
<th>Market</th>
</tr>
</thead>
<tbody>
@foreach (var material in Model.RequiredMaterials)
{
<tr class="text-cente" style="font-size:small;">
<td><img src="@(String.Format("{0}{1}{2}", "https://imageserver.eveonline.com/Type/", material.MaterialTypeID, "_32.png"))" /></td>
<td>@material.TypeName</td>
<td>@material.Quantity</td>
<td>@material.MaterialCost</td>
<td><button class="btn btn-sm btn-outline-primary" value="@material.MaterialTypeID" onclick="location.href='@Url.Action("ReloadViewComponent", "BlueprintBreakdown", new { Model.CharacterRegionId, material.MaterialTypeID })'">View</button></td>
</tr>
}
</tbody>
</table>
</div>
</div>
<div class="col-lg-8 col-md-12">
@await Component.InvokeAsync("MarketOrderComponent", new { Model.CharacterRegionId, Model.RequiredMaterials.First().MaterialTypeID })
</div>
</div>
but when clicking the view button to reload the ViewComponent it is rendered like this.
Note by using the ViewComponent()
controller method, your client only gets the component part of the view. So instead of changing the browser's current location, you should send an ajax request and dynamically replace the right side content.
Add an id='MarketOrderComponent'
attribute so that we can reference this element later:
<div id='MarketOrderComponent' class="col-lg-8 col-md-12"> @await Component.InvokeAsync("MarketOrderComponent", new { Model.CharacterRegionId, Model.RequiredMaterials.First().MaterialTypeID }) </div>
And change the button click event handler to send an ajax request. For example, in order to reload the market order component, you can change your code as below:
<script>
function reload(url){
return $.ajax({
method:"get",
url:url,
success:function(resp){ $('#MarketOrderComponent').html(resp);},
});
}
</script>
<div class="card" style="margin-bottom:0; ">
...
</div>
<div class="table-responsive">
...
<tbody>
@foreach (var material in Model.RequiredMaterials)
{
<tr class="text-cente" style="font-size:small;">
<td><img src="@(String.Format("{0}{1}{2}", "https://imageserver.eveonline.com/Type/", material.MaterialTypeID, "_32.png"))" /></td>
<td>@material.TypeName</td>
<td>@material.Quantity</td>
<td>@material.MaterialCost</td>
<td>
<button class="btn btn-sm btn-outline-primary"
value="@material.MaterialTypeID"
onclick="var link='@Url.Action("ReloadViewComponent", "BlueprintBreakdown", new { Model.CharacterRegionId, material.MaterialTypeID })'; event.preventDefault(); reload(link)"
>
View
</button>
</td>
</tr>
}
</tbody>
...
</div>
<div id='MarketOrderComponent' class="col-lg-8 col-md-12">
@await Component.InvokeAsync("MarketOrderComponent", new { Model.CharacterRegionId, Model.RequiredMaterials.First().MaterialTypeID })
</div>