I want to retrieve data from a view, it should work like this:
User fill a form available on the webpage
User clicks SEARCH button
Some function(s) collect the data and display them in another view
I tried all the basic tutorials and tips on others stackoverflow question but it still doesn't work. I don't know what I'm doing wrong...
Here's my code from the view:
section id="roomSearch">
<div class="banner">
<div class="banner-info">
<div class="container">
<div class="details-1">
#using (Html.BeginForm("UploadRoomSearchData", "HomeController", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="col-md-10 dropdown-buttons">
<div class="col-md-3 dropdown-button">
#Html.AntiForgeryToken()
<div class="input-group">
#Html.TextBoxFor(m => m.YourName, new { #class = "form-control has-dark-background", #placeholder = "Imię" })
#Html.ValidationMessageFor(m => m.YourName, "", new { #class = "text-danger" })
<!--<input class="form-control has-dark-background"
name="slider-name" id="slider-name" placeholder="Imię" type="text" required="">-->
</div>
</div>
<!---strat-date-piker---->
<link rel="stylesheet" href="~/Content/jquery-ui.css" />
<script src="~/Scripts/jquery-ui.js"></script>
<script>
$(function () {
$("#datepicker,#datepicker1").datepicker();
});
</script>
<!---/End-date-piker---->
<div class="col-md-3 dropdown-button">
<div class="book_date">
<form>
<input class="date" id="datepicker" type="text" value="Przyjazd" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Przyjazd';}">
<!-- #Html.TextBoxFor(m => m.CheckIn, new { #class = "date" })
#Html.ValidationMessageFor(m => m.CheckIn, "", new { #class = "datefield" })-->
</form>
</div>
</div>
<div class="col-md-3 dropdown-button">
<div class="book_date">
<form>
<input class="date1" id="datepicker1" type="text" value="Wyjazd" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Wyjazd';}">
<!--#Html.TextBoxFor(m => m.CheckOut, new { #class = "date1" })
#Html.ValidationMessageFor(m => m.CheckOut, "", new { #class = "datefield" })-->
</form>
</div>
</div>
<div class="col-md-3 dropdown-button">
<div class="section_1">
<select id="country" onchange="change_country(this.value)" class="frm-field required">
<option value="null">Dwuosobowy</option>
<option value="null">Jednoosobowy</option>
<option value="AX">Apartament</option>
<option value="AX">Gościnny</option>
</select>
</div>
</div>
<div class="clearfix"> </div>
</div>
<div class="col-md-2 submit_button">
<form >
<input type="submit" value="SZUKAJ">
<!-- <p> #Html.ActionLink("SZUKAJ", "Book1", "Home")</p>-->
</form>
</div>}
And here's my code in the controller. For now I try to retrieve only a name, to see if it's working.
[HttpPost]
public ActionResult UploadRoomSearchData(FormCollection form)
{
string name = Request["YourName"].ToString();
StringBuilder sbRoom = new StringBuilder();
sbRoom.Append("<b>Amount :</b> " + name + "<br/>");
//return RedirectToAction("Book1");
return Content(sbRoom.ToString());
}
I also tried something like this:
foreach(var v in form)
{
Write.Response("name:" + v);
}
I tried your code and it seems to work.
First I have the controller method to display the form
public ActionResult CreatePerson()
{
Person model = new Person();
return View(model);
}
Then the form:
#model RetrieveDataFromaView.Models.Person
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Person</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.YourName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.YourName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.YourName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="submit" class="btn btn-default" />
</div>
</div>
</div>
}
Which does a post to the controller method
[HttpPost]
public ActionResult CreatePerson(FormCollection formCollection)
{
string name = Request["YourName"].ToString();
StringBuilder sbRoom = new StringBuilder();
sbRoom.Append("<b>Amount :</b> " + name + "<br/>");
return Content(sbRoom.ToString());
}
This returns a view with only the content of the StringBuilder.
Maybe you are looking for RedirectToAction?
Hello you have this line inside the form:
#Html.AntiForgeryToken()
You can remove it or add the corresponding attribute to use it:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreatePerson(FormCollection formCollection)
{
///Your code here
}
Basically this is a token generated for the server to avoid requests from forms not generated by the server.
You have many ways of retrieving data from a form Post in ASP.NET MVC.
Using a Model
Usually, forms are created by specifying a Model type in the Razor view. You can use that type to retrieve the data. ASP.NET MVC will parse the body and populate the object in parameter for you.
Ex:
Controller:
public class HomeController: Controller
{
[HttpGet]
public ActionResult Index()
{
return View(new Person());
}
[HttpPost]
public ActionResult Index(Person p)
{
//Just for the sake of this example.
return Json(p);
}
}
Razor view
#model WebApplication2.Models.Person
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>title</title>
</head>
<body>
<div>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
#Html.LabelFor(m => m.FirstName): <br/>
#Html.TextBoxFor(m => m.FirstName)
</div>
<div>
#Html.LabelFor(m => m.LastName): <br/>
#Html.TextBoxFor(m => m.LastName)
</div>
<input type="submit" value="Submit" />
}
</div>
</body>
</html>
Using a FormsCollection
The FormsCollection object allows you to access the raw values of a form. It acts as a Dictionary for the Forms value. This is useful, especially when you have a dynamic model to parse, or if you just plain don't know about the Model type.
It's also pretty straightforward to use.
[HttpPost]
public ActionResult Index(FormCollection form)
{
var dict = form.AllKeys.ToDictionary(key => key, key => form[key]);
return Json(dict);
}
PS: I saw you are using Request[key]. It may just be me, but this call just looks like Dark magic, where you get data from who knows where (it uses the Query String, the cookies, the Request body, etc. It seems like it could be really problematic in some cases in the future. I much prefer knowing exactly where the data comes from. But that may just be me.
Conclusion
In conclusion, use the Model approach if you know exactly what should be in the Form. Use the FormCollection approach if you really need to. That's pretty much it.
Good luck.
Related
I am using two viewbags to get the same list(List of tags) on get request these viewbags are showing list as a dropdown but when I submit the page (post request) they are binding the 0 values(no matter what I select from the dropdown list) with the object in the controller but when I used only the single dropdown list it binding its value with an object in the controller?
[HttpGet]
public ActionResult CreateNewTotalizerTag()
{
//This is RawTag List
var RawTaglist1 = cRTu.RawTagsList();
ViewBag.RawTaglist1 = new SelectList(RawTaglist1, "Real_Tag_Id", "R_Tag_Name");
//This is RawTag List
var RawTaglist2 = cRTu.RawTagsList();
ViewBag.RawTaglist2 = new SelectList(RawTaglist2, "Real_Tag_Id", "R_Tag_Name");
return View();
}
//Controller
[HttpPost]
public ActionResult CreateNewTotalizerTag(RawTagVM rawTagVM)
{
return View(rawTagVM);
}
#using (Html.BeginForm("CreateNewTotalizerTag", "TotalizerTags", FormMethod.Post))
{
#Html.HiddenFor(x=>x.Real_Tag_Id)
<div class="container-fluid">
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-6">
<!-- general form elements disabled -->
<div class="card card-warning">
<div class="card-header" style="background-color:#343a40">
<h3 class="card-title" style="color:white">Create Totalizer Tag</h3>
</div>
<!-- This form is to create Raw tag totalizer onPrem or onCloud -->
<div class="card-body">
<form role="form">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<div class="custom-control custom-switch">
#Html.CheckBoxFor(m => m.Is_Cloud_Totalizer, new { #class = "custom-control-input", id = "Is_Cloud_Totalizer" })
<label class="custom-control-label" for="Is_Cloud_Totalizer">Is Cloud Totalizer?</label>
</div>
</div>
</div>
</div>
<!-- On Cloud Inputs starts here -->
<div id="oncloud_totalizer" style="display:none">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label>Enter Tag Name</label>
#Html.EditorFor(m => m.R_Tag_Name, new { htmlAttributes = new { #class = "form-control" } })
#*#Html.ValidationMessageFor(model => model.R_Tag_Name, "", new { #class = "text-danger" })*#
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label>Select Raw Tag</label>
#Html.DropDownListFor(m => m.Real_Tag_Id_Cloud, (IEnumerable<SelectListItem>)ViewBag.RawTaglist1, "Select Raw Tag", new { #class = "form-control", id = "Raw_Tag_List1" })
</div>
</div>
</div>
</div>
<!-- On Prem Inputs starts here -->
<div class="row" id="onPrem_totalizer">
<div class="col-sm-6">
<div class="form-group">
<label>Select Raw Tag</label>
#Html.DropDownListFor(m => m.Real_Tag_Id, (IEnumerable<SelectListItem>)ViewBag.RawTaglist2, "Select Raw Tag", new { #class = "form-control", id = "Raw_Tag_List2" })
</div>
</div>
</div>
<div class="form-group">
<center><button type="submit" class="btn btn-primary">Create Totalizer</button></center>
</div>
</form>
</div>
<!-- /.card-body -->
</div>
<!-- /.card -->
<!-- general form elements disabled -->
<!-- /.card -->
</div>
</div>
</div>
}
<script>
$(document).ready(function () {
// Initialize select2
//$("#Raw_Tag_List1").select2();
//$("#Raw_Tag_List2").select2();
//$("#Source_Tag_List").select2();
$("#Is_Cloud_Totalizer").change(function () {
if (this.checked) {
$("#oncloud_totalizer").show();
$("#onPrem_totalizer").hide();
}
else {
$("#onPrem_totalizer").show();
$("#oncloud_totalizer").hide();
}
});
});
</script>
You could assign the viewbag properties on postback aswell. Viewbag properies are used in the view (cshtml) for rendering the page, the resulting rendered HTML page that is sent to the client does not know them, and also they are not sent back to the server together with form data on post back.
//Controller
[HttpPost]
public ActionResult CreateNewTotalizerTag(RawTagVM rawTagVM)
{
var RawTaglist1 = cRTu.RawTagsList();
ViewBag.RawTaglist1 = new SelectList(RawTaglist1, "Real_Tag_Id", "R_Tag_Name");
//This is RawTag List
var RawTaglist2 = cRTu.RawTagsList();
ViewBag.RawTaglist2 = new SelectList(RawTaglist2, "Real_Tag_Id", "R_Tag_Name");
return View(rawTagVM);
}
You might try to assign the drop down a list of SelectListItem
ViewBag.RawTaglist1 = RawTaglist1.Select(x => new SelectListItem()
{
Value = x.Real_Tag_Id.ToString(),
Text = x.R_Tag_Name
}).ToList();
Validate Input is not working.The form gets submitted and the success view is displayed even when the form is posted with html tags
<b> hello </b>
Why is the cross site scripting prevention not working? It should be enabled by default right?
Razor View
<h4 style="color:purple">
<b>ID:</b> #ViewBag.ID <br />
<b>Name:</b> #ViewBag.Name <br />
</h4>
<hr />
#using (Html.BeginForm("register", "Adder", FormMethod.Post))
{
<div class="form-group">
#Html.TextArea("comments");
<input type="submit" />
</div>
}
Controller Method
[HttpPost]
public string register(string val)
{
// quickdbEntities1 ent = new quickdbEntities1();
// Player p1 = ent.Players.FirstOrDefault(p => p.Name == "name");
//// ent.Players.Add(player);
//// int res = ent.SaveChanges();
// ViewBag.id = player.PlayerId;
// ViewBag.Name = p1.Name;
return ("success");
}
Update:
I have added DataAnnotation [Required] and now uses a form like this.Still the form submits
#model Vidly.Domain.Player
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section scripts
{
#Scripts.Render("~/bundles/jqueryval" )
}
#using (Html.BeginForm("register", "Adder", FormMethod.Post))
{
<div class="form-group">
#Html.TextBoxFor(m => m.Name,new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Name)
<input type="submit" name="submit" />
</div>
}
It is because you are accepting the parameter as string and no validation script in view page (as of we can't see if the layout page has the scripts).
The resource cannot be found.
Requested URL: /Home/Home/Signup_User
However it should be /Home/Signup_User
where Home is the controller and Signup_User is the function in Home Controller.I have checked the spelling its correct.
My Sign Up Form as follows.
<form action="~/Home/Signup_User" method="post" enctype="multipart/form-data">
#Html.AntiForgeryToken()
<div class="row">
<div class="large-6 columns">
<label>
Enter Name
#Html.EditorFor(model => model.username, new { htmlAttributes = new { #class = "form-control" } })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Age
#Html.EditorFor(model => model.age, new { htmlAttributes = new { #class = "form-control" } })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Email Address
#Html.TextBoxFor(model => model.email, new { #class = "large-12", placeholder = "xyz#gmail.com", type = "email" })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Password
#Html.PasswordFor(model => model.password, new { })
</label>
</div>
</div>
<br />
<hr />
<button type="submit" class="button tiny right" style="margin-left:5px;color:white;">Submit</button>
Cancel }
<a class="close-reveal-modal" aria-label="Close">×</a>
</form>
FormExtensions (with Controller and ActionName)
#using (Html.BeginForm("Signup_User", "Home", FormMethod.Post))
{
}
FormExtensions (with Controller , ActionName and Area )
#using (Html.BeginForm("Signup_User", "Home", FormMethod.Post, new { area = "AreaName" }))
{
}
Try replacing
action="~/Home/Signup_User"
with
action="#Url.Action("Signup_User", "Home")"
You just need to add Controller name slash action name, no need to add ~
Refer following code for Solution 1:
<form action="/Home/Signup_User" method="post" enctype="multipart/form-data">
//Add rest of your code
</form>
Else, use MVC's built in HTML helper to render the form and put your rest of the code into same.
#using (Html.BeginForm("Signup_User", "Home", FormMethod.Post))
{
// Add your rest of code
}
Above code will generate empty tag.
It seems you are using relative path in action URL . that's why Home Added twice like this.
/Home/Home/Signup_User
Asp.net MVC come up with beautiful Form Extensions.Just you need to specify Controller Name, Action Method Name and Area name if any.
for e.g.
#using (Html.BeginForm("actionName", "controllerName", new {area = "AreaName"}))
In your case
ActionName :"Signup_User"
ControllerName:"Home"
Assuming, you don't have no area defined. replace your piece code with below snippet. it will resolve your issue.
CODE:
#using (Html.BeginForm("Signup_User", "Home"))
#Html.AntiForgeryToken()
<div class="row">
<div class="large-6 columns">
<label>
Enter Name
#Html.EditorFor(model => model.username, new { htmlAttributes = new { #class = "form-control" } })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Age
#Html.EditorFor(model => model.age, new { htmlAttributes = new { #class = "form-control" } })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Email Address
#Html.TextBoxFor(model => model.email, new { #class = "large-12", placeholder = "xyz#gmail.com", type = "email" })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Password
#Html.PasswordFor(model => model.password, new { })
</label>
</div>
</div>
<br />
<hr />
<button type="submit" class="button tiny right" style="margin-left:5px;color:white;">Submit</button>
Cancel }
<a class="close-reveal-modal" aria-label="Close">×</a>
</form>
One reason this could occur is if you don't have a start page set under your web project's properties. So do this:
Right click on your mvc project
Choose "Properties"
Select the "Web" tab
Select "Specific Page"
Assuming you have a controller called HomeController and an action method called Index, enter "home/index" in to the text box corresponding to the "Specific Page" radio button.
Now, if you launch your web application, it will take you to the view rendered by the HomeController's Index action method.
I've built a page, where master and details(pictures, aso) are shown on one page. However, if the submitt button for the second form is clicked, the form is not submitted, if validations in the first form fail. If I correct the values, the HttpPostedFileBase uploadFile is null.
The page looks like this:
#model app1.Models.MasterModel
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm(new { #class = "form-inline col-lg-12" }))
{
#Html.AntiForgeryToken()
<div>
<h4>MasterModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="row">
#*Master properties*#
<div class="col-md-4 col-lg-4">
<div class="form-horizontal">
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-8">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
#* aso... *#
</div>
</div>
}
#* Master Details *#
<div class="col-md-4 col-lg-4">
#using (Html.BeginForm("NewPic", "Master", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input name="uploadFile" type="file" />
<input type="submit" value="Upload File" /> <!-- First Button, does not work -->
<div class="container-fluid">
#foreach (app1.Models.PicModel b in Model.Pics)
{
var base64 = Convert.ToBase64String(b.DbPic);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
<img src="#imgSrc" width="200" height="200" />
}
</div>
#Html.ActionLink("Upload", "NewPic", new { id = Model.Id }) <!-- Second Button, does not work either -->
<label class="control-label col-md-4 col-lg-4" for="Title">Picer</label>
}
</div>
</div>
<div>
<div class="form-group">
<div class="col-md-offset-2 col-md-12 col-lg-12">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The controller looks like this:
public ActionResult NewPic(int id, HttpPostedFileBase uploadFile)
{
// uploadFile is null
}
You forgotten to put [HttpPost] before NewPic method. So NewPic method will be considered as [HttpGet] so it will not work.
[HttpPost]
public ActionResult NewPic(int id, HttpPostedFileBase uploadFile)
{
// uploadFile is null
}
And also give proper Id to both form as follow so it would be easy to work with this both while client side validation.
Form 1
#using (Html.BeginForm(new {id = "Form1", #class = "form-inline col-lg-12" }))
Form 2
#using (Html.BeginForm("NewPic", "Master", FormMethod.Post, new { id = "Form2", enctype = "multipart/form-data" }))
For more information visit here
this is my controller:
public ActionResult Create() {
Number newNumber = new Number();
return View(newNumber);
}
and View :
#model PhoneBook.Models.Number
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="../../Scripts/jQuery.AddNewNumber.js" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Contact.Id)
<fieldset>
<legend>Number</legend>
<div class="TargetElements">
<div class="editor-label">
#Html.LabelFor(model => model.PhoneNumber)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumber)
#Html.ValidationMessageFor(model => model.PhoneNumber)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.NumberKind)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.NumberKind.Title, NumberKinds)
</div>
</div>
<p>
<input class="AddNew" value="Add New" type="button" /></p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
By press AddNew button (use jQuery AddNewNumber.js) new input+DropDown Added to form in client side. But there is a problem in retrieve values, When I have one entry element(include input+DropDown) I can retrieve values like the following in post of my controller:
[HttpPost]
public ActionResult Create(Number NewNumber, FormCollection collection) {
db.Numbers.Add(NewNumber);
db.SaveChanges();
return RedirectToAction("Index")
}
But when there is multi-entry how can I retrieve values and add them to DataBase?
Use by the name of element like this:
string[] PhoneNumbers = collection.GetValues("PhoneNumber");
You want all of your input elements to have the same name. Then in your POST action method, the parameter would be List. Here is an example:
Model Binding to a List of objects