Passing whole model to controller from view via link - c#

I want to pass an entire model to the controller. Right now it passes nothing and I don't know why. The Model is partially filled in when it get's to this page, so it should atleast have some info in it.
The problem: When I click on the button on the view, the model is not passed to the controller. Not even the filled in parts!
View (that contains a model that is partially filled in)
#{
ViewBag.Title = "Winkelmand";
Layout = "~/Views/Shared/_Layout3.cshtml";
}
#model IntroSport.Models.Bestel
<br />
<br />
#if (Model.winkelmand.facturen != null)
{
<table style=" width:auto; height:auto; border-style:solid; border-color:black;">
<tr><th>Artikelnummer</th><th>Merk</th><th>Naam</th><th>Prijs</th><th>Aantal</th></tr>
#for (int i = 0; i < Model.winkelmand.facturen.Count; i++)
{
<tr>
<td>#Model.winkelmand.facturen[i].product.ProductID</td>
<td>#Model.winkelmand.facturen[i].product.Merk</td>
<td>#Model.winkelmand.facturen[i].product.Naam</td>
<td>€#Model.winkelmand.facturen[i].product.Prijs</td>
<td >#Model.winkelmand.facturen[i].Aantal</td>
</tr>
}
</table>
}
<br />
<hr />
<b>Totaal: </b>€ #Model.winkelmand.Totale_prijs
Bestel!
Controller:
public ActionResult KlantOverzicht(Bestel bestel)
{
return View(bestel);
}

You would not be able to simply provide the whole model into the #Url.Action and have it create the link with each of the fields in your model.
You essentially will need to create the link "by hand"!
From the view that you have, it appears the user is not changing any information, and most likely, you pulled the information you are displaying from a database, so if you do create the link that passes in the model, the information will match the data in your database.
My suggestion would be that instead of posting an unchanged model to the server, you simply pass in the Id of the object into your view and have the view retrieve the object from the database.
Bestel!

You can send Model to controller with <form>.
Or send all properties by link and in action collect them to a new model.
<a href="#Url.Action("Klantoverzicht", "Winkelmand",
new {
pId = Model.ProductID,
mark = Model.Merk,
name = Model.Naam,
price = Model.Prijs,
number = Model.Aantal,
})">Bestel!</a>
In action:
public ActionResult KlantOverzicht(int pId, string mrk, string nam, double price, int number )
{
Bestel model = new Bestel();
model.ProductID = pId;
model.Merk = mark;
model.Naam = name;
model.Prijs = price;
model.Aantal = number;
}

Related

Razor syntax to complete an MVC form

I'm very new to using Razor with C# and am conducting this project in order to try to better my understanding of it.
This application is supposed to, once completed, is ask the user to input three integers and then print out the sum of those integers. Right now, I have the basic frame of the View and Controller set up. (There is currently no Model.) The controller is set up to use an HTTP-Post protocol in order to send information to the HTML form.
What I'm struggling with, is the code needed to communicate the data directly to the form, as well as whatever parameters are needed so that ASP.net will ignore the presence of two identically-named controller actions (which I'm told it should be able to do once the Razor syntax is set up properly).
Any guidance here would be very helpful. (Note: It is a requirement that I use the HTTP Post protocol in the finished solution.)
Controller:
public ActionResult Index(int firstInt = 0, int secondInt = 0, int thirdInt = 0)
{
return View();
}
[HttpPost]
public ActionResult Index(int firstInt = 0, int secondInt = 0, int thirdInt = 0)
{
int sum = firstInt + secondInt + thirdInt;
ViewBag.result = sum;
}
Index View:
<form action="" method="post">
<table>
<tr><td>Enter the 1st Number: <input id="firstInt" name="firstInt" type="text" value="0" /></td></tr>
<tr><td>Enter the 2nd Number: <input id="secondInt" name="secondInt" type="text" value="0" /></td></tr>
<tr><td>Enter the 3rd Number: <input id="thirdInt" name="thirdInt" type="text" value="0" /></td></tr>
<tr>
<td><input id="Submit" type="submit" value="submit" /><input id="Reset" type="reset" value="reset" /></td>
</tr>
<tr>
<td>Sum = #ViewBag.result</td>
</tr>
</table>
</form>
You need to make sure your methods with same name has unique signature. Since you mentioned the user enter the numbers via the form, there is no reason to have those params in the GET action method. Just remove it and it should work now.
public ActionResult Index()
{
return View();
}
Also you need a return View(); statement in your HttpPost action. Otherwise you will get a compilation error.
[HttpPost]
public ActionResult Index(int firstInt = 0, int secondInt = 0, int thirdInt = 0)
{
int sum = firstInt + secondInt + thirdInt;
ViewBag.result = sum;
return View();
}
If you are going to have many parameter values coming from the form, i would advise creating a view model which has those properties and use that as the parameter.
Normally what you do for Razor views is declare the Model, and use the Razor methods to output the form and form elements. As Shyju says, you need unique signatures on the actions.
#using MyModelNamespace
#model MyModel
#using (Html.BeginForm("Index", "HomeController", routevalues, etc..) {
Html.TextBoxFor(m => m.firstInt);
}
Your post action should take the model as a parameter
public ActionResult Index() {
return View();
}
[HttpPost]
public ActionResult Index(MyModel m) {
int sum = m.firstInt + m.secondInt + m.thirdInt;
ViewBag.result = sum;
return View(m);
}
You can set ViewBag state in your action.

MVC Maintaining Model through multi view form submits

So I am working on a MVC which is basically three steps.
Create a view for each step i.e.
StepOne
StepTwo
StepThree
On step one and two I ask the users to enter some details.
All the values for the multiple step I store in one Model.
And getting from StepOne to StepTwo is fine. Certain values in my model are being set and maintained.
But on StepTwo when I do my second httppost and pass the model, it seems to just create a new instance of the model and values from stepone are not maintained.
<% using (Html.BeginForm("StepTwo", "Home", FormMethod.Post, new { id = "restrictionForm" })) { %>
<%: Html.AntiForgeryToken() %>
<div id="wrapping" class="clearfix">
<h3>Postcode Restriction Type : </h3>
<%= Html.DropDownListFor(x => x.SelectedRestriction, Model.RestrictionTypes,"Select Restriction...", new { #class = "selmenu required" }) %>
<h3>Restriction Description : </h3>
<%= Html.TextBoxFor(m => m.RestrictionDescription, new { #class = "txtblock required" }) %>
</div>
<section id="buttons">
<input type="submit" value="Submit" id="submitBtn" />
</section>
And in my controller
On Page Load my Model is still intact and still maintains values from previous step.
[Authorize]
public ActionResult StepTwo(PostcodesModel model)
{
var summaryMessage = "";
model.SummaryMessage = summaryMessage;
model.RestrictionTypes = _Provider.GetRestrictionTypes();
return View(model);
}
But at the Httppost, the model has lost values and seems to have created new instance of model.
[Authorize]
[HttpPost]
[ActionName("StepTwo")]
[ValidateAntiForgeryToken]
public ActionResult StepTwoPost(PostcodesModel model)
{
return View(model);
}
Any idea how I can maintain model between Http Posts ?
It seems from your question that you believe models persist across requests. This is not true.
You either pass information to the view via your model from the controller, or submit values from your view to your controller and MVC handles this by binding html form inputs to your View Model.
If you want to persist your View Model across each step you need to take the values accepted and copy them into a new model (or directly inject it) when calling your new view.
Something like this (I just typed this up off my head so its not clean but should give you an idea):
[HttpGet]
public ActionResult StepOne()
{
var model = new MyNewModel();
return View(model);
}
/* NOTE THE MODEL PASSED BACK HERE IS NOT THE EXACT SAME OBJECT
AS THE ONE CREATED IN THE GET ACTION ABOVE, MODEL BINDING HAS OCCURRED
TO READ YOUR FORM INPUTS AND MATCH THEM TO A NEW MODEL WHICH IS EXPECTED */
[HttpPost]
public ActionResult StepOne(MyNewModel model)
{
if (ModelState.IsValid)
{
// Do something here
// pass model to new view
TempData["model"] = model;
return RedirectToAction("StepTwo");
}
return View(model);
}
[HttpGet]
public ActionResult StepTwo()
{
MyNewModel model;
if (TempData["model"] != null)
{
model = (MyNewModel) TempData["model"];
// make some changes if necessary
model.MyProperty = 2;
return View(model);
}
return RedirectToAction("StepOne");
}
I think you can also keep your model in Session ( per application ) or in a ViewState ( per page ).
Every time you make a post you upgrade the session. It's also optimal because on the client side you receive only a session identifier.
Some differences between Session and Viewstate:
Session is per application, while ViewState is per page
Session sends to the client side only a session identifier, while ViewState sends an ecrypted text

html actionLink parameters to view

I'm a noob in .Net and all the web developpement :s
I'm having an issue using html.BeginForm and html.ActionLink.
I got this in my homeWeb.cshtml:
#using (Html.BeginForm("resultWeb", "Result", new { val = 1 }, FormMethod.Post ))
{
<div class="main-block">
<input style="width:100%;" type="text" name="searchValue" /><br />
<div style="text-align: center;">
<input type="submit" value="Submit" />
</div>
</div>
}
its calling my result controller and my resultWeb view sending the val = 1 as parameter
here is my ResultController.cs:
[HttpPost]
public ActionResult resultWeb(int val, FormCollection collection)
{
List<WebSite> list = new List<WebSite>();
// Doing stuff with my list and the val
return View(list);
}
this part is working and well sending the parameter to my view.
The problem is when i try to do the same thing with an html.ActionLink on an other page
resultWeb.cshtml:
<tr>
#for (int i = 0; i <= Model.Count / 15; i++)
{
int j = i + 1;
<td>#Html.ActionLink(#j.ToString(), "resultWeb", new { val = j })</td>
}
</tr>
And when i click on one of the links, it doesn't work i got this error:
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Result/resultWeb/1
I guess i'm doing something wrong but i don't understand what. Does someone can help me on this ?
Thanks !
Actionlinks can't post a form/data to a controller. All they do is create <a> tags.
If you want to submit the form with an actionlink, you could use the #Ajax.ActionLinkhelper, or just post the form with jquery alltogether.
Also, this question has been asked lots of times before on stackoverflow, like here or here.
Thousands Answer is correct you cannot Post data via ActionLinks. If your FormsCollection is not too large then you can use Query Strings.
This is what I have done
Controller:
public ActionResult Index(string loc, string ma, string mo, int co = 0, int mi = 0)
{
search c = new search() { loc = loc, ma = ma, co = co, mo = mo, mi = mi }
/*replace search() and query string variables with your FormsCollection*/
/*Do thing here*/
return View(DisplayModel)
}
MyModels
public class DisplayModel
{
public search Search { get; set; }
public List<Website> Result { get; set; }
}
public class Search
{... All my search variables in this model}
And finally the View
#model MyApp.Models.DisplayModel
<div>
#using (Html.BeginForm("Index", "Buying", FormMethod.Get)){
<fieldset>
<legend>My form</legend>
<input id="ma" name="ma" type="hidden" disabled="disabled" value="#Model.Search.ma" />
... The way you choose to display your your view. You can either keep the same form hidden or
<input type="submit" value="mybutton"/>>
</fieldset></div>
#foreach( var item in Model.Result)
{
... The way you choose to display your List.
}

Load View again by passing updated parameter to the same Controller MVC 3

I want to load the same view again by passing updated parameter from text input on the link click. I tried to use something like <a href="#Url.Action("Index", "Home", new {id = "txtCount".value }). Not sure if there is even a way to do this. I know I could use partial but I want to reload the whole page with updated parameter. Thanks in advance for any help.
Controller
[HttpGet]
public ActionResult Index(int id)
{
return View(id);
}
View
#model int
#using (#Html.BeginForm())
{
<input id="txtCount" value="1" />
Update
for (int i = 0; i < Model; i++)
{
<div>#i </div>
}
}
Maybe something like this
Go!
and binding with jquery
$("#mylink").click(function(){
document.location.href = '#Url.Content("~/Controller/Action")' + $("#mytxt").val();
return false;
});
Obviously with the proper validations if the textbox is empty and all that stuff.
You cannot add the id value to the #Url.Action because it is processed before on the server side, before the page is rendered

Passing data from View to Controller

In an ASP.NET MVC application, I'm making logic for Admin to accept or reject new members. I'm showing a list of members and two buttons Accept and Reject, like this:
<% foreach (var mm in (ViewData["pendingmembers"] as List<MyMember>)) %>
<% { %>
<tr><td>Username:<%=mm.UserName %></td><td>
<tr><td>Firstname:<%=mm.FirstName %></td><td>
...etc...
<tr>
<td>
<% using (Html.BeginForm("AcceptPendingUser", "Admin"))
{ %>
<input type="submit" value="Accept" />
<% } %>
</td>
<td>
<% using (Html.BeginForm("RejectPendingUser", "Admin"))
{ %>
<input type="submit" value="Reject" />
<% } %>
</td>
</tr>
<% } %>
So, the list of pending member data is in a list of MyMember-objects. Each MyMember object will be printed out member and two buttons are setup for the admin to either accept or reject a pending member.
Then, in the controller I'm separating the handling of those two input fields/forms, like this:
public ActionResult AcceptPendingUser()
{
// TODO: Add code to save user into DB and send welcome email.
return RedirectToAction("Index");
}
public ActionResult RejectPendingUser()
{
// TODO: Add code to remove user from PendingUsers list and send rejection email.
return RedirectToAction("Index");
}
I would like to directly get the object next to the button the user pressed.
How can I send the MyMember object from the View to the controller?
Or how do I send perhaps a numeric index with button press? Maybe with a hidden field?
The simplest option would probably be a hidden input:
<input type="hidden" value="<%=mm.Key%>" name="key" id="key" />
(name accordingly; in each form)
The two controller would then take an argument called "key" (rename to suit). If you want to parse the object from multiple inputs, you'll need a ModelBinder. Of course, rather than 2*n forms, you might consider either query-string based urls, or use something like jQuery (or some other script helper) to submit the data without needing the forms (if script is available).
Instead of using an HTML button consider using an ActionLink and construct it to include the id of the member being approved. Another alternative would be to have a checkbox (whose value is the id of the member being approved) that the admin can select for each member to be approved and a similar one for reject and one each approve/reject buttons for the entire form.
Answering to myself and other mvc newbies:
I got it finally working with this code:
VIEW:
<%=Html.ActionLink(
"Jump",
"Jump",
new { name=(ViewData["Person"] as Person).Name,
person=ViewData["Person"]},
null) %>
CONTROLLER:
public ActionResult Index()
{
ViewData["Title"] = "Home Page";
ViewData["Message"] = "Welcome to ASP.NET MVC!";
Person p = new Person();
p.Name = "Barrack";
p.Age = 35;
ViewData["Person"] = p;
return View();
}
public ActionResult Jump(string name, Person person)
{
return View();
}
Debugging the app in the Jump method gives me nice "Barrack"-string for the name parameter, but Person parameter in null.
I also understand what the kind commenters tried to explain: it's easy to send simple data types like strings and ints to controller, but complex types such as my Person object needs something else.
Basically passing an int is enough for me. The hardest part here was figuring out the right way to set up ActionLink.
Cheers,
Pom

Categories