I'm studying ASP.NET MVC 5. I created a View "Create". But I'm not using Razor to generate the input fields, I'm using inputs with pure html.
Create.cshtml
#model MyProject.Product
<h2>Create Product</h2>
<form method="post">
Description: <br />
<input type="text" name="Description" id="Description"/> <br />
ValueType: <br />
<input type="text" name="ValueType" id="ValueType"/>
<br />
<input type="submit" name="btSend"/>
</form>
My Controller:
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Product product)
{
if (ModelState.IsValid)
{
db.Product.Add(product);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
return View(product);
}
It works fine. I can create new products.
But I need to use some server-side validations with Annotations in the Model.
So, I would like to send the data and, if the model is not valid, go back to the Create with the values. I know how to put the validation messages. So, I tried this:
#model MyProject.Product
<h2>Create Product</h2>
<form method="post">
Description: <br />
<input type="text" name="Description" id="Description" value="#Model.Description"/> <br />
ValueType: <br />
<input type="text" name="ValueType" id="ValueType" value="#Model.ValueType"/>
<br />
<input type="submit" name="btSend"/>
</form>
How to bind pure input with html to model?
Why null value?
Thanks a lot.
I think you may misunderstand the razor view engine. Pages 2.0 and 3.0 (razor) does not have databinding in any way. It emulates it with the html helpers, but this is not native razor databinding. Take a look at the code behind s could of the helpers (https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Html/DefaultEditorTemplates.cs) and you will see they are just performing the work that you are hoping for.
If you don't want to use razor based form approach, you can use display validation message with Viewbag/ViewData.
[HttpPost]
public ActionResult Create(Product product)
{
if (!ModelState.IsValid)
{
//if you want to get validation message from ModelState itself, you can query from Modelstate :
string message = string.Join(" , ", ModelState.Values
.SelectMany(v => v.Errors)
.Select(e => e.ErrorMessage));
ViewData["ValidationMessage"] = "Validation Message";// you can use above variable message here
return View(product);
}
// your other implementation
}
Your view should be like this :
#model MyProject.Product
<h2>Create Product</h2>
<form method="post">
<div class="error-message">#ViewData["ValidationMessage"]</div>
Description: <br />
<input type="text" name="Description" id="Description" value="#Model.Description"/> <br />
ValueType: <br />
<input type="text" name="ValueType" id="ValueType" value="#Model.ValueType"/>
<br />
<input type="submit" name="btSend"/>
</form>
But, I would recommend to use razor based form approach if you are allowed to do so.
Related
I am currently creating a web application that takes in a new user, adds their information to a list, and then displays the users. When I follow the link to my form with validation (a form I have used many times before in other projects) I am getting an unhandled exception.
Here is the specific error code
AspNetCore.Views_Home_RegisterNewUser.<ExecuteAsync>b__12_0() in RegisterNewUser.cshtml, line 15
To this point, I have double checked that the model is correct and has the correct validation. I have made sure the controller and action are correct.
Here is the page for the form
#{
ViewData["Title"] = "RegisterNewUser";
}
<h1>RegisterNewUser</h1>
#model Lab20.Models.RegisterUser
#Html.ValidationSummary()
<form asp-controller="Home" asp-action="ListAllUser" method="post" class="bg-dark">
<div class="col-12">
First Name:
<input type="text" name="FirstName" value="#Model.FirstName" placeholder="#Model.FirstName" class="col-5" />
#Html.ValidationMessageFor(m => m.FirstName)
</div>
<div class="col-12">
Last Name: <input type="text" name="Last Name" value="#Model.LastName" placeholder="#Model.LastName" class="col-5" />
#Html.ValidationMessageFor(m => m.LastName)
</div>
<div class="col-12">
Birthday: <input type="datetime" name="Birthday" value="#Model.Birthday" placeholder="#Model.Birthday" class="col-5" />
#Html.ValidationMessageFor(m => m.Birthday)
</div>
<div class="col-12">
Email: <input type="text" name="Email" value="#Model.Email" placeholder="#Model.Email" class="col-5" />
#Html.ValidationMessageFor(m => m.Email)
</div>
<div class="col-12">
Password: <input type="text" name="Password" value="#Model.Password" placeholder="#Model.Password" class="col-5" />
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="col-12">
Favorite Color: <input type="text" name="FavoriteColor" value="#Model.FavoriteColor" placeholder="#Model.FavoriteColor" class="col-5" />
#Html.ValidationMessageFor(m => m.FavoriteColor)
</div>
<input type="submit" value="Add User" />
</form>
Here is the HomeController
public class HomeController : Controller
{
List<RegisterUser> listOfUsers = new List<RegisterUser>() { };
public IActionResult Index()
{
return View();
}
[HttpGet]
public IActionResult RegisterNewUser()
{
return View();
}
[HttpPost]
public IActionResult RegisterNewUser(RegisterUser newUser)
{
if (!ModelState.IsValid)
{
return View(newUser);
}
else
{
return View("AddNewUser", newUser);
}
}
public IActionResult AddNewUser(RegisterUser user)
{
listOfUsers.Add(user);
return View("Index");
}
public IActionResult ListAllUsers()
{
return View();
}
}
I would like my page to firstly, display, secondly, catch the validation I have added, and thirdly take the new user's information and display it in the ListAllUsers View.
<form asp-controller="Home" asp-action="RegisterNewUser" method="post" class="bg-dark">
</form>
your form post action will be in RegisterNewUser method, you're pointing it wrong in ListAllUsers.
hope, you get it
You form is posing to the action ListAlluser in the controller Home. Now according to your code, you don't have an action method by that name.
The correct asp-action parameter should be RegisterNewUser. So the code becomes
<form asp-controller="Home" asp-action="RegisterNewUser" method="post" class="bg-dark">
</form>
I have list of html checboxes in form and I need get checked checboxes values to C# array after form sent, it is possible?
<form id="form1" action="" method="post">
#foreach (var category in ViewBag.Categories)
{
<ul>
<li>
<input type="checkbox" name="Category" value=#category["UUID"] />#category["CategoryName"]<br /> //Generate >20 checkboxes
</li>
</ul>
}
<button type="submit" formmethod="post">Search</button>
</form>
First of all change following line:
<input type="checkbox" name="Category" value=#category["UUID"] />#category["CategoryName"]<br />
to:
<input type="checkbox" name="Category" value="#category["UUID"]"/>#category["CategoryName"]<br />
and now in your action you can get it from Request object or by adding a parameter of name Category to get in the action:
[HttpPost]
public ActionResult SomeAction()
{
var checkedCategories = Request.Form["Category"];
}
or:
[HttpPost]
public ActionResult SomeAction(int[] Category)
{
}
<input type="checkbox" name="Category" value=#category["UUID"] runat="server" />#category["CategoryName"]<br />
include runat="server" in the input type. you can acess in the code behind.
I have a question about MVC4 (Razor). I have page where I want to filter data. There is a textbox (input) and a submit button. I want to move the text in the textbox to the actionresult. How can I resolve this?
On my page I've the following row:
#{ using (Html.BeginForm("Experiences"))
{
<span class="label">Filter on:</span><input id="FilterText" type="text" size="50"/>
<input type="submit" value="Submit" name="knowledge" /><br />
}
}
<br />
And I want to call the ActionResult Experiences
public ActionResult Experiences(string knowledge = "")
{
ReadExperienceData(knowledge);
return View(ListOfExperiences);
}
Specify the name property value of the input element same as the action method parameter name.
<input id="FilterText" name="knowledge " type="text" size="50"/>
<input type="submit" value="Submit" name="submitKnowledge" />
Also it looks like you are not using the Beginform method properly. You may try any of the below overloads, as needed
#using(Html.Beginform("Knowledge","YourControllerName"))
{
//form elements
}
or
#using(Html.Beginform())
{
//form elements
}
I am having an issue getting data in my model on my MakePayment.cshmtl view.
The AccountScreen.cshtml is calling the MakePayment.cshtml view:
#model SuburbanCustPortal.SuburbanService.CustomerData
#{
ViewBag.Title = "Account Screen";
}
<h2>AccountScreen</h2>
<div class="leftdiv">
<fieldset>
<legend>customer info</legend>
#Html.Partial("CustomerInfoPartialView", Model)
</fieldset>
<fieldset>
<legend>delivery address</legend>
#Html.Partial("DeliveryAddressPartialView", Model)
</fieldset>
<fieldset>
<legend>delivery info</legend>
#Html.Partial("DeliveryInfoPartialView", Model)
</fieldset>
</div>
<div class="rightdiv">
<fieldset>
<legend>balance</legend>
<div>
#Html.Partial("BalancePartialView", Model)
</div>
</fieldset>
<fieldset>
<legend>payment</legend>
<div>
#Html.Partial("MakePayment", Model)
</div>
</fieldset>
<fieldset>
<legend>billing info</legend>
<div>
#Html.Partial("BillingInfoPartialView", Model)
</div>
</fieldset>
</div>
My MakePayment.cshtml view:
#model SuburbanCustPortal.SuburbanService.CustomerData
#using (Html.BeginForm("MakePayment2", "Customer", FormMethod.Post))
{
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
}
My CustomerController:
public ActionResult AccountScreen(LogOnModel model)
{
return ShowCustomer(model.AccountNumber);
}
public ActionResult MakePayment(CustomerData model)
{
return View("MakePayment", model);
}
[HttpPost]
public ActionResult MakePayment2(CustomerData model)
{
//CustomerData model = new CustomerData();
var newmodel = new PaymentModel.SendToGateway();
newmodel.AccountBalance = model.TotalBalance;
newmodel.Amount = model.TotalBalance;
return RedirectToAction("PrePayment", "Payment", newmodel);
}
The public ActionResult MakePayment(CustomerData model) is never being reached.
My problem: The [HttpPost] public ActionResult MakePayment2(CustomerData model) is being reached but the model has nulls in it.
I know the data initial model from the AccountScreen is being populated since the other views that are being rendered is showing data.
Anyone see what I am doing wrong?
The problem is there's nothing inside your form except a submit button. You need to make sure input fields are there (either text boxes, select lists, or hidden fields), as those are what post data back to the controller.
You could try using EditorForModel inside your partial view:
#using (Html.BeginForm("MakePayment2", "Customer", FormMethod.Post))
{
#Html.EditorForModel()
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
}
Edit based on comments
Razor doesn't include an Html.HiddenForModel() method, for whatever reason. Possible workarounds:
List out each property of the model using Html.HiddenFor(model => model.Property)
Annotate the model properties with \[HiddenInput\]
Use EditorForModel() but wrap it in <div style="display: none;"></div> (NOTE that a malicious user can still modify the properties as if they were visible.)
Use only Html.HiddenFor(model => model.id) and fetch the model in the controller.
Use the serialization method in the MVC Futures assembly
Related quesion here:
Is there some way to use #Html.HiddenFor for complete model?
The problem is, you are creating a form containing nothing else than a submit button.
When you submit it, it posts nothing back to the server, thus your function receives an empty model.
#using (Html.BeginForm("MakePayment2", "Customer", FormMethod.Post))
{
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
}
This translates as :
<form method="POST" action="{url}">
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
</form>
More details :
Since in the logic you then redirect to a new page to collect payment information, you don't want to give the user the opportunity to mess with your model, thus you should query your customer data from your Context instead of trusting what is submitted in the POST.
Thus all you really need to add if this :
#using (Html.BeginForm("MakePayment2", "Customer", FormMethod.Post))
{
#Html.HiddenFor(model => model.{ID Field})
<div style="text-align:center;">
<input class="makePaymentInput" type="submit" value="Make a Payment" />
</div>
}
This way, you will be able to get your model back in the server side code.
Basically, your form submits nothing as there are no input fields inside the form scope. Try to wrap all your html in AccountScreen.cshtml within #using (Html.BeginForm( statement (and throw it out from MakePayment.cshtml).
I am attempting to create a message board in ASP.NET MVC. I have two partial views, one to display a message (this is recursive and will display all child... messages as well), and one to display a form to submit new messages. When a message gets posted, I want the form to submit via ajax, and return the partial view to display a message (the message that was just posted).
This is the partial view for displaying the form (NewMessage)
#model Intranet.Entities.ForumRepository.Message
<div id="#Html.Raw("formbox" + Model.ParentID)">
#using (Ajax.BeginForm("NewMessage", new AjaxOptions { UpdateTargetId = "formbox" + Model.ParentID })) {
#Html.TextAreaFor(m => m.Text, new { #class = "responsebox" })
#Html.HiddenFor(m => m.ParentID)
<br /><input type="submit" value="Save Comment" class="savebutton" />
}
</div>
And its submit method
[HttpPost]
public ActionResult NewMessage(ForumRepository.Message message) {
if (ModelState.IsValid) {
RouteData.Values.Add("Responses", message);
//message.SaveMessage();
return PartialView("DisplayMessage", message);
} else {
return PartialView(message);
}
}
When I attempt to submit the form, the form view doesn't get replaced with the DisplayMessage view. It keeps showing the form. Running in debug mode shows that the backend code is getting called.
I'm fairly certain that it has something to do with the fact that the div that the ajax code is using to redisplay is inside the NewMessage view (it can't replace its own container) but I have no idea how to set this up so that it will work.
As requested, here is some rendered HTML
<div id="formbox0">
<form action="/EventList/NewMessage/Q6UJ9A00T49L" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#formbox0" id="form0" method="post"><textarea class="responsebox" cols="20" data-val="true" data-val-required="The Text field is required." id="Text" name="Text" rows="2">
</textarea><input data-val="true" data-val-number="The field ParentID must be a number." data-val-required="The ParentID field is required." id="ParentID" name="ParentID" type="hidden" value="0" /> <br /><input type="submit" value="Save Comment" class="savebutton" />
</form>
</div>
I prefer to avoid the AjaxBeginForm method and like to write handwritten and Clean jQuery code.
I am giving a css class (commentItem) to the container div so that i can use it in my jQuery selector later.
#model Intranet.Entities.ForumRepository.Message
<h3> Enter your comment</h3>
<div id="formbox#Model.ParentID" class="commentItem">
#using(Html.BeginForm())
{
#Html.TextAreaFor(m => m.Text, new { #class = "responsebox" })
#Html.HiddenFor(m => m.ParentID)
<input type="submit" value="Save Comment" class="savebutton" />
}
</div>
<script type="text/javascript">
$(function(){
$(".savebutton").click(function(e){
var item=$(this);
e.preventDefault();
$.post("#Url.Action("NewMessage","EventList")",
item.closest("form").serialize(),function(data){
item.closest("div.commentItem").html(data);
});
});
});
</script>
This code will replace the existing form (or whatever inside the container div) with the content received from your Action method.