Update and ASP.NET MVC model on button click - asp.net-mvc

I'm new to ASP.NET MVC. I'm trying to update model on button click with no success: every time I push the button an HttpGet controller method is invoked.
Here is my markup
#model DataInterface.Model.Entry
<button onclick="location.href='#Url.Action("Survey")'">Finish survey</button>
Here is Controller code
[HttpGet]
public ActionResult Survey()
{
var entry = new Entry();
return View(entry);
}
[HttpPost]
public ActionResult Survey(Entry newEntry)
{
// save newEntry to database
}
When I click button HttpGet method is invoked. Why?
It is bad to be a rookie)
Thanks to all!

If you access a URL without explicitly specifying the HTTP method, ASP.NET MVC will assume a GET request. To change this, you can add a form and send it:
#using (Html.BeginForm("Survey", "Controller", FormMethod.Post))
{
<input type="submit" value="Finish survey" />
}
If you do this, your POST method will be invoked. The Entry parameter, however, will be empty, since you do not specify any values to send along with the request. The easiest way to do so is by specifying input fields, e.g. text inputs, dropdown, checkboxes etc.
#using (Html.BeginForm("Survey", "Controller", FormMethod.Post))
{
#Html.TextBoxFor(m => m.Title)
<input type="submit" value="Finish survey" />
}
If you have the object stored on the server somewhere and only want to finish it off by writing it into the database or changing its status, you could pass the Id of the object (or some temporary Id) along the post request and make the controller method work only with the Id:
#using (Html.BeginForm("Survey", "Controller", FormMethod.Post))
{
#Html.HiddenFor(m => m.Id)
<input type="submit" value="Finish survey" />
}
[HttpPost]
public ActionResult Survey(Entry newEntry)
{
// newEntry.Id will be set here
}

#using (Html.BeginForm("Survey", "<ControllerName>", FormMethod.Post))
{
<input type="submit" value="Finish survey" />
}

you must declare your form
#model DataInterface.Model.Entry
#using (Html.BeginForm("action", "Controlleur", FormMethod.Post, new {#class = "form", id = "RequestForm" }))
{
<input type="submit" value="Finish survey" />
}

Related

How to pass model values from a view to a controller?

I'm using VSCode in Mac creating a MVC.
The parameter "new { problem = #Model }" shouldn't pass the values from the view to the controller?
View code:
#model ProblemsV4.Models.ProblemModel
<h2>New Solution</h2>
#using(Html.BeginForm("SaveSolution", "Problem", new { problem = #Model }, FormMethod.Get))
{
<label>Solution: </label>
<input type="text" name="solution" /><br/><br/>
<input type="submit" value="Save"/>
}
Controller code:
public IActionResult SaveSolution(ProblemModel problemModel, string solution)
{
SolutionModel model = new SolutionModel();
model.Solution = solution;
ProblemBC bc = new ProblemBC();
bc.AddSolution(model);
List<ProblemModel> models = bc.ListAll();
ViewBag.Message = "Solução inserida com sucesso";
return View("Index", models);
}
You should receive a HttpPost at the controller and send the parameters of the model with a HiddenFor, a type of
HtmlHelper that doesn't shows any input.
The BeginForm method has many signatures, one of them contains the Object routeValues, that is an object that contains the parameters for a route. You don't need to use that,
you can use other signature like this: https://msdn.microsoft.com/en-us/library/dd460344(v=vs.118).aspx
First step:
[HttpPost]
public IActionResult SaveSolution(ProblemModel problemModel, string solution)
{
SolutionModel model = new SolutionModel();
model.Solution = solution;
ProblemBC bc = new ProblemBC();
bc.AddSolution(model);
List<ProblemModel> models = bc.ListAll();
ViewBag.Message = "Solução inserida com sucesso";
return View("Index", models);
}
Second step:
#model ProblemsV4.Models.ProblemModel
<h2>New Solution</h2>
#using(Html.BeginForm("SaveSolution", "Problem", FormMethod.Post))
{
<label>Solution: </label>
<input type="text" name="solution" /><br/><br/>
#Html.HiddenFor(model => model.Problem)
#Html.HiddenFor(model => model.Description)
#Html.HiddenFor(model => model.ID)
<input type="submit" value="Save"/>
}

Pass argument to controller on submit

So, i started learning MVC, and i need to pass an email to a controller. (Trying to make a standard email signup)
Therefore i have an input and a button which (should) pass the input to an argument accepting controller and then redirect to another view.
I have the following controllers:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string mail)
{
person = new EmailSignup{Email = mail};
return RedirectToAction("details");
}
public ActionResult details()
{
return View(person);
}
This is what i have in my View:
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<form class="col-md-12">
<div class="form-group form-inline">
<label class="margin20">Sign up for newsletter</label>
<input type="Email" class="form-control" style="display:inline-block; max-width:200px" id="mail" placeholder="Example#Example.com" />
<button type="submit" class="btn btn-default" style="display:inline-block" id="emailSignup">Signup</button>
</div>
</form>
}
It redirects to my "details" view, but my email is not showing.
Furthermore, is this best practice? would i want to do it like this?
#using (Html.BeginForm("Index", "Home", FormMethod.Post)) renders a form, you don't need a second one inside it (if you need to add the class, you can use an overload of Html.BeginForm). Your input contains an id property, but not a name property. name is what's used when an action happens inside a form.

What should I do when more than one submit cases exist

I have a form where I fill in a blank and then save it, which takes me to the read only version of the entry I've just saved. At this step I have 2 options:
Either "Confirm" or "Cancel". Both actions will update some values in the database, so they're both good candidates for submit button(HttpPost, of course). I know this shouldn't be tied to a particular web development technology as
all-in-all it's all about Request and Response, but still I'll talk in ASP.NET MVC "language" as that is what I'm using now. So far, the only idea that has come to my mind is to have a separate submit buttons with different names and on the server side check for the name and act accordingly. But this seems a bit ugly to me as I might have to have a huge and universal action method. Do you have any better approach? Maybe MVC has some built in way for this purpose?
huge and universal action method
That's entirely your responsibility. You write action methods to map HTTP requests to business logic.
public class PostModel<T>
{
public string SubmitAction { get; set; }
public T TheModel { get; set; }
}
public ActionResult HandleSomePost(PostModel<Foo> model)
{
switch (model.SubmitAction.ToUpperInvariant())
{
case "SAVE":
_yourBLL.Save(model.TheModel);
break;
case "CANCEL":
_yourBLL.Cancel(model.TheModel);
break;
default:
throw new ArgumentException("SubmitAction");
}
return View();
}
Then you can handle both submit buttons from this form:
#using (Html.BeginForm("HandleSomePost", "TheController", FormMethod.Post))
{
#Html.EditorFor(m => m.TheModel)
<input type="submit" name="SubmitAction" value="Cancel">
<input type="submit" name="SubmitAction" value="Save">
}
However, this will quickly become a mess. You can also use attributes to let submit buttons map to action methods (though for simplicity I removed the "action:" prefix used for localization, be sure to read that Q&A and the linked blog):
[HttpPost]
[MultipleSubmit(SubmitAction = "Save")]
public ActionResult Save(Foo model)
{
_yourBLL.Save(model);
return View();
}
[HttpPost]
[MultipleSubmit(SubmitAction = "Cancel")]
public ActionResult Cancel(Foo model)
{
_yourBLL.Cancel(model);
return View();
}
You could do this with 2 forms, each posting to different action methods:
<form method="post" action="/cancelAction">
<input name="id" type="hidden" value="some-id-value">
<input type="submit" value="Cancel">
</form>
<form method="post" action="/confirmAction">
<input name="id" type="hidden" value="some-id-value">
<input type="submit" value="Confirm">
</form>
Or using MVC Razor syntax since you mentioned it:
#using (Html.BeginForm("cancelAction", "MyController", FormMethod.Post))
{
#Html.HiddenFor(model => model.ID)
<input type="submit" value="Cancel">
}
#using (Html.BeginForm("confirmAction", "MyController", FormMethod.Post))
{
#Html.HiddenFor(model => model.ID)
<input type="submit" value="Confirm">
}
From the information above it seems hard to pin down the exact use case here, however it might not be neccessary to have both a post for the confirm and cancel.
Consider using the submit event for "confirmation" and then just call the cancel event using normal HTTP-GET and passing the item that needs to be cancelled's ID? Then you can either handle the confirm or cancel events in either of the Actions directly or do a RedirectToAction to the HugeUniversalAction.
#using (Html.BeginForm("Confirm","ExampleController",FormMethod.Post))
{
<input type/>
<input type="submit" value="confirm"/>
#Html.ActionLink("Cancel", "ExampleController", id = Model.Id)
}
Then in your controller you can call the larger universal method.
public ActionResult Cancel(int id)
{
// Cancel directly
// or
return RedirectToAction("HugeUniversalAction", new { confirm = "false", id = id });
}
[HttpPost]
public ActionResult Confirm(Foo model)
{
// Confirm Directly
// or
return RedirectToAction("HugeUniversalAction", new { confirm = "true", id = model.Id });
}
Then handle the two paths in whichever way you need to in your HugeUniversalAction
public ActionResult HugeUniversalAction(int id, confirm = false){ // If confirm confirm it else cancel it }

How can I get both a model and HttpPostedFileBase into a controller?

I've looked quite a bit online, and every example I see explains how to get IEnumerable<HttpPostedFileBase> into a controller, OR how to get a model, but not both.
What I want is something like:
<form>
<input type="text" name="Stored file name>
<input type="file" multiple="multiple" name="files>
<input type="submit">
</form>
with controller
[ActionName("Index"), HttpPost]
public ActionResult IndexPost(Models.MyModel mdl, IEnumerable<HttpPostedFileBase> files)
{
// Do some something with the data in mdl and files here
return RedirectToAction("Index");
}
But every way I try to implement this, it comes back 'no parameterless handler found'. It works fine if I don't include the model.
Am I missing something really obvious?
I guess you couldn't find Darin's this post. It's not exactly about passing model with HttpPostedFileBase but if you undrerstand the behavior the it's easy to do that.
See below example.
View
#model WebApplication2.Models.MyModel
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.HiddenFor(m => m.Id)
<input type="file" name="file" />
<input type="submit" value="OK" />
}
Action Method
[HttpPost]
public ActionResult Index(MyModel model, HttpPostedFileBase file)
{
if (file != null)
{
//do your stuff here
}
return View();
}

MVC Model validation on "HttpPostedFileWrapper"

Can someone help me with model validation on a HttpPostedFileWrapper object?
Model:
[Required(AllowEmptyStrings = false)]
public HttpPostedFileWrapper BlahFile { get; set; }
Controller:
[HttpPost]
public ActionResult LoadBlahData(BlahModel blahModel)
{
if (!ModelState.IsValid)
return RedirectToAction("Index");
}
cshtml:
#using (Html.BeginForm("LoadBlahData", "Admin", FormMethod.Post, new { #class = "blahhForm", enctype = "multipart/form-data", id = "uploadBlah" }))
{
<fieldset>
<legend>Upload Blah Information</legend>
#Html.LabelFor(x=>x.BlahFile, "Upload Blah file:")
<input size="26" class="uploader" type="file" name="BlahFile" />
<p><input class="ttButton" type="submit" value="Load Stuff" /></p>
</fieldset>
}
Problem:
Cannot see the "data-val*" attributes being added to the html.
Does not set the unobtrusive validation off (red border on input box)
Notes:
Other items in the Model are working fine with validation, its only the <input type="file"/> that seems to be having problems.
Comes into the action method fine - (i.e - i can access the InputStream if i want).
All scripts are referenced correctly (its working on normal text input's)
Thanks in advance,
Just for anyone else coming across this question you can also do this -
<%: Html.TextBoxFor(x => x.BlahFile, new { type = "file" }) %>
you have not added any data attributes to your element. Add it like,
<input data-pk="1" size="26" class="uploader" type="file" name="BlahFile" />
and there is no support of validation of <input type="file"

Resources