I just created a small test project to see if it's possible to load a different partial view on an ASP.NET MVC Razor page, but it seems like I failed to do so. Instead of replacing the "partial" div by "Partial", it opens "Partial" as a new page...
Can anyone tell me what I'm doing wrong?
Current situation:
Overview/Index.cshtml:
#model dynamic
#{
ViewBag.Title = "title";
}
<h2>title</h2>
#Html.Partial("AnotherPartial")
Overview/AnotherPartial.cshtml:
#model dynamic
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
#{
ViewBag.Title = "title";
}
<h2>title</h2>
#using(Ajax.BeginForm("Post", "Overview", new AjaxOptions{InsertionMode = InsertionMode.Replace, UpdateTargetId = "partial", HttpMethod = "POST"}))
{
<button type="submit">Submit</button>
}
<div id="partial">
</div>
Report/Partial.cshtml:
#model dynamic
#{
ViewBag.Title = "title";
}
<h2>Partial</h2>
OverviewController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace AjaxWebTest.Controllers
{
public class OverviewController : Controller
{
// GET: Overview
public ActionResult AnotherPartial()
{
return PartialView();
}
public ActionResult Index()
{
return View();
}
[HttpPost]
public PartialViewResult Post()
{
return PartialView("~/Views/Report/Partial.cshtml");
}
}
}
ReportController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace AjaxWebTest.Controllers
{
public class ReportController : Controller
{
// GET: Report
public ActionResult Index()
{
return View();
}
public ActionResult Partial()
{
return PartialView();
}
}
}
EDIT:
Found the solution:
Found the problem, jQuery wasn't defined on my page, so the unobtrusive-ajax js file didn't load properly. Added following reference BEFORE my unobtrusive-ajax include:
<script src="~/Scripts/jquery-1.10.2.js"></script>
You should put your unobtrusive-ajax script reference in the Scripts section of your main view.
#model dynamic
#{
ViewBag.Title = "title";
}
<h2>Main Index page title</h2>
#Html.Partial("AnotherPartial")
#section Scripts
{
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
}
In the Layout file, #RenderSection("scripts", required: false) is called at the very bottom after loading jQuery library. The unobtrusive-ajax script is expecting jQuery to be available/already loaded.
<div id="pageContent">
#RenderBody()
</div>
#Scripts.Render("~/bundles/jquery")
#RenderSection("scripts", required: false)
So if you want to execute some js files from your other views, you need to include those in the scripts section so that when the page is fully rendered, it will be added to the bottom ( After other dependeny libraries like jQuery is loaded);
Found the problem, jQuery wasn't defined on my page, so the unobtrusive-ajax js file didn't load properly.
Added following reference BEFORE my unobtrusive-ajax include:
<script src="~/Scripts/jquery-1.10.2.js"></script>
Related
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!
i'm creating a new website with umbraco8 i have a problem how to load an Action in Controller from a view of Homepage
Homepage view
#inherits Umbraco.Web.Mvc.UmbracoViewPage<ContentModels.HomePage>
#using ContentModels = Umbraco.Web.PublishedModels;
#{
Layout = "webBase.cshtml";
}
#{ Html.RenderAction("RenderHomeSlider", "HomePage"); }
Homepage Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Web.Mvc;
using System.Web.Mvc;
using Umbraco.Core.Models;
using HAWELE.Models;
using Archetype.Models;
using Umbraco.Web;
using System.Threading;
using Umbraco.Web.Mvc.SurfaceController;
public class HomePageController : Umbraco.Web.Mvc.SurfaceController
{
public ActionResult Index(RenderModel model)
{
return base.Index(model);
}
private const string PARTIAL_VIEW_HOME_FOLDER = "~/Views/Partials/HomePage/";
public ActionResult RenderHomeSlider(this HtmlHelper html)
{
return PartialView(PARTIAL_VIEW_HOME_FOLDER + "_HomeSlider.cshtml");
}
}
The issue isn't related to Umbraco. [ChildActionOnly] attribute is missing on the calling method:
RenderAction(HtmlHelper, String, String)
Invokes the specified child action method using the specified controller name and renders the result inline in the parent view.
https://learn.microsoft.com/en-us/dotnet/api/system.web.mvc.html.childactionextensions.renderaction?view=aspnet-mvc-5.2
Try the following:
Remove the index method from your controller. It is not relevant in a surfacecontroller.
Modify the RenderHomeSlider Action to:
public ActionResult RenderHomeSlider()
{
return PartialView(PARTIAL_VIEW_HOME_FOLDER + "_HomeSlider.cshtml");
}
This line in your view
#{ Html.RenderAction("RenderHomeSlider", "HomePage"); }
should change to
#Html.Action("RenderHomeSlider", "HomePage")
This should render whatever html is in _HomeSlider.cshtml
It's not clear whether your _HomeSlider.cshtml partial requires any model to be passed into so I am assuming it doesn't.
To test that the above works, you can just put some simple text in your partial and see if it rendered on the page.
I don't know what the rest of your code looks like so can't say exactly whether what you are trying to achieve here is the most expedient way to do it.
Good luck
I've been trying to follow https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/authoring?view=aspnetcore-2.1 to get tag helpers to work but no matter what I do they aren't recognised in intellisense, no breakpoints are hit in the code producing the html and the elements aren't transformed.
This is my EmailTagHelper.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace eHealthy.TagHelpers
{
public class EmailTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "a"; // Replaces <email> with <a> tag
}
}
}
This is my _ViewImports.cshtml
#using Microsoft.AspNetCore.Identity
#using eHealthy.Models
#using eHealthy.Models.AccountViewModels
#using eHealthy.Models.ManageViewModels
#using eHealthy.Helpers;
#using eHealthy.TagHelpers;
#addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
#addTagHelper "*, eHealthy.TagHelpers"
This is the page where I try to invoke the helper
#model EditViewModel
#{
ViewBag.Title = "title";
Layout = "_Layout";
}
#*<h2>title</h2>*#
<form method="post">
<email>
potato
</email>
</form>
<input type="hidden"/>
Unquote your add of the tag helpers. Delete the eHealthy.TagHelpers helper, you do not need to even create it.
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
I am using 2017 VC for mac, the xamarian version of vs does not have the auto Areas Mapper. I manually added Areas folder and configured the routing properly, when I add an actionLink to my main csHTML page it is throwing an 500 error and stating.
System.InvalidOperationException
The view 'Billing' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/BillingMain/Billing.cshtml
~/Views/BillingMain/Billing.vbhtml
~/Views/Shared/Billing.cshtml
~/Views/Shared/Billing.vbhtml
~/Views/BillingMain/Billing.aspx
~/Views/BillingMain/Billing.ascx
~/Views/Shared/Billing.aspx
~/Views/Shared/Billing.ascx
Instead it should be searching in ~/Areas/Billing/Views/BillingMainController.cshtml
I have tried everything to get this to work, but only keep on getting stuck.
Here is my directory hierarchy
Project-
AppStart-
Areas-
Billing-
Invoice-
Controllers-
Scripts-
Views-
Global.asax
I am only testing Billing area for now, below is the rest of my code.
RouteConfig
using System.Web.Mvc;
using System.Web.Routing;
namespace WORK_GODDAMN
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//AreaRegistration.RegisterAllAreas();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
//,namespaces: new string[] { "WORK_GODDAMN.Areas.Controllers" }
);
}
}
}
BillingAreaRegistration.cs
using System;
using System.Web.Mvc;
namespace WORK_GODDAMN.Areas.Billing
{
public class BillingAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Billing";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Billing_Default",
"Billing/{controller}/{action}/{id}",
new {controller = "BillingMain", action = "Index", id = UrlParameter.Optional }
, namespaces: new string[] { "WORK_GODDAMN.Areas.Billing.Controllers" }
);
}
}
}
Global.asax
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Http;
namespace WORK_GODDAMN
{
public class Global : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
main _Layout.cshtml this is where the Action Link redirects and believe I might be doing something wrong here, but at this point I have no clue what could be causing the problem.
<!DOCTYPE html>
<html>
#using System.Web.Optimization
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>#ViewBag.Title</title>
#Scripts.Render("~/Scripts/modernizr.js")
</head>
<body>
<div>
<div>
<h2>{Demo}- Pluggable Modules</h2>
</div>
<div id="nav">
#Html.ActionLink("Home","Index","Home", new {Area=""}, null)
#Html.ActionLink("Invoice","Index","InvoiceMain", new {Area=""}, null)
#Html.ActionLink("Billing","Index","BillingMain", new {Area=""}, null)
</div>
<hr />
<div>
#RenderBody()
</div>
</div>
#Scripts.Render("~/Scripts/jquery.js")
#RenderSection("Scripts", required: false)
</body>
</html>
Figured it out, it was in my controller that the error was happening. Instead of returing return View("Index") I just gave the absolute path return View("~/Areas/Billing/Views/Index.cshtml") which is sort of a work-around, which is the only thing I found would work.
Also in the future if anyone wants to use html action link and model tags, you will need to manually add Web.Config file in both Areas/{area}/Views and Areas folder so you can use MVC framework in your cshtml View file. THIS IS FOR ANYONE WHO HAD TO MANUALLY CREATE AREAS if you use VS tool to add->Areas VS will automatically generate required files if you have VS do it, since Im using Mac Xamarin VS I don't have that convenient option.
This is what I had to change.
In {Project/Areas/Billing/Views/Index.cshtml} Change
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace WORK_GODDAMN.Controllers
{
public class BillingMainController : Controller
{
// GET: Billing/BillingMain
public ActionResult Index()
{
return View("Index");
}
}
}
TO
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace WORK_GODDAMN.Controllers
{
public class BillingMainController : Controller
{
// GET: Billing/BillingMain
public ActionResult Index()
{
return View("~/Areas/Billing/Views/BillingMain/Index.cshtml");
}
}
}
Assuming your have BillingMain controller inside the Billing area, you should explicitly specificity the area name when using the ActionLink.
#Html.ActionLink("Billing","Index","BillingMain", new {Area="Billing"}, null)
This will generate the link with href value pointing to yourSiteBaseAddress/Billing/BillingMain/Index
Assuming you do not have any customer route definitions to override the default conventions, it should work as long as you have the view file Index.cshtml in ~/Areas/Billing/Views/BillingMain/ or ~/Areas/Billing/Views/Shared/ (Assuming you are not trying to return a different view file from the Index action)
Specify the name of area in Html.ActionLink.
#Html.ActionLink("Billing", "Index", "BillingMain", new { Area = "Billing" }, null)
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.