I don't understand why ModelState.isValid give me in all the ways. I set something in the email returns true and I pùt empty field, it returns true too. My question ism, what do I have to do to return true when the field is empty and nothing whn I wrote the email?
I have the next view file:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<div style="padding-top:5px;clear:both;"></div>
<% using (Html.BeginForm()) { %>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Email usuario</legend>
<div class="editor-field">
<%: Html.TextBoxFor(m => m.Email) %>
<%: Html.ValidationMessageFor(m => m.Email) %>
</div>
<input type="submit" value="Enviar Email" />
</fieldset>
<% } %>
<div style="padding-top:5px;clear:both;"></div>
</asp:Content>
The Controller is:
//
// GET: /Account/EmailRequest
public ActionResult EmailRequest()
{
return View();
}
[HttpPost]
public ActionResult EmailRequest(string email)
{
if (ModelState.IsValid)
{
// save to db, for instance
return RedirectToAction("AnotherAction");
}
return View();
}
My model class is:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Security;
namespace PortalClient.Models
{
public class EmailRequest
{
[Required(ErrorMessage = "required")]
public string Email { get; set; }
}
}
Change the signature of your post action from string email to EmailRequest model and then check the state. e.g.
[HttpPost]
public ActionResult EmailRequest(EmailRequest model)
{
if (ModelState.IsValid)
{
// save to db, for instance
return RedirectToAction("AnotherAction");
}
return View();
}
You need to bind a view model to your view.
Change your EmailRequest model to something more descriptive like:
public class EmailRequestViewModel
{
[Required(ErrorMessage = "Required")]
public string Email { get; set; }
}
Your get action method would look something like:
public ActionResult EmailRequest()
{
EmailRequestViewModel viewModel = new EmailRequestViewModel();
return View(viewModel);
}
Your post action method:
public ActionResult EmailRequest(EmailRequestViewModel viewModel)
{
// Check for null view model
if (!ModelState.IsValid)
{
return View(viewModel);
}
// Do whatever you need to do
return RedirectToAction("List");
}
And then your view. Please excuse the ASP.NET MVC 4 code, MVC 2 is prehistoric :) This is just part of your view:
#model YourProject.ViewModels.EmailRequestViewModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(x => x.Email)
#Html.ValidationMessageFor(x => x.Email)
}
I hope this helps.
you need to bind your model with binder first to have ability to chek it by Modelstat.IsValid
public ActionResult EmailRequest()
{
EmailRequest email = new EmailRequest();
TryUpdateModel(email);
if (ModelState.IsValid)
{
// save to db, for instance
return RedirectToAction("AnotherAction");
}
return View();
}
Related
I want to use data annotations in my app and the problem is when I click in submit button and don't fill the required field I don't see any error message and it submits. In the controller, the model.state works fine, but I think I should see the error message.
The model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace ValidationTest.Models
{
public class User
{
[Required(ErrorMessage = "Enter your name.")]
public string Name { get; set; }
public string Lastname { get; set; }
}
}
The View:
#model ValidationTest.Models.User
#{
ViewBag.Title = "Index";
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
#using (Html.BeginForm("Record", "Home"))
{
#Html.Label("Name:")
#Html.TextBoxFor(m => m.Name)
#Html.ValidationMessageFor(m => m.Name)
<br />
#Html.Label("Lastname:")
#Html.TextBoxFor(m => m.Lastname)
#Html.ValidationMessageFor(m => m.Lastname)
<input type="submit" value="Record" />
}
</body>
</html>
The controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ValidationTest.Models;
namespace ValidationTest.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Record(User usr)
{
if (ModelState.IsValid)
{
return Content("It Worked!");
}
return RedirectToAction("Index");
}
}
}
In Scripts folder inside the ASP.NET MVC project i have:
bootstrap.js
bootstrap.min.js
jquery-3.2.1.intellisense.js
jquery-3.2.1.js
jquery-3.2.1.min.js
jquery-3.2.1.min.map
jquery-3.2.1.slim.js
jquery-3.2.1.slim.min.js
jquery-3.2.1.slim.min.js
modernizr-2.6.2.js
You will have to add JavaScript script references of jquery.validate.min.js and jquery.validate.unobtrusive.min.js for client side validation to work.
Move return RedirectToAction("Index"); inside if (ModelState.IsValid) condition.
return view(); should be added outside if condition.
I have got the two buttons in the same view one is working with the data to show in a label in another view and I have written the function for the button2 (adding another value), when I click on the button2 its not showing the data in view ..... rather it's giving error like this ... http:404 Resource not found error
and this is the view
#model MvcSampleApplication.Models.products
#{
ViewBag.Title = "Valuesadd";
}
<h2>Valuesadd</h2>
#using (Html.BeginForm("SubmitValue","EnterValue",FormMethod.Post))
{
<div>
<fieldset>
<legend>Enter Textbox Value</legend>
<div class ="editor-label">
#Html.LabelFor(m => m.EnteredValue)
</div>
<div class="editor-field">
#Html.TextBoxFor(m=>m.EnteredValue)
</div>
<p>
<input type="submit" value="Submit1" />
</p>
</fieldset>
</div>
}
#using (Html.BeginForm("SubmitValue2","EnterValue",FormMethod.Post))
{
<p>
<input type="submit" value="Submit2" />
</p>
}
and this is the controller for
namespace MvcSampleApplication.Controllers
{
public class EnterValueController : Controller
{
[HttpPost]
public ActionResult SubmitValue(MvcSampleApplication.Models.products model)
{
TempData["logindata"] = model.EnteredValue;
return RedirectToAction("submittedvalues" , "SubmitValue2");
// how can we redirect to another view when the button is clicked in one view
}
public ActionResult submittedvalues()
{
var model = new MvcSampleApplication.Models.category();
string data = TempData["logindata"] != null ? TempData["logindata"].ToString() : "";
model.lablvalue = data;
return View(model);
}
// action for second button click
public ActionResult submittedvalues2()
{
var model = new MvcSampleApplication.Models.category();
string data = TempData["logindata"] != null ? TempData["logindata"].ToString() : "";
model.lablvalue = "HIIII"+data;
return View(model);
}
}
}
would you pls suggest any idea ..
Many thanks...
Your form action and action in the controller are not named the same. Also you don't have a HttpPostfor it
#using (Html.BeginForm("SubmitValue2","EnterValue",FormMethod.Post))
{
}
//add this
[HttpPost]
public ActionResult submittedvalues2()
{
var model = SOMETHING;
return View("submittedvalues", model);
}
or
[HttpPost]
public ActionResult submittedvalues2()
{
//Do your post actions and redirect to action
return RedirectToAction("submittedvalues");
}
SubmitValue2 in the form should be submittedvalues2, and add a HttpPost attribute on it
I have a small website with a Homepage which displays x2 paragraphs of text. These paragraphs are populated from a single record in a database containing 3 fields ("ID", "para1" and "para2"). This record is updated via a form which contains x2 textareas (assigned to update "para1" and "para2"), allowing me to type into the textarea, click "update" and then the two paragraphs on the Homepage will update to reflect the new text.
To navigate to the form page that contains the textareas from the homepage I click an "admin" link which takes me to a logon page, I enter username and password and click "login" and this forwards me on to the "update" page.
What I'd like, is the x2 textarea inputs to be pre-populated with the data stored in the "para1" and "para2" fields in the database table. This way, if someone wanted to make a minor edit to either of the paragraphs on the homepage then they won't need to re-type the whole thing from scratch.
I'm using C# Razor in Microsoft Visual Web Developer Express. I am a total beginner at not just this, but any form of development work, so I'm learning as I'm going, please be gentle :-)
Code examples below:
(the View page):
#model DFAccountancy.Models.Data
#{
ViewBag.Title = "Update";
}
<h2>Update</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Data</legend>
<div class="editor-label">
#Html.LabelFor(model => model.para1)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.para1, new { cols = 75, #rows = 5 })
#*#Html.EditorFor(model => model.para1)*#
#Html.ValidationMessageFor(model => model.para1)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.para2)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.para2, new { cols = 75, #rows = 5 })
#*#Html.EditorFor(model => model.para2)*#
#Html.ValidationMessageFor(model => model.para2)
</div>
<p>
<input type="submit" value="Update" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
(the Model):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
namespace DFAccountancy.Models
{
public class Data
{
[DataType(DataType.MultilineText)]
public int ID { get; set; }
public string para1 { get; set; }
public string para2 { get; set; }
}
public class DataDBContext : DbContext
{
public DbSet<Data> Data { get; set; }
}
}
(the Controller):
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DFAccountancy.Models;
namespace DFAccountancy.Controllers
{
public class DataController : Controller
{
private DataDBContext db = new DataDBContext();
//
// GET: /Data/
public ViewResult Index()
{
return View(db.Data.ToList());
}
//
// GET: /Data/Details/5
public ViewResult Details(string id)
{
Data data = db.Data.Find(id);
return View(data);
}
//
// GET: /Data/Update/5
public ActionResult Update()
{
return View();
}
//
// POST: /Data/Update/5
[HttpPost]
public ActionResult Update(Data data)
{
if (ModelState.IsValid)
{
data.ID = 1; //EF need to know which row to update in the database.
db.Entry(data).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View(data);
}
}
}
You just need to update your Update method to include passing in an Id
//
// GET: /Data/Update/5
public ActionResult Update()
{
Data data = db.Data.Find("1");
return View(data);
}
In addition the link to the update method will need to be updated to pass that Id in as well. Assuming you're using the standard list template for MVC.
<td>
#Html.ActionLink("Update", "Update") |
...
</td>
I have some questions regarding my MVC learning curve
Goal:
I want to get the txtMHM entered text
after the btnStat is pushed and show the entered text via a label or span or ...
The View Model you should use (simplified):
public class YourViewModel
{
public string TextEntered { get ; set ; }
}
The View:
#model YourViewModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.TextEntered)
<br />
<input id="btnStat" type="submit" value="MHM" />
}
#Html.LabelFor(m => m.TextEntered)
The Controller Action method:
[HttpPost]
public ActionResult ChangeLabelText(YourViewModel yourViewModel)
{
return View(yourViewModel);
}
Your Altered Code
index.cshtml
#model MVCTest1.Models.EnteredTextModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.TextEntered)
<br />
<input id="btnStat" type="submit" value="MHM" />
}
#Html.LabelFor(m => m.TextEntered)
The Model
namespace MVCTest1.Models
{
public class EnteredTextModel
{
public string TextEntered { get; set; }
}
}
The HomeController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MVCTest1.Models ;
namespace MVCTest1.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
[HttpPost]
public ActionResult Index(EnteredTextModel theModel)
{
return View(theModel);
}
public ActionResult About()
{
return View();
}
}
}
Sypress,
Best practice would be to use a viewmodel for your action. However, at a very simple level, based on exactly what you have above, you could use the viewbag object to pass back the input value. without further ado, the frig, i mean code :):
Controller actions:
[HttpGet]
public ActionResult ChangeLabelText()
{
return View();
}
[HttpPost]
public ActionResult ChangeLabelText(FormCollection formCollection)
{
ViewBag.LastNameEntered = formCollection["txtName"];
return View();
}
View stuff (assumes that the view is named ChangeLabelText.cshtml of course):
#{
ViewBag.Title = "ChangeLabelText";
}
<h2>ChangeLabelText</h2>
<form action="ChangeLabelText" method="post">
<input id="txtMHM" type="text" name="txtName" value="" />
<input id="btnStat" type="submit" value="Post" />
<br />
#Html.Label("Entered Text");
<span id="spnEnteredText">#ViewBag.LastNameEntered </span>
</form>
and the above is called as such http://localhost:xxxx/Home/ChangeLabelText (where xxxx is the port number of your dev server)
I would add that this would NOT be the way that I would approach this to be honest, but is my direct response to your example. go for sharks' example using the viewmodel.
good luck
[EDIT] - I've updated my answer now that I'm at a machine, so the above should work as intended.
I've read a lot of similar posts about null model but my case is very very simple and still the model on Create action is null. What am I doing wrong???
Here is the situation: One main view, two strongly typed partial views inside, each binded to a public property of the main model. Any help is appreciated.
models:
public class SimpleModel1
{
public IEnumerable<string> SomeStrings1 { get; set; }
}
public class SimpleModel2
{
public IEnumerable<string> SomeStrings2 { get; set; }
}
public class ComplexModel
{
public SimpleModel1 model1 { get; set; }
public SimpleModel2 model2 { get; set; }
public IEnumerable<string> SomeStringsComplex { get; set; }
}
int he controller:
public ActionResult Create()
{
ComplexModel complex = new ComplexModel();
complex.model1 = new SimpleModel1();
complex.model1.SomeStrings1 = new List<string> { "a1", "a2", "a3"};
complex.model2 = new SimpleModel2();
complex.model2.SomeStrings2 = new List<string> { "b1", "b2", "b3" };
complex.SomeStringsComplex = new List<string> { "c1", "c2", "c3" };
return View(complex);
}
[HttpPost]
public ActionResult Create(ComplexModel model)
{
if (ModelState.IsValid)
{
var test = model.SomeStringsComplex;
}
return View();
}
Views:
2 strong partial views -each for model
<%# Control Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<MvcApp1.Models.SimpleModel2>" %>
<fieldset>
<legend>Fields</legend>
<% foreach (string item in Model.SomeStrings2)
{%>
<p>
<label for="Title">Item Title:</label>
<%= Html.TextBox(item,item)%>
</p>
<%
}
%>
</fieldset>
1 main view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MvcApp1.Models.ComplexModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Create
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Create</h2>
<% using (Html.BeginForm()) {%>
<fieldset>
<div> Own values
<% foreach (string item in Model.SomeStringsComplex)
{%>
<p>
<label for="Title">Item Title:</label>
<%= Html.TextBox(item,item) %>
</p>
<%
}
%>
</div>
<div>Simple values 1
<%Html.RenderPartial("SimpleModelView1", this.ViewData.Model.model1, new ViewDataDictionary()); %>
</div>
<div>Simple values 2
<%Html.RenderPartial("SimpleModelView2", Model.model2, new ViewDataDictionary()); %>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
I'm going to take a wild stab and say your Model validation is failing when posting a ComplexModel back to the server
Your Model validation doesn't have to fail at all. You're not returning anything from inside the if block so you're always returning a View with no Model associated:
if (ModelState.IsValid)
{
var test = model.SomeStringsComplex;
}
return View(); // View is called with no Model data
Judging by your code, that would cause the Create view to be instantiated with no Model. That can be fixed fairly simply:
[HttpPost]
public ActionResult Create(ComplexModel model)
{
if (ModelState.IsValid)
{
var test = model.SomeStringsComplex;
// Do something to Create the object
RedirectToAction("Index");
}
// Model State is invalid, return so the user can correct
return View(model);
}
Aren't you supposed to send something to the view, on that line?
return View();
I think the problem is how you are specifying your text fields - the model binder does not know how to assign them back to the properties that they came from.
You may want to read this Haacked article that describes how to use model binding for enumerable properties:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Finally I found a solution. The data posted to Create method should look s.th. like this:
[HttpPost]
public ActionResult Create(ComplexModel mainModel, SimpleModel nestedModel, SimpleModel2 nested2Model)
{
if (ModelState.IsValid)
{
var main = mainModel;
var nested1 = nestedModel;
var nested2 = nested2Model;
}
return View();
}
The nested parameters are not null when the models are binded to partial views. If used in the main form through main model than the values are in the instance of the main model. I've also changed IEnumerable<string> to IList<string> and then rendered the string values with
for (int i = 0; i < Model.Strings.Count; i++)
{ %>
<%: Html.EditorFor(m => m.Strings[i])%>
<% }
Thanks all