I would like to pass a model and an int to a controller upon clicking an ActionLink.
@Html.ActionLink("Next", "Lookup", "User", new { m = Model.UserLookupViewModel, page = Model.UserLookupViewModel.curPage }, null)
Does not work, instead it passes a blank instance of the model, which one would expect when using new.
@Html.ActionLink("Next", "Lookup", "User", Model.UserLookupViewModel, null)
Does work.
Controller
[HttpGet]
public ActionResult Lookup(UserLookupViewModel m, int page = 0)
{
return this.DoLookup(m, page);
}
View model
public class UserLookupViewModel
{
public int curPage { get; set; }
[Display(Name = "Forenames")]
public string Forenames { get; set; }
[Display(Name = "Surname")]
public string Surname { get; set; }
[Display(Name = "DOB")]
public DateTime? DoB { get; set; }
[Display(Name = "Post code")]
public string Postcode { get; set; }
}
How can I pass them together? The Lookup method’s arguments match the named properties in the ActionLink.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You can’t use an ActionLink to pass properties with a Link but you can do the following to get the same behavior.
<form action="/url/to/action" Method="GET"> <input type="hidden" name="Property" value="hello,world" /> <button type="submit">Go To User</button> </form>
If you create a helper to generate these GET forms, you will be able to style them like they are regular link buttons. The only thing I caution against is that ALL forms on the page are susceptible to modification so I wouldn’t trust the data. I’d rather just pull the data again when you get to where you are going.
I use the technique above when creating search actions and want to retain a search history and keep the back button working.
Hope this helps,
Khalid 🙂
P.S.
The reason this works.
@Html.ActionLink("Next", "Lookup", "User", Model.UserLookupViewModel, null)
Is because the parameter list of the ActionLink method is generalized to take an object, so it will take anything. What it will do with that object is pass it to a RouteValueDictionary and then try to create a querystring based on the properties of that object.
If you say that method is working above, you could also just try adding a new property to the viewmodel called Id and it will work like you wanted it to.
Method 2
You’ll have to serialize your model as a JSON string, and send that to your controller to turn into an object.
Here’s your actionlink:
@Html.ActionLink("Next", "Lookup", "User", new { JSONModel = Json.Encode(Model.UserLookupViewModel), page = Model.UserLookupViewModel.curPage }, null)
In your controller, you’ll need a method to turn your JSON data into a MemoryStream:
private Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
In your ActionResult, you turn the JSON string into an object:
public ActionResult YourAction(string JSONModel, int page)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Model.UserLookupViewModel));
var yourobject = (UserLookupViewModel)ser.ReadObject(GenerateStreamFromString(JSONModel));
}
Method 3
While I highly suggest you use a form to accomplish what your attempting to do here for security sake.
@Html.ActionLink("Next", "Lookup", "User", new
{ Forenames = Model.UserLookupViewModel.Forenames,
Surname = Model.UserLookupViewModel.Surname,
DOB = Model.UserLookupViewModel.DOB,
PostCode = Model.UserLookupViewModel.PostCode,
page = Model.UserLookupViewModel.curPage }, null)
MVC will map the properties appropriately doing this; however, this will use your url to pass the values to the controller. This will display the values for all the world to see.
I highly suggest using a form for security sake especially when dealing with sensitive data such as DOB.
I personally would do something like this:
@using (Html.BeginForm("Lookup", "User")
{
@Html.HiddenFor(x => x.Forenames)
@Html.HiddenFor(x => x.Surname)
@Html.HiddenFor(x => x.DOB)
@Html.HiddenFor(x => x.PostCode)
@Html.HiddenFor(x => x.curPage)
<input type="submit" value="Next" />
}
You can have multiple of these type of forms on the page if needed.
Your controller then accepts a post but functions the same way:
[HttpPost]
public ActionResult Lookup(UserLookupViewModel m, int page = 0)
{
return this.DoLookup(m, page);
}
Method 4
Please try this solution:
@{
var routeValueDictionary = new RouteValueDictionary("");
routeValueDictionary.Add("Forenames",Forenames);
routeValueDictionary.Add("Surname",Surname);
routeValueDictionary.Add("DoB ",DoB );
routeValueDictionary.Add("Postcode",Postcode );
routeValueDictionary.Add("Page",PageNum );
// Add any item you want!
}
@html.ActionLink("LinkName", "ActionName", "ControllerName",
routeValueDictionary , new{@class="form-control"})
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0