I am having 2 buttons namely Save and Cancel on my Profile.cshtml. Now my method is something like:
[HttpPost]
public ActionResult Profile()
{
//code..
}
This save the records into database. But problem is because Cancel also posts here, the record is saved in database anyway. How do I handle this?
In the view you could have 2 forms (one for each button), where the action of each form posts to the relevant action method in the controller. For example, in the view:
#using (Html.BeginForm("Save", "Profile"))
{
<input type="submit" value="Save"/>
}
#using (Html.BeginForm("Cancel", "Profile"))
{
<input type="submit" value="Cancel"/>
}
Then in the controller:
[HttpPost]
public ActionResult Save()
{
...
}
[HttpPost]
public ActionResult Cancel()
{
...
}
I often use a viewmodel class passed to a view, and in that viewmodel I have:
public string submit { get; set; }
public bool SaveButtonClicked()
{
return this.submit.Equals("save");
}
public bool CancelButtonClicked()
{
return this.submit.Equals("cancel");
}
Then in the controller
[HttpPost]
public ActionResult Save(MyViewModel inputViewModel)
{
if(inputViewModel.SaveButtonClicked()) {}
blah.......
}
My view looks like this
#using (Html.BeginForm())
{
// Other stuff.
<input type="submit" name="submit" value="Save" />
<input type="submit" name="submit" value="Cancel" />
}
This works really well for me. By having the submit buttons use the same name, when either one is pressed, that name is passed to the submit property of the viewmodel. Not sure if having duplicate names is a bad idea, but for my needs it's fine.
This sounds like your cancel button has the type attribute set to submit. This will make the form submit as though you were pressing a save button.
The question you should ask yourself is what do you want the 'Cancel' button to do? It may be better to make a button that goes to another page if it's just a case of not finishing the form, otherwise if you need to point it towards an ActionResult then you will have to do a redirect for that to work.
Feel free to ask any questions if you need.
normaly you have the Save-button to submit your form and the cancel-"button" is just an ActionLink pointing back to your index or whatever.
Related
Im trying to sending data from controller to view and then Im trying to get data back to another action.
In my case I am trying to send a View with Model and datay(Date,Id,Room) from the controller. In the view I want to add the Name value to the submitted model and then send the whole model back to the next controller action. The problem is that in the next action only the Name value is shown and the other values are null. Does anyone know what to do?
Model im using.
public class ReservationModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public DateTime Cas { get; set; }
public RoomModel Room { get; set; }
}
Action where from Im displaying the View with data Cas, Id and Room
[HttpGet]
[Route("Home/Room/Create_reservation")]
public async Task<IActionResult> CreateReservation(DateTime date)
{
ReservationModel reservation = await _reservation.PrepareModel(date, _id);
return View(reservation);
}
The view where I wanna add Name value and send it whole back.
#model ReservationModel
<form asp- asp-controller="Home" asp-action="CreateReservation" method="post">
<input required="required" type="text" class="form-control scan" placeholder="Name"
asp-for="Name" />
<span asp-validation-for="Name" class="text-danger"></span>
<input type="submit" class="model-close button btn btn-primary primary-btn"
style="width:auto;" value="Add" />
</form>
Action where in debuging show that reservationModel has only Name data other is null.
[HttpPost]
[Route("Home/Room/Create_reservation")]
public IActionResult CreateReservation([Bind("Name","Room","Cas","Id")] ReservationModel reservationModel)
{
return View();
}
If you want to transfer every field in the model then you'd need inputs for every field in the model. Currently you only have one input for Name:
<input required="required" type="text" class="form-control scan" placeholder="Name" asp-for="Name" />
Since you're only sending the Name value, then only the Name value is sent.
Based on a comment above:
Im trying just to add Name value to data I have send from CreateReservation and in Post Action just save whole model to Database.
Then there are two pieces of data you want, the Name and the Id. Include the Id as another input:
<input type="hidden" asp-for="Id" />
Then in the resulting controller action you'll have both the Name and the Id. Arguably you should create a custom view model for this and not use the same model, just to avoid future confusion. But for the sake of brevity here the same model will work. It will just only have those two properties populated, since they're the only two you're populating.
In that controller action you would use that Id value to fetch the entire model from the data again. Then you'd update that model instance with the Name which was provided by the input, and re-save that fetched model instance.
Making some assumptions, but just to illustrate:
[HttpPost]
[Route("Home/Room/Create_reservation")]
public IActionResult CreateReservation([Bind("Name","Id")] ReservationModel reservationModel)
{
// fetch from the db
var existingModel = _context.Reservations.Single(r => r.Id == reservationModel.Id);
// update the value
existingModel.Name = reservationModel.Name;
// save
_context.SaveChanges();
// as an aside, this should probably be a redirect and not a view
return View();
}
After all, why send all that data to the client and then back to the server if you're not expecting the client to do anything with it, or even see it? Even populating hidden form fields, you're still giving the client the ability to edit all of the other data. (Which means it's also worth noting here that the client can edit the id value, so you'll want to perform some kind of authorization to make sure they're not editing an object they're not allowed to edit.)
I have a basic MVC form that allows a user to submit a zip code and after clicking submit, the user should be redirected to a new view. My code seems to redirect to the next action successfully. However after the redirect, the controller returns back to the original action, so to the user, the page next changed at all.
Here's my View code:
#using (Html.BeginForm("PricingQuote", "Home", FormMethod.Post, new { #class = "rd-mailform text-center offset-top-30" }))
{
<div class="form-group">
<label class="form-label" for="contact-zip">Zip Code</label>
<input class="form-control" id="contact-zip" type="text" name="zip" data-constraints="##Required">
</div>
<button class="btn btn-primary offset-top-30" type="submit">GET STARTED</button>
}
Here's the PricingQuote action in my HomeController. This action redirects to the Pricing action in my Pricing controller:
[HttpPost]
public ActionResult PricingQuote(string zipCode)
{
return RedirectToAction("Pricing", "Pricing");
}
Here's my PricingController:
public class PricingController : Controller
{
// GET: Pricing
public ActionResult Pricing()
{
return View();
}
}
So, after clicking GET STARTED, it accesses my Home/PricingQuote action. This action then tries to redirect to the Pricing/Pricing action, which it does however, the code then seems to (incorrectly) return back to Home/PricingQuote and exits the action.
Any idea how I can redirect & display my Pricing view?
Thanks
Pass the controller in as the second parameter:
[HttpPost]
public ActionResult PricingQuote(string zipCode)
{
return RedirectToAction("Pricing", "PricingController");
}
Thanks for your responses. I was able to figure out my problem. The name of the action I was trying to redirect to ("Pricing") was the same name as my controller ("Pricing"). As a test, I renamed my action to "PricingA" & it worked, so apparently based on this, an action cannot be the same name as the controller when attempting a "RedirectToAction", which I was unaware of (at least that's my assumption based on the results I've found).
Unfortunately, I tried googling for some add'l evidence of this, to provide with this answer, but was unable to find any.
This works:
HomeController:
[HttpPost]
public ActionResult PricingQuote(string zipCode)
{
return RedirectToAction("PricingA", "Pricing");
}
Pricing Controller
[HttpGet]
public ActionResult PricingA()
{
return View();
}
I want to show one TextBox. In that if give any input string and button clicked it should so like this
hai , what is ur name
[TextBox]
welcome,ur name is "xyz"
I am new in MVC. Please help me to do this.
View
#{
ViewBag.Title = "MyPage";
}
<h2>Mymethod</h2>
<h3>#ViewBag.Message</h3>
#Html.TextBox("Name")
<form method="post">
<input type="submit" value="Submit" name="btn" />
</form>
HomeController.cs
public ActionResult Mymethod()
{
ViewBag.Message = "Hello what is ur name ??? ";
return View();
}
There are many ways to do this to accomplish what you want. I will provide you with a simplistic approach, please modify and change it to fit in with your scenario.
I would normally recommend using a view model above any other way, for example using a single string value or using FormCollection or ViewBag. They can work but I prefer to use view models.
I answered a question on what view models are and what they are supposed to do, please read it:
What is ViewModel in MVC?
First you will create a view model that will handle your input data, like first name, last name, age, etc. You will then pass this view model through to the view. In your example I will only include name:
public class ViewModel
{
public string Name { get; set; }
}
In your Create action method you will instantiate this view model and pass it to the view. And when you click on the button to submit the form then the post action method will receive this view model as input parameter:
public ActionResult Create()
{
ViewModel model = new ViewModel();
return View(model);
}
[HttpPost]
public ActionResult Create(ViewModel model)
{
if (!ModelState.IsValid)
{
// If validation fails send the view model back to the view and fix any errors
return View(model);
}
// Do what you need to do here if there are no validation errors
// In your example we are posting back to the current view to
// display the welcome message
return View(model);
}
And then finally you view will look like this:
#model Project.Models.ViewModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.Name)
<button type="submit">Submit</button>
if (!string.IsNullOrWhiteSpace(Model.Name))
{
<p>welcome, your name is #Model.Name</p>
}
}
Please spend some time reading through the many online tutorials on ASP.NET MVC.
Modify your current view to
#using(Html.BeginForm("ControllerName","Mymethod",FormMethod.Post))
{
<input type="submit" value="Submit" name="btn" />
}
Add another action method in your controller like this :
[HttpPost]
public ActionResult Mymethod(FormCollection form)
{
string Name = form["Name"];
Viewbag.Name = Name;
return View()
}
Then add view to this controller and write this into it.
Hi , Your Name is #Viewbag.Name
You should wrap your form in form tag. It is a form after all. So when you click submit, you are submitting the form.
<form method="post">
<h2>Mymethod</h2>
<h3>#ViewBag.Message</h3>
#Html.TextBox("Name")
#if (!String.IsNullOrEmpty(ViewBag.Name))
{
<h3>
welcome,ur name is #ViewBag.Name
</h3>
}
<input type="submit" value="Submit" name="btn" />
</form>
On the controller, you need to add HttpPost handler for your Mymethod action. This is where your web server is accepting the form you've submitted.
[HttpPost]
public ActionResult Mymethod(string name)
{
ViewBag.Message = "Hello what is ur name ???";
ViewBag.Name = name;
return View();
}
During a scan of an application at work, it became clear that modifying an input's value, then posting it potentially causes rendering issues if you try to pass that model back to the view.
For example, with the model:
public class Survey
{
public bool LikesCandy { get; set; }
}
The actions:
public ActionResult Survey()
{
return View(new Survey());
}
[HttpPost]
public ActionResult Survey(Survey model)
{
//do something worthwhile with the model, like validation, etc. etc.
//even setting the model's boolean doesn't help the rendering.
model.LikesCandy = true;
//then return to the page
return View(model);
}
And a basic razor view:
#model BoolTest.Models.Survey
#using (Html.BeginForm())
{
#Html.EditorFor(i => i.LikesCandy)
<input type="submit" value="Submit"/>
}
The form gets rendered something like:
<form action="/Home/Survey" method="post">
<input checked="checked" id="LikesCandy" name="LikesCandy" type="checkbox" value="true">
<input name="LikesCandy" type="hidden" value="false">
<input type="submit" value="Submit">
</form>
Posting that works fine.
However, if someone changes the input value like so:
<form action="/Home/Survey" method="post">
<input checked="checked" id="LikesCandy" name="LikesCandy" type="checkbox" value="foobar">
<input name="LikesCandy" type="hidden" value="false">
<input type="submit" value="Submit">
</form>
The model looks reasonable on the server-side (it defaults LikesCandy to false), but the view rendering will always fail with String was not recognized as a valid Boolean..
Can someone explain why this is so? And is there some idiomatic way to fix/handle this? I can do something like use reflection to compare the model's property's types to the request form and give the user some "stop that!" message, or write my own html tags and manually bind the model to those, but neither seem very clean/extensible/correct.
Edit: As stated in the comments, the model binder is expecting a true or a false. If you submit something else for that field then a 500 error is the expected response. Also, if you change the value of the model during the post processing and then redisplay the view then you're not going to see the model change made in the controller reflected in the POST response. See here:
http://patrickdesjardins.com/blog/modelstate-clear-is-required-to-display-back-your-model-object
public ActionResult Survey()
{
return View(new Survey());
}
[HttpPost]
public ActionResult Survey(Survey model)
{
//do something worthwhile with the model, like validation, etc. etc.
//even setting the model's boolean doesn't help the rendering.
model.LikesCandy = true;
//clear model state so that the change on the line above is applied
ModelState.Clear();
//then return to the page
return View(model);
}
This is what I've had in mind but of course it doesn't work.
#{
var textBoxData = form.find('input[name="textboxList"]').val();
}
<input type="button" value="Add" title="Add" onclick="location.href='#Url.Action("Create_Add", "Controller", new { textboxList = textBoxData })'" />
How should I pass this? Controller action name and parameter are correct. Just that I don't know how to get the value entered in textbox...
I have trouble with saving a form within a form, so someone suggested this solution. Proxy code would be:
<firstForm>
textboxfor Name
dropdownfor DType
If DTypeDDL value is "List" then
<secondForm>
textboxfor nameOfItem
submitSecondForm (using that method i mentioned above)
</secondForm>
End If
submitFirstForm
</firstForm>
I've been trying to save 2 forms for quite a while now but no luck. This is basically my last resort.
First of all, you should go with a viewmodel oriented html file since you are using MVC (Model, View, Controller):
Create a viewModel:
public class ExampleViewModel
{
public ExampleViewModel()
{
}
public virtual string TextBoxData { get; set; }
}
After, code your html using the viewmodel as model:
#model Models.Views.ExampleViewModel
#using (Html.BeginForm())
{
<div class="editor-row">
<div class="editor-label">
#Html.LabelFor(model => model.TextBoxData)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TextBoxData)
</div>
</div>
<input type="submit" value="submit" />
}
and your controller:
public ActionResult Example()
{
ExampleViewModel model = new ExampleViewModel();
return This.View(model);
}
[HttpPost]
public ActionResult Example(ExampleViewModel model)
{
string infoEntered = model.TextBoxData;
// Do something with infoEntered
}
Hope this will help you!
If you're using view models, check out this answer: MVC sending data from View to Controller
If you're only interested in sending the data from an input to the action method without view models, you can do that as well:
View:
#using (Html.BeginForm("Edit", "Some", FormMethod.Post))
{
<input type="text" id="myTextBox" name="myTextBox" />
<input type="submit" value="Submit" />
}
Notice the BeginForm line. The first parameter is the Action I want the data to go to, which I named Edit. The next parameter is the Controller I am using, which I named SomeController. You don't add the Controller bit to the name when you're referencing the Controller in BeginForm. The third parameter is telling the form to use the POST method when sending the data to the server.
Controller:
public class SomeController
{
[HttpPost]
public ActionResult Edit(string myTextBox)
{
// Do what you want with your data here.
}
}
If you added more inputs (again, without a view model here), you can add them as parameters to the Edit method. This isn't really the preferred method, though. Look into using a view model. ScottGu has a nice blog post on doing what you need, using view models:
http://weblogs.asp.net/scottgu/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx