MVC 5 AJax.Beginform Routevalues are generated wrongly - ajax

I am trying to post to action the current querystring. So i have created the below extension method :
public static RouteValueDictionary ToRouteValues(this NameValueCollection col, Object obj = null)
{
var values = obj != null ? new RouteValueDictionary(obj) : new RouteValueDictionary();
if (col == null) return values;
foreach (string key in col)
{
//values passed in object are already in collection
if (!values.ContainsKey(key)) values[key] = col[key];
}
return values;
}
And in my view i am using the routvalues as below:
using (Ajax.BeginForm(actionName: "Post", routeValues:Request.QueryString.ToRouteValues(), controllerName: "Request", ajaxOptions: new AjaxOptions { HttpMethod = "Post", OnSuccess = "SuccessCallBack", UpdateTargetId = "successDiv", InsertionMode = InsertionMode.InsertAfter }, htmlAttributes: new { #data_toggle = "validator" }))
{
}
But strangely when the html markup is generated the form tag action does not have the actual querystring values but instead has a string version of the object metadata.
<form action="/Request/Post?Count=5&Keys=System.Collections.Generic.Dictionary%602%2BKeyCollection%5BSystem.String%2CSystem.Object%5D&Values=System.Collections.Generic.Dictionary%602%2BValueCollection%5BSystem.String%2CSystem.Object%5D" data-ajax="true" data-ajax-method="Post" data-ajax-mode="after" data-ajax-success="SuccessCallBack" data-ajax-update="#successDiv" data-toggle="validator" id="form0" method="post" novalidate="true">

This works for me:
#using (Ajax.BeginForm(
actionName: "AddOns",
controllerName: "Basket",
routeValues: Request.QueryString.ToRouteValues(),
ajaxOptions: new AjaxOptions { HttpMethod = "Post", OnSuccess = "SuccessCallBack", UpdateTargetId = "successDiv", InsertionMode = InsertionMode.InsertAfter },
htmlAttributes: new Dictionary<string, object> { { "class", "mainForm" } }))
{
#:Blah
}
It outputs:
<form action="/Basket/AddOns?test=test" class="mainForm" data-ajax="true" data-ajax-method="Post" data-ajax-mode="after" data-ajax-success="SuccessCallBack" data-ajax-update="#successDiv" id="form0" method="post">
Blah
</form>
Please note the last parameter which is a Dictionary<string, object>.
Used this post as source: MVC3 Html.BeginForm - passing arguments as RouteValueDictionary fails

The issue is that your using named parameters and there are overloads of Ajax.BeginForm() that accept both object routeValues and RouteValueDictionary routeValues.
In your case its using object routeValues and your generating a route value for each property of RouteValueDictionary (Count, Keys, etc). I'm assuming that's because the overload with object routeValues is defined first (but have yet to find anything documenting the behavior)
You can solve this by omitting the names and using
#using (Ajax.BeginForm("Post", "Request", Request.QueryString.ToRouteValues(), new AjaxOptions { HttpMethod = "Post", OnSuccess = "SuccessCallBack", UpdateTargetId = "successDiv", InsertionMode = InsertionMode.InsertAfter }, new { #data_toggle = "validator" }))
{
}

Related

ActionLink to submit Model value

I want my Ajax.ActionLink to pass a viewModel property to action.
Here is my ViewModel
public class ViewModel
{
public string Searchtext { get; set; }
}
My .cshtml
#Ajax.ActionLink("Bottom3", "Bottom3",new { name = Model.Searchtext}, new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "pointsDiv"
})
using(Html.BeginForm("Bottom3", "Home", FormMethod.Get))
{
#Html.TextBoxFor(x => x.Searchtext)
<button type="submit">Search</button>
}
<div id="pointsDiv"></div>
}
My Controller action:
public PartialViewResult Bottom3(string name)
{
var model = db.XLBDataPoints.OrderBy(x => x.DataPointID).Take(3).ToList();
return PartialView("Partial1", model);
}
But the name parameter passed to the action is always null. How do I solve this?
In your code... you have 2 different ways of posting to the server: the link and the form button.
The problem is that the ActionLink has no way to get the value from the input in client side... just the original value.
If you press the Search button, you will see a value posted.
Now, you can use some jQuery to modify a standard ActionLink (not the Ajax.ActionLink):
https://stackoverflow.com/a/1148468/7720
Or... you can transform your Form in order to do a Ajax post instead of a normal one:
https://stackoverflow.com/a/9051612/7720
I did this for a model of mine like so. I ONLY supported the HttpPost method. So add the HttpMethod="POST" to your Ajax.ActionLink
[HttpPost]
public ActionResult Accounts(ParametricAccountsModel model)
{
if (model.Accounts == null)
{
GetAccountsForModel(model);
}
if (model.AccountIds == null)
{
model.AccountIds = new List<int>();
}
return View(model);
}
On the razor view
#Ajax.ActionLink(
"Add Account to Order", "Accounts", "Parametric", null,
new AjaxOptions() { InsertionMode = InsertionMode.Replace, UpdateTargetId = "...", HttpMethod = "POST" },
new { #id = "AddParametricAccountLink" })
The model has a list of selected account ids. So in javascript, I modified the href of the action link dynamically.
function UpdateParametricAccountAction() {
var originalLink = '/TradeNCashMgmt/Parametric/Accounts';
var append = '';
var numberOfRows = $('#ParametricAccounts').find('.parametric-account- row').size();
for (var i = 0; i < numberOfRows; i++) {
if (i != 0) {
append += '&';
}
else {
append = '?';
}
var idValue = $('#NotionalTransactionsAccountId_' + i).val();
append += 'AccountIds%5B' + i + '%5D=' + idValue;
}
$('#AddParametricAccountLink').attr('href', originalLink + append);
}
Since the model binder looks for parameter names in the query string and form submission, it will pick up values using the href. So I posted a model object using the querystring on my Ajax.ActionLink. Not the cleanest method, but it works.

Change ajax UpdatetargetID depends of model state validation MVC

Lets say i've got simple ajax begin form:
#using (Ajax.BeginForm("DodajTresc", "Administracja", new AjaxOptions { Confirm = "Czy jesteś pewien że chcesz dodać treść ?", InsertionMode = System.Web.Mvc.Ajax.InsertionMode.Replace, UpdateTargetId = "podgladDodanejTresc", LoadingElementId = "spinWiadomosci" }))
{
some code[...]
}
Is it possible to change UpdatetargetID after post depends of model state validation ?. For exmaple:
if(ModelState.IsValid)
{
UpdatetargetID="div1";
}
else
{
UpdatetargetID="div2";
}
Is there an option to achieved that ?

Clickable image in WebGrid inside a Controller (via Ajax )?

I'm using the MVC3 WebGrid inside my controller.I need to have an image in a column,such that when you click on that image, data is passed to an action inside any controller.I want to do this via Ajax, i.e. clicking on the image shouldn't cause a post back,it should be an Ajax call to an Action on some Controller.And I would like to pass an object (model), not any string,or int, or whatever).
public ActionResult AddInGrid(AjaxModel m)
{
if (Session["ajaxmodel"] == null)
{
Session.Add("ajaxmodel", a.am);
}
List<AjaxModel> list = (List<AjaxModel>)Session["ajaxmodel"];
list.Insert(0, m);
Session.Add("ajaxmodel", list);
WebGrid g = new WebGrid(list);
IHtmlString s = g.GetHtml();
string s1 = s.ToString();
return Json(new { text = s1 });
}
What should be put inside of GetHtml() method??
EDIT: Here's what I've tried so far, and it isn't working:
I've found out what HTML renders on Ajax.ActionLink and tried to incorporate that
WebGrid g = new WebGrid(list);
string link = string.Format(#"<a data-ajax='true' data-ajax-method='GET' data-ajax-mode='replace' href='/Home/Delete/{0}' />Delete</a>",item.fname);
IHtmlString s = g.GetHtml(g.Columns(g.Column(format:link)));
#grid.GetHtml(
columns: grid.Columns(
grid.Column(
columnName: "",
format:
#<text>
#Ajax.ActionLink(
"Delete",
"delete",
"home",
new AjaxOptions {
UpdateTargetId = "sometargetdiv",
InsertionMode = InsertionMode.Replace
}
)
</text>
)
)
)
As far as passing an entire model to the action is concerned, well, you could use the routeValues parameter and pass the different properties as query string parameters:
#Ajax.ActionLink(
"Delete",
"delete",
"home",
new {
fname = item.fname,
lname = item.lname
.... and so on for each property you want to fetch back
},
new AjaxOptions {
UpdateTargetId = "sometargetdiv",
InsertionMode = InsertionMode.Replace
}
)

Dynamic images and formatting parameters with #Ajax.ActionLink

I’m trying to change the following working code into Ajax.
<a href="#Url.Action("Index", new { pn = pc })">
<img src="#Url.Content("~/Photos/" + #photoFile[pc])", id = "imgnb" width = "100px" height = "150px" alt = "Photo" /></a> <br />
The code needs to handle a string[] variable, #photoFile[pc]), and take formatting, ( id = "imgnb" width = "100px" height = "150px" alt = "Photo"). (imgnb is css, no image border)
Soe Moe built an Ajax helper here Problem with ajax.actionlink helper, return string.
His code works great with a static image with no paratmeters.
#Ajax.ImageActionLink("../../Photos/Children/albersona1.jpg", "Index", new { pn = pc }, new AjaxOptions
{
UpdateTargetId = "Selected Thumbnail",
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET" })
Would anyone know how to modify this helper to convert the URL.Action into Ajax so that it handles dynamic images and formatting parameters.
Any help greatly appreciated.
Thanks, Joe
public static class ImageActionLinkHelper
{
public static IHtmlString ImageActionLink(
this AjaxHelper helper,
string imageUrl,
string actionName,
object routeValues,
object htmlAttributes,
AjaxOptions ajaxOptions
)
{
var builder = new TagBuilder("img");
builder.MergeAttribute("src", imageUrl);
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
var link = helper.ActionLink("[replaceme]", actionName, routeValues, ajaxOptions);
var html = link.ToHtmlString().Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing));
return new HtmlString(html);
}
}
and then:
#Ajax.ImageActionLink(
Url.Content("~/Photos/" + photoFile[pc]),
"Index",
new { pn = pc },
new { id = "imgnb", width = "100px", height = "150px", alt = "Photo" },
new AjaxOptions
{
UpdateTargetId = "foo"
}
)

Passing routeValues to Controller in MVC 3

i have this code in View
#using (Html.BeginForm())
{
#: Location #Html.DropDownList("territryID", (SelectList)ViewBag.Territory, "choose one")
#Ajax.ActionLink(
"ok",
"Info", new { territryID = "#territryID" },
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "post1"
})
<div id="post1">
</div>
}
and this code in my Controller
[HttpPost]
public ActionResult Info(int? territryID)
{
if (territryID == null)
{
return RedirectToAction("Info");
}
var model = (from c in _db.OCRDs
where c.Territory == territryID
select c).Distinct();
return PartialView("_getCustomerByTerritory", model);
}
how to passing my dropdownlist selected value to territryID parameter in controller, how to do that?
thanks,
erick
How about this, initialize your URL to something like this (also note the assignment of an id to the link):
#Ajax.ActionLink("ok", "Info", new { territryID = "REPLACEME" }, new AjaxOptions { InsertionMode = InsertionMode.Replace, HttpMethod = "POST", UpdateTargetId = "post1" }, new { id = "oklink" })
Replace the placeholder (REPLACEME) when the dropdown changes, like so:
<script>
$('#territryID').change(function () {
var newid = $('#territryID').val();
var oldLink = $('#oklink').attr('href');
var newLink = oldLink.replace('REPLACEME', newid);
$('#oklink').attr('href', newLink);
});
</script>

Resources