Saving data from a html form to List - c#

I have two Create methods one decorated with HttpGet, and the other with HttpPost. I have a create view for the first one looking like this :
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<form action="/" method="post">
<input type="text" name="txt" value="" />
<input type="submit" />
</form>
The methods :
List<string> myList = new List<string> { "element1", "element2", "element3" };
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(string txt)
{
//myList.Add(Request.Form["txt"]);
myList.Add(txt);
return View();
}
I am simly trying to pass the data from my form on button to my second Create() and save it to myList.
I need some advice on how to make this work.

Once you've fixed your form (in that you're posting back to your application's default route (by default HomeController.Index() method) by sending the request to /, instead of your Create method), you are actually correctly adding the value to your list. The problem is, that value only stays for the current request.
To make things persistent, you need to consider a persistence layer in memory, in database, or in session. I've provided a full sample below that uses the session, which will give you a per-user list instance. Without this layer, your Controller is being routinely disposed of once the action has completed processing, and so the amends to your list are not persisted. This is the normal request lifecycle in ASP.NET and makes sense when you consider that your app is basically only ever dealing with 1 request at a time. It's important to note that making something static isn't a form of persistence per-se, in that its lifetime and reliability is indeterminable. It will appear to work, but once your application pool recycles (ie. the app is destroyed and reloaded in memory) you will have again lost all amends to your list.
I would suggest you read up on Session State to understand exactly what is going on below. In a nutshell, each application user / unique visitor to your site will be given a unique 'session ID', you can then use this session ID to store data that you wish to use on the server side. This is why, if you were to visit your Create method from separate browsers (or try Private mode) you will be maintaining two separate lists of data.
View (which also outputs the list to the user):
#model List<string>
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<ul>
#foreach(var str in Model)
{
<li>#str</li>
}
</ul>
#using (Html.BeginForm())
{
<input type="text" name="txt" />
<input type="submit" />
}
Controller contents:
public List<string> MyList
{
get
{
return (List<string>)(
// Return list if it already exists in the session
Session[nameof(MyList)] ??
// Or create it with the default values
(Session[nameof(MyList)] = new List<string> { "element1", "element2", "element3" }));
}
set
{
Session[nameof(MyList)] = value;
}
}
public ActionResult Create()
{
return View(MyList);
}
[HttpPost]
public ActionResult Create(string txt)
{
MyList.Add(txt);
return View(MyList);
}

Please use this:
#using (Html.BeginForm("Create", "Controller", FormMethod.Post)){
<input type="text" name="txt" value="" />
<input type="submit" />
}
Replace Controller with your Controller name.
Or simply use:
#using (Html.BeginForm()){
<input type="text" name="txt" value="" />
<input type="submit" />
}
When you call BeginForm() without any parameters it default to using the same controller/action used to render the current page.

Related

How to pass a model and a variable to a post method with one input

I'm trying to have one post route that takes care of multiple operations.
Here's the Controller:
[HttpPost("dish/{operation}")]
public IActionResult Dish(string operation, Dish dish)
{
if (operation == "RedEdit")
{
return RedirectToAction("EditDish", dish);
}
if (ModelState.IsValid)
{
if (operation == "Add")
{
_context.Add(dish);
_context.SaveChanges();
return RedirectToAction("Index");
}
else //Unused currently
{
Console.WriteLine("Oops");
_context.Add(dish);
_context.SaveChanges();
return RedirectToAction("Index");
}
}
else
{
return View("DishForm");
}
}
The POST route will take a string, which is the operation it'll do, and depending on the operation it'll run something different. Right now I don't have all the operations, and my else within the validation isn't what it's going to be. The problem I'm having currently is with the "RedEdit," which is just a method to redirect to the edit page. Here's my view and what I'd like to do:
#{
ViewData["Title"] = "Add a dish!";
ViewData["Header"] = "Add a new Dish!";
ViewData["Home"] = true;
ViewData["Add"] = false;
var parms = new Dictionary<string, string>
{
{"operation", ""}
};
}
#model RichCRUDelicious.Models.Dish
<div class="container d-flex flex-column text-center">
<h3><u>#Model.Name by #Model.Chef</u></h3>
<p>#Model.Description</p>
<p>Calories: #Model.Calories</p>
<p>Tastiness: #Model.Tastiness</p>
<footer>
#using (Html.BeginForm("Dish", "Home", "operation", FormMethod.Post)){
//Two Buttons with Edit and Delete
}
</footer>
</div>
I'd essentially like to have one form, which has two buttons, one for edit and delete. The button for edit will change my operation value in parms to "RedEdit," while delete will change it to "Delete" (which I don't have a route set up for currently but that's not the issue.) I've tried a couple different methods, and mostly the issue comes down to the parameters within the post method, I'm not sure how I can pass the model in AND the operation value. I don't mind if they're split up into two different forms, but I'd really like just one post method for this controller.
I've tried using a generic HTML Form with:
<form asp-action="Dish" asp-controller="Home" asp-all-route-data="parms" method="post">
But my issue wasn't resolved using this method either, I'm thinking a hidden input with two different forms will work, but if there's a better way I'd like to hear.
If you want to use a form with two buttons which go to the same action,you can try to add asp-route-operation to your buttons,here is a simple demo:
Dish:
public class Dish {
public int Id { get; set; }
public string Name { get; set; }
}
view:
<form method="post">
<input hidden name="Id" value="1" />
<input hidden name="Name" value="test" />
<button asp-controller="Home" asp-action="Dish" asp-route-operation="RedEdit">RedEdit</button>
<button asp-controller="Home" asp-action="Dish" asp-route-operation="Delete">Delete</button>
</form>
action:
[HttpPost("dish/{operation}")]
public IActionResult Dish(string operation, Dish dish)
{
...
}
}
Hidden inputs will help you pass the value of Dish to the action,asp-route-operation will help pass different operation values to the action.When clicking RedEdit button,the value of operation will be RedEdit.With Delete button,it will be Delete.

Call ActionResult method from button press

I'm trying to call an ActionResult method from a web page form but I can't seem get the two items to connect.
The desired result is for the page to refresh and filter the model to display the required results.
Method in serversController.cs
The internal code works as intended when placed in ActionResult Index
[HttpPost]
public ActionResult activeServers()
{
// load the servers into local variable
var servers = from s in db.Servers
select s;
// filter out the archived servers
servers = servers.Where(s => s.archive.Equals(0));
return View(servers.ToList());
}
Button making the call
#using (Html.BeginForm())
{
<button name="activeServers" type="submit" value="activeServers" class="btn btn-default">Active</button>
}
Thanks is advance
Try to specify the action method, controller name (without the controller suffix) and the http method (it defaults to GET) in the BeginForm:
#using (Html.BeginForm("activeServers", "Servers", FormMethod.POST))
{
<button name="activeServers" type="submit" value="activeServers" class="btn btn-default">Active</button>
}

How do I save my MVC4 model if I need 2 submit buttons?

I have to allow the user to move to the next or previous form, I just need to save the model on navigation. Is there another way to pass back the model to the controller besides using submit? Since I need to redirect to other possible pages.
You could put your model object in the TempData collection on submit, redirect, then read it back out again. For example:
[HttpPost]
public ActionResult FirstForm(FirstFormModel model) {
TempData["TempModelStorage"] = model;
return RedirectToAction("SecondForm");
}
public ActionResult SecondForm() {
var firstModel = TempData["TempModelStorage"] as FirstFormModel;
// check for null, use as appropriate, etc.
return View(...);
}
More details here: http://msdn.microsoft.com/en-us/library/dd394711(v=vs.100).aspx
You may save the data asynchronously using jQuery ajax on those button click events.
Assuming your View is something like this
#using(Html.BeginForm("Save","Items"))
{
<div>
Name : #Html.TextBoxFor(s=>s.Name)
<input type="button" class="navigBtns" value="Prev" />
<input type="button" class="navigBtns" value="Next" />
</div>
}
And your script is
$(function(){
$(document).on("click",".navigBtns",function() {
e.preventDefault();
var _this=$(this);
$.post(_this.closest("form").attr("action"), _this.closest("form").serialize(),
function(res){
//check res variable value and do something as needed
// (may be redirect to another page /show/hide some widgets)
});
});
});
Assuming you have an action method called Save in your controller to handle the saving part.
Was given a neat article about this.
MVC Wizard Example
Basically this, you literally pass the name of the html button.
In the view form
<input type="submit" name="btnPrev" />
<input type="submit" name="btnNext" />
In the Controller
Controller
public ActionResult DoStuff(ModelClass mc,string btnPrev,string btnNext)
{
string actionString = "previousPage";
if(btnNext != null)
actionString = "nextPage";
return RedirectToAction(actionString,"Controller")
}

accessing controller method on button click

I am new to C# and MVC, while I understand the Controller and the Model side. I have encountered a problem when accessing methods within a controller in order to do a simple conversion that I can then return to my View.
My Controller:
public class Exercise05Controller : Controller
{
//
// GET: /Exercise05/
public ViewResult Index()
{
return View();
}
public ActionResult GramsToOunces(double? grams)
{
ViewData["grams"] = grams;
ViewData["ounces"] = (grams * 0.035d);
if (grams < 5)
{
return RedirectToAction("Index", "Home");
}
else if (grams > 5)
{
return View("GramsToOunces");
}
return RedirectToRoute(new
{
controller = "Exercise05",
action = "Index"
});
}
}
My Index View:
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<form action="/Exercise05/GramsToOunces" method="post">
<input name="grams" type="text" placeholder="Insert grams to convert to ounces" />
<input type="submit" value="Convert Grams to Ounces" />
</form>
My GramsToOunces View:
#{
ViewBag.Title = "Index";
}
<h2>GramsToOunces</h2>
<!-- Currently nothing else here -->
I believe my issue is arising somewhere on this line; action="/Exercise05/GramsToOunces". Using debugging has shown me that the the controller processes all the information and gets ready to return the view to suddenly just not return anything. I wish to do a simple conversion and then return this as a view. Would someone be able to point me as to where I am going wrong?
As long as your view is named the same as the controller action, try:
#using (Html.BeginForm())
{
<input name="grams" type="text" placeholder="Insert grams to convert to ounces" />
<input type="submit" value="Convert Grams to Ounces" />
}
This is just a sanity check, but you are using the line return View("GramsToOunces", "ounces");. According to the docs http://msdn.microsoft.com/en-us/library/dd470743(v=vs.118).aspx, first string is the view name and second string is the master page. Do you have a master page called "ounces"? If not that could explain why no result is returning. Perhaps you want to use return View("GramsToOunces");
If you simply want to do the conversion and show the result to user. Just make it Ajaxified. Do not post the entire form.Make an ajax call and get the result and show it to user.
Assuming you have jQuery loaded to your form.
#using(Html.BeginForm("GramsToOunce","Exercise5"))
{
<input name="grams" id="gram" type="text" placeholder="Insert grams" />
<input type="submit" id="btnSubmit" value="Convert Grams to Ounces" />
<div id="result"></div>
}
<script type="text/javascript">
$(function(){
$("#btnSubmit").click(function(e){
e.preventDefault();
var url=$(this).closest("form").attr("action");
$.post(url,{ grams : $("#gram").val()} ,function(res){
$("#result").html(res);
});
});
});
</script>
Let's make sure that our action method returns the value.
[HttpPost]
public string GramsToOunces(double? grams)
{
var result=grams * 0.035d;
return result.ToString();
}
Also if you simply want to do the multiplication, just do it in the client side(javascript). No need of a server call.
According to the documentation this line:
return View("GramsToOunces", "ounces");
Tries to return the view with the specified master page. However it seems there is no master page "ounces" in your project. So most likely what you need here is simply:
return View("GramsToOunces");
Note that you do not need to pass any models whatsoever because you are already using the ViewData.

How to change the way the Url is formatted on a submit

I have a search box in a Razor template:
#{
using (Html.BeginForm("Detail", "Book", FormMethod.Get))
{
#Html.TextBox("Id")
<input type="submit" value="Search" />
}
}
When I submit a search it goes to a url like:
~/Book/Detail?Id=1234
However I want it to format the url like so, just because I think it looks cleaner:
~/Book/Detail/1234
Which works perfectly fine because the controller method signature looks like this:
// GET: /Book/Detail/id
public ActionResult Detail(string id)
Model with TextBoxFor
I've tried a Html.TextBoxFor:
#model WebApplication.Models.SearchModel
#{
using (Html.BeginForm("Detail", "Book", FormMethod.Get))
{
#Html.TextBoxFor(m => m.Id)
<input type="submit" value="Search" />
}
}
Same result.
I think you want to take a look at the #Html.BeginRouteForm method, like in this question.
You use a GET request. This means that all parameters will appear in the url box.
I can't check now, but I suppose you could use these options:
The IIS url rewrite - http://www.iis.net/downloads/microsoft/url-rewrite
Url rewrite through a web.config - http://www.hanselman.com/blog/RedirectingASPNETLegacyURLsToExtensionlessWithTheIISRewriteModule.aspx
And a batch of stupid methods:
You can change your request to POST and then modificate the Url by the JS - Modify the URL without reloading the page
You can redirect the request
Also, did you try to add a personal routing for the search url?
Try using a model for the form submit and use #Html.TextBoxFor.
The answer was to add a new search action then redirect to the detail. This is nice because I can choose to do more when searching, such as returning a different view if the query has multiple matches.
//
// GET: /Book/Search?query=
public ActionResult Search(string query)
{
return RedirectToAction("Detail", new { id = query });
}
//
// GET: /Book/Detail/id
public ActionResult Detail(string id)
Razor:
#{
using (Html.BeginForm("Search", "Book", FormMethod.Get))
{
#Html.TextBox("query")
<input type="submit" value="Search" />
}
}

Categories

Resources