Update drop down using Ajax.ActionLink - asp.net-mvc

I am trying to update the dropdown list:
View:
<div class="editor-field">
Names: <%: Html.DropDownList("names", (SelectList)ViewData["Names"]) %>
<%:Ajax.ActionLink("Refresh", "GetNames", new AjaxOptions { UpdateTargetId = "names", HttpMethod = "GET" })%>
</div>
Controller:
[HttpGet]
public ActionResult GetNames()
{
List<String> names = this.GenerateNames();
return Json(new SelectList(names));
}
The flow is the following: when user makes the first request, the list is updated from viewdata, then user presses refresh and the dropdown is populated usin ajax request.
I tried to return both JSON result - the dropdown is not updated. When returning SelectList the dropdown just gets cleared.
How can I accomplish this task?

You could put this drop down into a partial (Names.ascx):
<%# Control Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<YourApp.Models.SomeViewModel>" %>
Names: <%: Html.DropDownList(x => x.SelectedName, Model.Names) %>
And then in your main view use this editor template:
<div class="editor-field">
<span id="names"><% Html.RenderPartial("Names"); %></span>
<%: Ajax.ActionLink("Refresh", "Names",
new AjaxOptions { UpdateTargetId = "names", HttpMethod = "GET" }) %>
</div>
And you controller action could look like this:
public ActionResult Names()
{
var model = new SomeViewModel
{
// TODO: fetch the names from db:
Names = new SelectList(new[] {
new { Id = "1", Text = "name 1" },
new { Id = "2", Text = "name 2" },
new { Id = "3", Text = "name 3" },
}, "Id", "Text")
}
return View(model);
}

Just update the viewdata again so the view can use the same code to update itself for the second shot, being the Ajax return. And u don't need to use Json for that. Let me know how it goes.

Related

How can I pass a parameter together with the Model?

Here's my View (Model ActivityViewModel):
#model GPMS.Models.ActivityViewModel
<div class="tab-pane" id="managepayments" role="tabpanel">
#{ Html.RenderPartial("_Payments", Model.Payments); }
</div>
Which render a Partial (Model IEnumerable<GPMS.Models.PaymentViewModel>):
#model IEnumerable<GPMS.Models.PaymentViewModel>
#using (Ajax.BeginForm("SavePayments", "Activities", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "DynamicContainer", InsertionMode = InsertionMode.Replace, OnBegin = "AjaxBeginFormOnBegin", OnComplete = "AjaxBeginFormOnComplete", OnSuccess = "AjaxBeginFormOnSuccess", OnFailure = "AjaxBeginFormOnFailure" }))
{
#Html.AntiForgeryToken()
<!-- My Form -->
}
Which send Ajax request to my Controller's Action:
public ActionResult SavePayments(IEnumerable<PaymentViewModel> payments)
{
if (ModelState.IsValid) {
// code; here I need ActivityViewModel.ID
}
}
The question is: how can I pass to that SavePayments also my activity ID stored in ActivityViewModel.ID? Can I do with routing?
I don't want to pass the whole ActivityViewModel to SavePayments, otherwise I need to take care of its required fields for the ModelState.IsValid check.
One option is to use the overload of Html.Partial to pass the ID using additionalViewData, then retrieve it in the partial view and add it as a route value in the form.
In the main view
#{ Html.RenderPartial("_Payments", Model.Payments, new ViewDataDictionary { { "ID", Model.ID} }); }
And in the partial
#using (Ajax.BeginForm("SavePayments", "Activities", new { id = ViewData["ID"] }, new AjaxOptions { ....
Then add a parameter in the POST method for the ID
public ActionResult SavePayments(int id, IEnumerable<PaymentViewModel> payments)

Updating a Partial View From A Link In Its Own WebGrid

This is pretty much my third day developing MVC and I have what I hope will be a simple question. Basically I have a WebGrid within a partial view, which has a column that performs an update via a controller.
The controller then returns the updated partial view successfully, but the it replaces the whole page with the results instead of just the partial view.
Here's the partial view:
#model Site.Models.UsersForCompanyModel
#{
ViewBag.Title = "Admin User Management Grid";
}
#{
var grid = new WebGrid(
Model.Users,
ajaxUpdateContainerId: "divUserGrid",
fieldNamePrefix: "gridItems_",
pageFieldName: "paging",
sortFieldName: "sortField"
);
grid.Pager(WebGridPagerModes.All);
var userColumns = new List<WebGridColumn>
{
new WebGridColumn {ColumnName = "Email", Header = "E-Mail", CanSort = true},
new WebGridColumn {Header = "Lock", Format = user => user.isAdmin ? Html.Raw("n/a") : Html.ActionLink(user.IsLocked ? "Unlock" : "Lock", "ToggleLock", new {userId = user.Id, companyId = Model.CompanyId}) },
};
<div id="divUserGrid">
#grid.GetHtml(
htmlAttributes: new { id = "userGrid" },
tableStyle: "table table-striped table-bordered",
columns: userColumns
)
</div>
}
...and here's the controller code:
public ActionResult GetUsersForCompany(string companyId)
{
using (var service = new ManagementService())
{
var model = GetUsersForCompany(companyId, service);
return PartialView("AdminUserManagement_Grid", model);
}
}
public ActionResult ToggleLock(string companyId, string userId)
{
using (var service = new ManagementService())
{
var user = service.GetUserById(userId);
service.LockUser(userId, !user.IsLocked);
return GetUsersForCompany(companyId);
}
}
What's the easiest way to go about updating the partial view with the results returned from ToggleLock()?
Is there a way to do it declaratively via Html.ActionLink or Ajax.ActionLink?
The easiest way is to put your partial view in container div like below
<div id="PartialViewDivId">
#{ Html.RenderAction("GetUsersForCompany",model.CompanyId);}
</div>
Then use jQuery to load the updated view
On some click event
var companyId= read company id
var userId= read user id
var url = "mycontroller/ToggleLock?companyId="+companyId+"&userId"+userId;
$("#PartialViewDivId").load(url)
Thanks, Kartikeya. Partial credit for the answer, though I found a declarative way that didn't require manual HTML/event wiring and custom javascript.
The key was simply switching to an Ajax.ActionLink (instead of using Html.ActionLink), then setting my partial view placeholder ID (I had a div setup similar to Kartikeya's example) and a few other parameters in the AjaxOptions of the control, like this:
new WebGridColumn {Header = "Lock",
Format = user => user.isAdmin ? Html.Raw("n/a") :
Ajax.ActionLink( user.IsLocked ? "Unlock" : "Lock",
"ToggleLock",
new{userId = user.Id, companyId = Model.CompanyId },
new AjaxOptions
{
UpdateTargetId="userGridPlaceholder", // <-- my grid placeholder
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET"
})

handle 'open in a new window' when clicked on ajax.ActionLink which point to action that returns partial view

Hello I've got an action which gets some data from database and returns a partial view
In the partial view there are ajax.actionLinks which when clicked execute the same ImportShow action but this time with new data; and as you see in the cshtml - then update only the with the new data.
The problem I'm trying to solve is - if a user clicks 'Open in new Window' or 'open in new tab' in the new window you will see loaded only this partial view. And I can't think of a way how to make redirect and reload the whole page only in this cases. (after all the link point to an action method that RETURNS A PARTIAL VIEW).
public virtual ActionResult ImportShow(String id, String menuID, string articlegroupID, int? counter)
{
GroupMenu p_GroupMenu = new GroupMenu();
p_GroupMenu.MenuHistory = p_GetMenuHistory.ToList();
p_GroupMenu.MenuLeft = p_GetMenuLeft.ToList();
return PartialView("ImportShow", p_GroupMenu);
}
As
model MvcBeaWeb.GroupMenu
<div class="importPartUpdate">
<ul id="products">
#{
if (Model != null)
{
foreach (MvcBeaDAL.WebServiceBeaMenu item in Model.MenuLeft)
{
<li id="#item.ID">
<div class="imageTilesShow">
<a title= #item.SpecialWord>
<img src="#item.ImageFile" alt='#item.SpecialWord)' id="ImageProducts" class="imageTilesShow">
#Ajax.ActionLink(#item.SpecialWord, "ImportShow", new { id = Model.LanguageName,menuID=#item.ID},new AjaxOptions { UpdateTargetId = "importPartUpdate", HttpMethod = "GET", InsertionMode = InsertionMode.Replace })
</a>
</div>
</li>
}
}
}
</ul>
</div>
There are a few posts that having this issue before, you can check out this and this. Basically what happens is: when you click the "ajax" link, it is a AJAX call, therefor the partial view was rendered and everything works as expected. However, when you right click to view the page a new tab or new window in the browser, it is NOT a AJAX call, but you're returning a partial view, the new tab or window will still return a partial view. That's why you only see the partial view.
To illustrate what I meant:
here's the code snippet.
public class HomeController : Controller
{
List<Person> people = new List<Person>()
{
new Person { Name = "Larry", Age = 10},
new Person { Name = "Jessie", Age = 11},
new Person { Name = "Ben", Age = 12},
new Person { Name = "Victor", Age = 13},
new Person { Name = "Tom", Age = 14},
new Person { Name = "Suresh", Age = 15},
new Person { Name = "Jim", Age = 16},
};
public ActionResult Index()
{
return View();
}
public ActionResult GetPerson()
{
Random r = new Random();
int i = r.Next(0, people.Count);
if (Request.IsAjaxRequest())
{
return PartialView(people[i]); //return partial if it's a ajax call
}
else
{
return View(people[i]); // return view if it's NOT a ajax call
}
}
}
Index View:
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Ajax.ActionLink("replace", "GetPerson", new AjaxOptions { UpdateTargetId = "replaceMe", HttpMethod = "Get", InsertionMode = InsertionMode.Replace})
<div id = "replaceMe"></div>
Partial View:
#model MvcApplication1.Controllers.Person
<div>
Name : #Model.Name <br />
Age : #Model.Age
</div>

ViewModel not storing values when Ajax.ActionLink calling controller

When I'm clicking ActionLink and setting ViewModel values in controller I can see changes when View being rendered. But same values comes as null into Controller when I'm clicking ActionLink second time.
How do I store the value, so it comes into controller ?
View:
#Ajax.ActionLink("Click me", "AjaxTest", "Controller", new AjaxOptions()
{
UpdateTargetId = "updatePanel",
HttpMethod = "POST",
OnSuccess = "A()"
})
<div id="updatePanel">
#Html.Partial("~/Views/Shared/_UpdatableContent.cshtml", this.Model)
</div>
Controller:
[HttpPost]
public ActionResult AjaxTest(MyViewModel model)
{
model.A = "A"
return PartialView("_UpdatableContent", model);
}
Partial view _UpdatableContent:
#Html.HiddenFor(x => x.A)
#if (Model.A == "A")
{
//Draw
}
Try adding this.Model to your ActionLink following:
#Ajax.ActionLink("Click me", "AjaxTest", "Controller", this.Model, new AjaxOptions() { UpdateTargetId = "updatePanel" })
This method passes the model back into the request, which should allow the update to happen.
Probably my biggest gripe with ASP.NET MVC is the fact that the various "Helper" functions are overloaded to the nth-degree, and not always consistently in terms of the order the arguments appear...
Hope that helps :)
I had this very same problem. Setting HttpMethod = "Post" in the AjaxOptions fixed it for me, thanks Sergejs.
My final, working code is as follows
#{
AjaxOptions ajaxOptions = new AjaxOptions
{
HttpMethod = "Post",
LoadingElementId = "product-adding-" +#Model.Product.Id,
LoadingElementDuration = 100,
OnSuccess = "AddedToCart"
};
}
<div>
#Ajax.ActionLink("Add to cart",
"AddToCart",
"Cart",
new { id = Model.Product.Id, returnUrl = Request.Url.PathAndQuery },
ajaxOptions,
new { #class = "button" })
<img id="product-adding-#Model.Product.Id" src="~/Images/ajax_loader.gif" />
</div>

using a usercontrol on aspx page in MVC using partial view

I have Dropdown and on click of a button, I want to display data in the usercontrol
the below code is not working as expected.
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%
using (Html.BeginForm())
{%>
<%=Html.DropDownList("CarMake", (SelectList)ViewData["CarMake"])%>
<input type="submit" value="Get all car model" />
<%
Html.RenderPartial("CarModel");
} %>
</asp:Content>
// in controller
public ActionResult Test1()
{
ViewData["CarMake"] = new SelectList(_carDataContext.Makes.Select(m => new { ID = m.Id, Name = m.Name }), "ID", "Name");
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Test1(int carMake)
{
ViewData["CarMake"] = new SelectList(_carDataContext.Makes.Select(m => new { ID = m.Id, Name = m.Name }), "ID", "Name");
var carModel = _carDataContext.Models.Where(m => m.MakeId == carMake).ToList();
return PartialView("CarModel", carModel);
}
Since you're doing a full post of the form, you don't want to return a partial view. You want to set the ViewData["CarModel"] to the correct model, then re-render the same view. The RenderPartial in the view will use this to "include" the correct partial view in the code.
Note this would be different if you were posting via AJAX. At that point, you'd have it set up to replace a particular element of the page and you would want to only render the partial that goes into that element.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Test1(int carMake)
{
ViewData["CarMake"] = new SelectList(_carDataContext.Makes.Select(m => new { ID = m.Id, Name = m.Name }), "ID", "Name");
ViewData["CarModel"] = _carDataContext.Models.Where(m => m.MakeId == carMake).ToList();
return View();
}

Resources