Load specific portion of the view on click using ViewComponent - c#

In my cshtml file
#foreach (var item in ViewBag.allFontCategory)
{
<a asp-controller="Fonts" asp-action="GetFonts" asp-route-id="#item.Item1" class="font-category-name">#item.Item2</a><br />
}
<div class="col-lg-8" id="font-viewcomponent">
#* Display fonts*#
</div>
In my js file
var url = '/Fonts/GetFonts/';
$('.font-category-name').click(function () {
$('#font-viewcomponent').load(url);
});
In my controller
public IActionResult Index()
{
ViewBag.allFontCategory = dataService.getAllFontCategory();
return View();
}
public IActionResult GetFonts(int id)
{
return ViewComponent("FontAdmin");
}
I am trying to update the content of #font-viewcomponent div element when clicking on the anchor tag helper using ASP.NET Core MVC's ViewComponent.
When I implement same thing with partial view in MVC5, it works good. But with ASP.NET Core MVC's ViewComponent it would not work and return the Defalut.cshtml file as separate view not load as specific portion of the view.

Related

ASP.NET - PartialView continues using layout

I have a checkout flow consisting of several steps. For performance reasons I work with ajax partial updates, thus I only want to return partial views without the layout.
Note that I am using ASP.NET Mvc, not ASP.NET Core!
First, I have an index method that loads a view that then will the partial of the step the order currently is in.
public override ActionResult Index(TradeInCheckOutPage currentPage)
{
var model = new BaseCheckoutStepViewModel(bulkOrderViewModel, currentPage,
GetCurrentStep(orderViewModel));
return View(Index.cshtml", model); // View handles redirect to correct view
}
The view of that method:
if (Model.Step.Equals(CheckoutStep.Confirm))
{
Html.RenderAction("confirm", "CheckoutPage",
new
{
currentPageId = Model.CurrentPage.PageId,
});
}
else if (Model.Step.Equals(CheckoutStep.ChooseSenderAddress))
{
Html.RenderAction("chooseAddress", "CheckoutPage",
new
{
CurrentPage = Model.CurrentPage.PageId,
BulkOrderId = Model.BulkOrder.Id
});
}
The order is in the state 'Confirm', so the method Confirm is called via Html.RenderAction.
public ActionResult Confirm(Guid currentPageId)
{
var model = new CheckoutConfirmViewModel(null, GetCurrentPage(currentPageId));
return View("Confirm.cshtml", model);
}
The view of that method, that initiates an ajax call for a partial:
#{
Layout = "_LayoutCheckOut.cshtml";
}
#using (Ajax.BeginForm(
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "content"
}))
{
}
I have the following code in my controller that gets hit by the ajax call:
[HttpPost]
public ActionResult Confirm(Guid currentPageId, bool confirm = false)
{
if (ModelState.IsValid)
{
return chooseAddress(currentPageId, bulkOrder.Id);
}
public PartialViewResult chooseAddress(Guid currentPageId, Guid bulkOrderId)
{
...
return PartialView("ChooseAddress.cshtml", model);
}
Problem is that for some reason the chooseAddress method viewresult is still using the layout despite it being a PartialViewResult! What's causing this?
I've tried specifying Layout = null in the ChooseAddress view too, but still the layout is being rendered.
Try:
Html.RenderPartial("chooseAddress", "CheckoutPage",...
Instead of Html.RenderAction("chooseAddress", "CheckoutPage",...
Also add the [ChildActionOnly] attribute to your chooseAddress Action. Its a good practice.
I managed to fix the issue!
Cause was that I had the following lines in _LayoutCheckOut (literally like this, for a quick local set-up), which loaded scripts:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.2/jquery.validate.min.js" integrity="sha512-UdIMMlVx0HEynClOIFSyOrPggomfhBKJE28LKl8yR3ghkgugPnG6iLfRfHwushZl1MOPSY6TsuBDGPK2X4zYKg==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ajax-unobtrusive/3.2.6/jquery.unobtrusive-ajax.js" integrity="sha512-f04GBpoqEZhbyjlRTuXeg8FIHDb+xfCJ0LVdqiN1fEl5B3jz3Z0SPe9IxDumOVdTeeXmKMcMJhb26VuGf1Laqw==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.js" integrity="sha512-Sw6xGAALk16gIMo01Nzur7z1lrF5DLbIy/cd9JiBy4yvcQsXwEnJRMHtTg2/OIO76WGv4C1yR+mCUkOtENKDTA==" crossorigin="anonymous"></script>
Apparently when you load in scripts in your view even though it is a partial and you specify layout = null, the layout will still be used!

Why PartialAsync doesn't call coresponding controller method?

I have a .NET Core 2.1 MVC application.
I have a Home controller that looks like this:
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult CountView(MyModel model)
{
...
return PartialView(model);
}
}
In the Index view I want to display a patial view called CountView.
But when I use the following method in the Index.cshtml:
#await Html.PartialAsync("CountView", Model)
the view is displayed as I wanted to but the method in the controller never gets called and thus the partial view doesn't get the data it needs that is intended to be fetched by the controller method.
Why is that so?
And how can I make it to work as desired?
#await Html.PartialAsync("CountView", Model)
Renders a Partial View, it doesn't call any Controller for that. The correct way for doing this in ASP.NET Core is to create a View Component.
As for the implementation, here's a simple one modified from the official documentation previously linked:
Create a ViewComponents folder at the root of the project
Inside it, create a ``CounterViewComponent` class:
public class CounterViewComponent: ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(MyModel model)
{
// magic here
return View(model);
}
}
Call it in your view:
#await Component.InvokeAsync("Counter", new { model = Model })

Repopulate form data when validation fails in aspnet core Razor Page

Thanks in advance for any help
I am working in aspnet core 2.1 razor pages. I need to repopulate form data when validation fails or ModelState is Invalid.
In MVC, we can use return View(model) but how to do that in aspnet core 2.1 razor page.
I tried return Page(), but that fires server side validation but does not repopulate data in form
Need Help...
Repopulation of the form values occurs automatically if you
Use the [BindProperty] attribute on the relevant PageModel properties,
Use the asp-for attribute in your input tag helpers to establish two-way binding in the UI (Razor content page)
Call return Page() in the event that ModelState.IsValid == false.
Here are the minimal steps required to demonstrate this:
A form:
<form method="post">
<input asp-for="FirstName"/><span asp-validation-for="FirstName"></span><br />
<input type="submit" />
</form>
And a PageModel:
public class FormValidationModel : PageModel
{
[BindProperty, StringLength(5)]
public string FirstName { get; set; }
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
return RedirectToPage("index");
}
}

ASP.NET MVC - T4 MVC - POST with Model

I have a controller that looks like this:
[RoutePrefix("items")]
public partial class ItemsController : Controller
{
public ActionResult Index()
{
var model = new MyApp.Models.Items();
return View(model);
}
// POST: /items/delete
[HttpPost]
[Route("delete")]
public ActionResult Delete(DeleteItemModel model)
{
// delete the item
model.Delete();
return RedirectToAction("Index");
}
}
In my Index.cshtml, I have the following:
#model MyApp.Models.Items
<h2>Hello</h2>
<form action="#Url.Action(MVC.Items.Delete())" method="post">
<button type="submit">delete</button>
</form>
The above is clearly a subset of my view. My main concern is, how to pass a DeleteItemModel from my form back to the Delete action. What am I missing? The MVC.Items.Delete path was generated from T4MVC. Yet, I can't figure out how to pass a model into it. Is there a fix here, or do I have to use some other approach entirely?

How to use more than 1 Model on a page by using asp.net mvc 5?

I want to use 2 models. The first is on Index.cshtml page, and the second is on _Layout.cshtml page
In the controller which contains the action public ActionResult Index(){...}, I declare some values and return it to View(). Like this:
public ActionResult Index()
{
HomePageViewModel model = new HomePageViewModel();
// do something...
return View(model);
}
And in MyProjectName.Models, I write some classes to check login account and put it on the page _Layout.cshtml. Like this:
On page _Layout.cshtml:
#using MyProjectName.Models
#model MyProjectName.Models.LoginModel
#if (Model.LoginAccount != null)
{
foreach(Account acc in Model.LoginAccount)
{
#Html.ActionLink(#acc.Email, "SomeAction", "SomeController", null, new { id = "loginEmail" })
#Html.ActionLink("Logout", "SomeAction", "SomeController", null, new { id = "logout" })
}
}
The code on page _Layout.cshtml doesn't work. It said that: I have returned a model (HomePageViewModel model), but some values which I want to render is referenced from MyProjectName.Models.LoginModel
Main requirement is: the first model is used to display the content on page Index.cshtml, and the second model is used to check user login (on page _Layout.cshtml).
Can you tell me how to do that? Thank you!
In your layout use Html.Action() or Html.RenderAction() to call a ChildActionOnly method that returns a partial view for LoginModel
[ChildActionOnly]
public ActionResult Login()
{
LoginModel model = // initialize the model you want to display in the Layout
return PartialView(model);
}
and create a partial view that displays the links, then in the Layout
# { Html.RenderAction("Login", "yourControllerName") }
A better approach would be to use partial views and the ViewBag.
in your controller you would do something similar to this:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Accounts = new AccountsViewModel();
ViewBag.HomePage = new HomePageViewModel();
return View();
}
}
From here you'd pass your model from the ViewBag to a partial view
#{
AccountViewModel Accounts = (AccountViewModel)ViewBag.Accounts;
}
#Html.Partial("_accountPartial", Accounts)

Categories

Resources