Make a View partial - c#

I have a view called drawGraph , this is accessed through the controller via;
#Html.ActionLink("DrawGraph", "drawGraph", new {id =item.data})
When i use this link the page loads on a new page (as it would) i would like to display it as a part of the page that the link is on, is there any easy way to achive this?
my controller looks like this;
public ActionResult drawGraph(string data)
{
*Bunch of code
return View(chart);
}

Yes you can, however you need to use Ajax, luckily ASP.NET MVC provides some nice convenience methods like Ajax.ActionLink
#Ajax.ActionLink("DrawGraph", "drawGraph", new {id =item.data},
new AjaxOptions
{
UpdateTargetId = "yourDiv",
InsertionMode = InsertionMode.Replace,
})
<div id="yourDiv"> </div>
Then you need to return a partial view from your action with PartialView:
public ActionResult drawGraph(string data)
{
//Bunch of code
return PartialView(chart);
}
You should not forget to include the jquery.unobtrusive-ajax.min.js in your layout/view in order to the Ajax helpers work.

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!

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)

Ajax.Actionlink forwarding to Get method while setting httpmethod to post

Controller's get and post method
[HttpGet]
public ActionResult Index()
{
SoSession.Authenticate("pierre", "pierre");
return View();
}
[HttpPost]
public ActionResult Index(CompanySearch model)
{
return RedirectToAction("Companies",new{searchString=model.SearchString});
}
in view
#using (Html.BeginForm("Index", "Company"))
{
<div class="input-block-level">
#Html.TextBoxFor(m => m.SearchString)
#Ajax.ActionLink(
"Submit",
"Index",
new{},
new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "partialDiv" })
</div>
}
<div id="partialDiv"></div>
Problem
Whenever user clicks submit link i get forwarded to get method and not post method. How do i forward the call to post method of my controller?
Make sure you have the unobutrusive ajax library file (and it's dependencies (jQuery)) loaded to your view properly. If you do not have this file loaded to your page, Clicking on the link produced by Ajax.ActionLink helper method will do a GET request instead of the asynchronous POST you were expecting.
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
It sounds like you are trying to use an ajax form:
#using Ajax.BeginForm("Submit", "Company", FormMethod.Post, new AjaxOptions { UpdateTargetId = "partialDiv", InsertionMode = InsertionMode.Replace}) {
#Html.TextBoxFor(m => m.SearchString)
}
If you include the ajax js libraries that should work.
You can also use JQuery for the partial load although the controller would return a partial. I do agree with mayabelle that Ajax.BeginForm() is another route to take.
[HttpGet]
public ActionResult Companies(string searchString)
{
return this.PartialView("MyView", MyObject)
}
inside of the cshtml javascript:
var searchString = $("#SearchString").val();
$("#partialDiv").load('#Url.Content("~/Home/Companies/")' + searchString, function(){ DoSomething(); });

How to use RedirectToAction while passing view model to a view with different route

I have a ASP.NET MVC 3 app with a common scenario where there is with an "About" controller using "Contact" and "ThankYou" actions.
I want user to go to /about/contact, fill out the form, submit it, and be taken to /about/contact/thankyou * page where the form contents (aka view model) will be displayed.
** Note there is no "Contact" controller nor do I want to create one for this purpose if possible.*
I am using RedirectToAction to prevent resubmission (Post/Redirect/Get pattern) and TempData to pass on view model to thank you page.
I can also use TempData to check if thank you page was reached directly and redirect back to contact form page (so it would not register as a "goal" in web analytics)
But one thing I could not figure out is how to use different route for thank you page so it appears as /about/contact/thankyou
Am I doing this right?
Is there a better way?
Here are relevant actions in AboutController
<!-- language: c# -->
[RequireHttps]
public ActionResult Contact()
{
var viewModel = new ContactViewModel();
return View(viewModel);
}
[RequireHttps]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Contact(ContactViewModel viewModel)
{
if (!ModelState.IsValid)
{
return View(viewModel);
}
// not sure if this is the best way or how to redirect to /contact/thankyou
TempData["viewModel"] = viewModel;
return RedirectToAction("ThankYou");
}
[RequireHttps]
public ActionResult ThankYou()
{
var viewModel = TempData["viewModel"];
// upon direct access, viewModel will be null and missing, so redirect to Contact form
if (viewModel == null)
{
return RedirectToAction("Contact");
}
return View(viewModel);
}
You could define a custom route before the default route:
routes.MapRoute(
"contact",
"about/contact/thankyou",
new { controller = "About", action = "ThankYou" }
);
Now when you navigate to /about/contact the Contact GET action will be executed (You have to rename it as in your code it is called ContactUs). Then the user fills the form and submits to the Contact POST action. The url stays the same for the moment: /about/contact. After the redirect the ThankYou action is executed and the url changes to /about/contact/thankyou.

Posting from a Form in Partial View - Why is it triggering the wrong controller action?

Bear with me as I describe the issue.
An MVC3 application making use of partial views. Having trouble posting a Comments form in a partial view from its parent-model's Details view.
For reference ArticleViewModel has a collection of CommentsViewModel so there is a OTM relationship.
Details View
#model ArticleViewModel
// Renders the Article and its Comments - no forms, just display markup
// A nested _Comments partial is used to render the article's comments.
#Html.Partial("_Article", Model)
// Renders HTML and Javascript for the Pagedown editor - POST form inside.
#Html.Partial("_CommentEditor", new CommentViewModel())
#section scripts { /* code here for validation and the javascript editor */ }
_CommentEditor Partial View
#model CommentViewModel
#using (Html.BeginForm("Comment","Article",FormMethod.Post)) {
#Html.TextAreaFor(m => m.Content)
<input type="submit" value="Submit" />
<input type="reset" value="Clear" />
}
Article Controller
public ActionResult Details(string slug) {
return View(_articleService.Get(slug));
}
[HttpPost]
public ActionResult Comment(string slug, CommentViewModel comment) {
if(ModelState.IsValid) {
_articleService.AddComment(comment, slug);
}
return RedirectToAction("Details", new { Slug = slug });
}
Scenario / Issue
Http Request for /Article/Details/{slug} renders the article, its comments, and the editor form correctly.
The editor works as intended, but on clicking Submit, I noticed the Details action on my controller being called rather than the HttpPost Comment action.
As you can see the Razor Form helper specifies the Comment action on the Article controller using POST.
Question
Why is this happening? What am I missing?
Chump Award!
The answer is Routing.
Looking closer with Fiddler, I was actually sending a POST request to /article/comment, so I checked my routing... how I missed this, I don't know:
routes.MapRoute("Article-Create", "article/create", new { controller = "Article", action = "Create" });
routes.MapRoute("Article-Edit", "article/edit/{slug}", new { controller = "Article", action = "Edit" });
routes.MapRoute("Article-Delete", "article/delete/{slug}", new { controller = "Article", action = "Delete" });
routes.MapRoute("Article", "article/{slug}", new { controller = "Article", action = "Details" });
routes.MapRoute("Articles", "articles", new { controller = "Article", action = "Index" });
There is no explicit route for the Comment action. There is a catch-all REST-ish route for fetching an article (article/{slug}). So the Comment POST was being handled by it before hitting the default route...
My specific solution (i like explicit routing - even when it gets me in trouble) was to add a route for comments, just about the catch-all article/{slug} pattern:
routes.MapRoute("Article-Comment", "article/comment", new { controller = "Article", action = "Comment" });
Problem solved. Embarrassing.

Categories

Resources