I have this simple list of users in my model.
If we click one user, I would like to set that user as the chosen one and refresh the partial view.
My code looks like:
<div id="myPartialView">
#if (#Model.ChosenUser != null)
{
#Model.ChosenUser.UserName
}
<ul>
#foreach (var u in Model.Users)
{
<li>
<a href='#Url.Action("ChooseUser", "Controller", new { userId = u.UserId })'>#u.UserName</a>
</li>
}
</ul>
The controller method returns an Ok();
My current code redirects me to an empty page and I have to go back and refresh the page in order to see the model changes.
My question is, how can I refresh only this partial view after the razor action?
You will need to use Ajax.ActionLink here :
#foreach (var u in Model.Users)
{
<li>
#Ajax.ActionLink(u.UserName, // <-- Text to display
"Choose User", // <-- Action Name
"Controller", // <-- Controller Name
new AjaxOptions
{
UpdateTargetId="myPartialView", // <-- DOM element ID to update
InsertionMode = InsertionMode.Replace, // <-- Replace the content of DOM element
HttpMethod = "GET" // <-- HTTP method
})
</li>
}
The helper method would render the html needed to create the anchor tag element with the specified values, and you need to make sure that you have scripts added in the master layout for unobtrusive ajax.
For that you can look here, what scripts are needed to be pre-requisite:
How to use Ajax.ActionLink?
and your action method should be returning the model of the same type that your partial view expects with data populated in the model.
Please refer to the following post to learn in detail about Ajax Action Link:
http://www.c-sharpcorner.com/UploadFile/abhikumarvatsa/ajax-actionlink-and-html-actionlink-in-mvc/
Related
I have something like this:
#using (Ajax.BeginForm("Validate", "Basket", new AjaxOptions
{
UpdateTargetId = "panelId",
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
OnSuccess = "SuccessMethod"
}))
{
#if(Model != null)
{
my action...
}
else
{
Response.Redirect(Url.Action("Index", "Home"))
}
}
It works perfect when I use submit button, because partial is refreshing, and layout stay the same.
I have a problem, when my Model became null, because user make a remove action on my page. Then I want to make redirect to my home page (different layout), but when I do that (like in my code), I get two layounts on my page, because of InsertionMode.Replace mode.
How can I omit the Ajax.BeginForm in my view?
Because you're using an ajax form (Ajax.BeginForm) the framework overwrites just the form, giving you the two layouts when you redirect from within the ajax form (as only the html within the form is redirected, the rest of the page outside the form is not redirected).
You can get around this with some javascript/jquery:
First, remove the Response.Redirect
This can be replaced by a placeholder div to indicate no results, or the code can check if there were no results - without more code, it can't be determined if/how this would be done in your specific case, so in the general case, add a placeholder, eg:
#if (Model == null)
{
<div class='nomodel'></div>
}
Second, update the OnSuccess code inside SuccessMethod() to check if there's no model (or check if there are no order rows), then redirect the entire page, eg:
if ($(".nomodel").length > 0) {
location.href = '#Url.Action("Index", "Home"))'
}
My problem: drop down list at layout page.
I've read this post: ASP.NET MVC Razor pass model to layout it's more or less similar to my problem.
In one of comments Mattias Jakobsson wrote that: "But a common solution is to use RenderAction to render parts that need their own data in the layout page".
So ok I've created layout page with #Html.Action() that render my drop dwon list with a date from the db. Everything's perfect. But...
I have two pages, for example: 'Home', 'About' and my drop down list (ddl) at layout page
How to achive that when I'm at 'Home' and I changed selection in ddl it refresh 'Home' page and when I'm at 'About' it refresh 'About' page.
How to store selected ddl value through pages?
Part of Layout.cshtml code:
.
.
<body>
<header id="top" class="grid-full-margin">
<strong id="logo" class="grid-304"><img src="/images/logo.png" ></strong>
#Html.ActionLink(#Resources.Resource.BackToIntranet, "Index", "Home", null, new {#class = "link link-home grid-position-left"})
<h1>#Resources.Resource.SiteTitle</h1>
#Resources.Resource.LayoutHelp
<nav clss="grid-896">
<ul>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem1, "Index", "Home")</li>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem2, "Index", "ClimaticStation")</li>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem3, "Index", "ClimaticPoint")</li>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem4, "Index", "IcewaterExchanger")</li>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem5, "Index", "Pipeline")
<ul>
<li>#Html.ActionLink("Zestawienie", "YearsLength", "Pipeline")</li>
</ul>
</li>
</ul>
<div class="mod-select-list tbl-actions">
#Html.Partial("~/Views/Shared/Partials/LoginPartial.cshtml")
</div>
</nav>
</header>
<form action="#">
#Html.Action("VariantsDdl", "MyBase")
</form>
#RenderBody()
.
.
Part of MyBaseController.cs
public class MyBaseController : Controller
{
[ChildActionOnly]
public ActionResult VariantsDdl()
{
var dataFromDb = GetDataFromDB(); // it's not importstn right now
return this.PartialView("~/Views/Shared/Partials/VariantsDdlPartial.cshtml", dataFromDb);
}
.
.
}
Regards,
Marcin
ok I've managed to solve this problem and I want to know your opinion abut my solution.
_Layout.cshtml looks the same way like at first post, so belowe is only most important part for this question (drop down list at layout)
<div style="float: right;">
#Html.Action("VariantsDdl", "MyBase")
</div>
Action: VariantsDdl is implemented at MyBaseController. This action loads selected variant id from session or if it's null then from web.config (in this situation it's project requirement that at least one variant must be present at db and its id must be specified in config):
[ChildActionOnly]
public ActionResult VariantsDdl()
{
long defaultVariantID;
long.TryParse(System.Configuration.ConfigurationManager.AppSettings["DefaultVariantId"], out defaultVariantID);
if (System.Web.HttpContext.Current.Session["mySelectedVariant"] != null)
{
long.TryParse(System.Web.HttpContext.Current.Session["mySelectedVariant"].ToString(), out defaultVariantID);
}
var variants = this.db.warianties.ToList();
var items = new List<SelectListItem>();
foreach (var variant in variants)
{
var selectedItem = false;
if(variant.id == defaultVariantID)
{
selectedItem = true;
}
items.Add(new SelectListItem { Selected = selectedItem, Text = variant.nazwa, Value = variant.id.ToString() });
}
return this.PartialView("~/Views/Shared/Partials/VariantsDdlPartial.cshtml", items);
}
Partial view and post action that stores selected variant id to session:
#model IEnumerable<SelectListItem>
<label for="field">Current variant</label>
#Html.DropDownList("Varaints", Model, new { id = "variantsDdl" })
<script type="text/javascript">
$(function () {
$('#variantsDdl').change(function () {
var val = $('#variantsDdl').val()
$.ajax({
type: "POST",
url: '#Url.Action("ChangeVariant", "MyBase")' + '/' + val,
success: function (result) {
location.reload();
},
error: function (data) { alert('Error'); }
});
});
});
Partial View post action 'ChangeVariant', saves selected variant id to session:
[HttpPost]
public ActionResult ChangeVariant(long id = 0)
{
System.Web.HttpContext.Current.Session["mySelectedVariant"] = id;
return null;
}
This is solution for my requirements:
1. DDL at layout
2. Refresh current page at DDL 'onchange'
3. Keep selected DDL value through pages
Please comment if it's appropriate solution or maybe should I go different way?
Regards,
Marcin
I dint find answers to this and tried several ways. any help would be appreciated thanks !!
I have view which updates the page without reloading on each click using ajax scripts. Below is the code. but after entire partial views are generated, I want user to redirect complete different view on clicking a link which is not associated to controller user is in now.
my View
#model IMONLP.Models.Search
#{
ViewBag.Title = "Search";
}
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
#using (Ajax.BeginForm("Search", new AjaxOptions() { UpdateTargetId = "results"
}))
{
<br />
#Html.TextBoxFor(m => m.search_text, new { style = "width: 200px;" })
<input type="submit" value="search" />
}
#Ajax.ActionLink("Try Demo", "PLNHK", "PLNHK", new AjaxOptions { })
// this ajax link should redirect to different view,
<div id="results">
#if (!String.IsNullOrEmpty(#Model.search_text))
{
Html.RenderPartial("Searchprocess", Model);
}
</div>
My controller:
public ActionResult Search(Search s)
{
//do something
return PartialView("Searchprocess", s);
}
public ActionResult Selected(Search s)
{
//DO something
return PartialView("Selected", s);
}
The above "TryDEMO" "PLNHK" ajax action link will have to be redirected to new controller and new action and return view thats returned by that action. everytime I click on that, I found it moving to that controller and then to corresponding view but again its getting back to old page. I used #html.actionlink instead of Ajax, but now I get this error
The "RenderBody" method has not been called for layout page "~/Views/PLNHK/PLNHK.cshtml".
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
EDIT : I did create PLNHK.cshtml. while I'm trying to debug this, the control goes to PLNHK controller then to PLNHK view(PLNHK.cshtml) parses each and every step in that page, but finally I would get the output to be the older page. I was thinking may be the Ajax scripts on before page is the reason.
I am new at .NET mvc.
In a view "DisplayThings" I have something like:
#foreach (var thing in Model)
{
#Html.Partial("DisplayPartial", thing)
}
In the partial view "DisplayPartial" I have
#using (Ajax.BeginForm("Afunc", new AjaxOptions ()))
{
#Html.EditorFor(model => model.AstringThing)
#Html.EditorFor(model => model.AintThing)
<input type="submit" name="submit" value="Ajax Post" />
}
At the moment the "Afunc"-Action saves the model to the database and then redirects to a controller action to retrieve all "things" from the database and render the entire "Displaythings" View.
My question is: When i press one of the submitbuttons (There is one submitbutton for every "thing" i the list). I want only that partial view to reload/reflect on my change. I dont want to reload the entire "Displaythings" view. How do I do this? If I just return a partial view I lose everything else but that partial view.
If this is a bad approach please give me directions.
Update:
I am still doing something wrong as I get the partial view rendered in a new page. My controller :
public ActionResult Afunc(ThingModel thingmodel)
{
// do
return PartialView("DisplayPartial", thingmodel);
}
I have tried using UpdateTargetId and onsuccess both with the same result (A new page)
In the AjaxOptions that your are simply now passing as new AjaxOptions you can specify the target element using the UpdateTargetId property:
<div id="unique_thing_id">
#using (Ajax.BeginForm("Afunc", new AjaxOptions { UpdateTargetId = 'unique_thing_id' }))
{
}
</div>
Above, a container with unique id for every "thing" is represented with <div id="unique_thing_id">. This will be replaced with the repsonse of the request. Change Afunc to render only the particular "thing" partial.
I am used to ASP.NET web forms, and am slowly learning ASP.NET MVC.
My website has a little login form on the homepage. My natural thought is that this login form may be useful in other places, and it is not the primary action of the homepage, so I want to separate it off into a partial view. And because it is related to accounts, I want the login in my AccountController not my HomepageController.
Login form is a pretty basic strongly typed partial view:
#model Models.Account.AccountLogin
<h2>Login Form</h2>
#using (Html.BeginForm("_Login", "Account")) {
#Html.ValidationSummary()
<div>
<span>Email address:</span>
#Html.TextBoxFor(x => x.EmailAddress)
</div>
<div>
<span>Password:</span>
#Html.PasswordFor(x => x.Password)
</div>
<div>
<span>Remember me?</span>
#Html.CheckBoxFor(x => x.RememberMe)
</div>
<input type="submit" value="Log In" />
}
</div>
On the homepage, I have this:
#Html.Action("_Login", "Account")
Finally, in the account controller, this:
[HttpGet]
public PartialViewResult _Login()
{
return PartialView();
}
[HttpPost]
public PartialViewResult _Login(AccountLogin loginDetails)
{
// Do something with this
return PartialView();
}
Now when I load my homepage, it looks OK and contains the form. When I click the Log In button, it takes me to myurl/Account/_Login, which contains the form, but not within the _Layout master page, just basic plain HTML and it doesn't do anything at all when I click Log In.
I am pretty sure that I have just missed some fundamental aspect of what I am supposed to be doing here, can someone please point me in the right direction?
It's because you're returning a partial view, which strips away the master page and just returns the main content. Often actions starting with an underscore are used for partials (e.g. ajaxing in a bit of a page, but not the full page). It sounds like you want a full action, and not a partial, so
[HttpPost]
public ActionResult Login(AccountLogin loginDetails)
{
// Do something with this
return View();
}
The issue here is that you are doing a fullpage postback.
You have two options, really.
Firstly, you can use a full page postback, and then call Html.Partial to display your Partial.
Something like
[HttpGet]
public ActionResult Login()
{
return View();//this typically returns the view found at Account/Index.cshtml
}
And then create a View along the lines of
#{
ViewBag.Title = "Index";
}
<h2>Title</h2>
#Html.Partial("PartialNameGoesHere")
Your partial is then rendered where indicated, but this is done when the page loads (if you look at the generated HTML, it appears exactly as though you had written it inline).
Or you can use jQuery/AJAX to load the partial on demand. Let's say you have a homepage of some description
public ActionResult Home()
{
return View();
}
public ActionResult Login()
{
return PartialView("_Login");
}
Create the view
#{
ViewBag.Title = "Index";
}
<h2>Home</h2>
<div>
<p>Hey welcome to my pretty awesome page!</p>
</div>
Show me the login!
<div id="container">
</div>
You can then load the PartialView into the container div whenever you need it, using some JS.
$(function() {
$('.my-login-link').click(function() {
$.ajax({
url: 'account/login',
success: function(data) {
$('#container').html(data);
}
});
return false;//cancel default action
});
});
In that instance, the page loads as normal without the login part. When the user clicks the link, the Login on the controller Account is called using AJAX/jQuery. This returns the HTML of the PartialView, which you can then add to the page using jQuery in the Success handler.