MVC [Required] attribute not working - asp.net-mvc

I'm new to MVC and trying to do a simple application form with a check box to accept the terms.
I cant understand why my error message isnt showing.
This is my .cshtml
<div class="form-row">
<div class="validation-container">#Html.ValidationMessageFor(m => m.HasAcceptedTerms)
</div>
<div class="label-container">#Html.LabelFor(m => m.HasAcceptedTerms)</div>
<div class="form-control">#Html.EditorFor(m => m.HasAcceptedTerms)</div>
</div>
my ViewModel
[Required(ErrorMessage = "Please indicate you have read the statements above before sending your request")]
[Display (Name = "Please tick to show you accept all the above statements")]
public bool HasAcceptedTerms
{
get; set;
}
Controller
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AppForm(AppFormViewModel App)
{
if (ModelState.IsValid)
{
return View();
}
return View(App);
}
When I click the button, the page refreshes with no changes. While debugging, the Model.State is false, so I really cant understand why nothing is happening. Does anyone have any ideas?

Being a value type, your bool has a default value of false - this is a value and therefore does not get recognised as "missing". You will need to validate that the value is true, rather than being required.
You could look at this question for a way to achieve this.

Related

How to return a single string to a div in my current page from HTTP POST in ASP.NET MVC 5?

I'm trying to post a message after a contact form, indicating to the user that their message has been sent after they click the submit button. I don't want to redirect to a different page or to return a different view inside my HTTP Post action method. How do I do something like that in ASP.NET MVC framework?
Below is my code sample:
#*contactus.cshtml*#
#model MySite.Models.ContactModel
#using (Html.BeginForm())
{
<div class="col-md-6">
<div class="form-group">
#Html.TextBoxFor(model => model.Name})
<p>#Html.ValidationMessageFor(model => model.Name)</p>
</div>
<div class="form-group">
#Html.TextBoxFor(model => model.Email)
<p>#Html.ValidationMessageFor(model => model.Email)</p>
</div>
<div class="form-group">
#Html.TextAreaFor(model => model.Message)
<p>#Html.ValidationMessageFor(model => model.Message)</p>
</div>
<div class="col-lg-12">
<button type="submit">Send Message</button>
</div>
</div>
}
#*ContactModel.cs*#
public class ContactModel
{
[Required(ErrorMessage = "* Please enter your name.")]
[StringLength(100, MinimumLength=3, ErrorMessage="* Please enter your full name.")]
public string Name { get; set; }
[Required]
[EmailAddress(ErrorMessage="* Not a valid email address.")]
public string Email { get; set; }
[Required]
public string Message { get; set; }
}
I only have a contact us form right now on my home/index page, and I don't want to redirect it to any other pages. I would like to display a message right below the Send Message button, but I'm not sure how to go about it using the action method below:
#*HomeController.cs*#
public ActionResult Index(ContactModel model)
{
if (ModelState.IsValid)
{
// this is my helper library, for brevity, I'm not copying it.
EmailHelper emailService = new EmailHelper();
bool success = emailService.SendEmail(model.Name, model.Email, model.Message);
return Content(success ? "success" : "no...something went wrong :(");
} else {
return View(model);
}
}
Right now this controller will return the string inside Content which replaces my entire page, and I would like the string to be returned below my contact form. Also, I have two sections on the same html page with Contact Form as the second one, when I return View(model), it automatically redirects to the first section, which isn't ideal... How do I tell the controller to only redirect it to the second section after the POST method? In addition, I feel like it would be more efficient if it didn't return the whole page... so is there a way to only return a Message string to the div?
You can place a hidden div on the page which will contain the message.
Then when your form has been submitted, capture the click event for your button, and use that to display the hidden message.
Let me know if you need a code example. Posting your form would help us answer you more specifically.
To only show the success message if the form is successfully sent, I would recommend setting a value in the ViewBag in the POST action of the controller and then returning that same page if you want to still have the same page showing. On the View itself, you could then place an If statement to test if the ViewBag variable contains a value and if so, display the message.
Controller:
[HttpPost]
public ActionResult YourAction(YourModel m)
{
//Do stuff to send the contact form
...
if(error)
{
ViewBag.Message = "There was a problem sending the form.";
}
else
{
ViewBag.Message = "The form was sent successfully!";
}
return View(m);
}
View:
#if(ViewBag.Message != null)
{
<div>#ViewBag.Message</div>
}
This lets you check if the form was posted successfully on the server before telling the user the result and will only display a message if ViewBag.Message has been set. Note that you can have as many ViewBag variables as you want and can name them whatever you want... just remember which one you use in which place.
EDIT:
Following the comments, this could also be done using an AJAX call. I'll use the jQuery .post() method for simplicity sake.
In Script:
<script>
$(document).on('click', "#buttonId", function() {
var nameText = $("#IdOfNameField").val();
var emailText = $("#IdOfEmailField").val();
var messageText = $("#IdOfMessageField").val();
$.post('#Url.Content("~/Controller/AJAXPostContactForm")',//the url to post to
{name: nameText, email: emailText, message: messageText }, //these are values to be sent to the action
function(){ //this is the success function
$("#successMessage").val("Form posted successfully.");
}
)
.fail(function() {//failure function
alert("Something went wrong.");
});
}
</script>
Controller:
public void AJAXPostContactForm(string name, string email, string message)
{
try
{
//do stuff with the information passed into the action
}
catch(exception e)
{
//Handle errors. If error thrown, Ajax should hit fail block in script
}
finally
{
//do any cleanup actions
}
}
View:
<div id="successMessage"></div>
I have not tested this code but it should theoretically work. On a specific button click, it will get the values from the form fields, post those values to a specialized ActionResult in the controller, and then return a message about what happened.

MVC Razor Form submit not working

I am trying to use a simple form to allow authorized users to modify content on select pages on an MVC3 Razor site that I'm building. I am unable to get the edit form to post correctly though.
My model is as follows:
public class WebContent
{
public virtual UInt32 id { get; set; }
public virtual String page { get; set; }
public virtual String section { get; set; }
[UIHint("tinymce_jquery_full"), AllowHtml]
public virtual String content { get; set; }
}
My Controller:
[Authorize]
public ActionResult Edit(String page, String section)
{
WebContent content = _WebContent.GetSection(page,section);
return View(content);
}
[Authorize]
[HttpPost]
public ActionResult Edit(WebContent content)
{
if (ModelState.IsValid)
{
_WebContent.Update(content);
return View("Index");
}
else return View("Index");
}
And my View:
#model SongbirdsStudios.Models.WebContent
#{
ViewBag.Title = "Edit '"+Model.page+"'Page Content";
}
<div>
<h2>Edit</h2>
#using (Html.BeginForm())
{
<fieldset>
<legend>Page Content</legend>
#Html.HiddenFor(m => m.id)
#Html.HiddenFor(m => m.page)
#Html.HiddenFor(m => m.section)
<div class="editor-label">
Content
</div>
<div class="editor-field">
#Html.EditorFor(m => m.content)
</div>
<p>
<input type="submit" value="Update" />
</p>
</fieldset>
}
</div>
The view renders correctly and displays the expected elements. The UIHint("tinymce_jquery_full") is getting picked up correctly and the TinyMCE editor appears on the page. But, when the form submits, I get an exception.
System.Web.HttpRequestValidationException: A potentially dangerous Request.Form value was detected from the client (content=...)
Everything I've read indicates that the AllowHTML attribute should allow this to post, but it's not for some reason.
I can get around this by adding the [ValidateInput(false)] attribute to the HttpPost controller method. If I do that, then this exception does not occur, but the model still does not get passed to the controller. It just passes null instead. Examining the HttpContext in the debugger indicates that it is passing 4 separate values - one for each property in my model instead of passing the model class back to the controller. I can't figure out what I need to change to make this work correctly.
I'm hoping it's something simple that I missed, and someone with a better eye can see what it is.
So after further investigation into how ASP MVC maps form fields to the model class and examining the HTML emitted to the browser, I found that this was an issue with the name of the property in my WebContent class.
public virtual String content { get; set; }
The TinyMCE editor uses a content variable to define certain characteristics associated with the editor interface. This was apparently causing the HTML 'content' generated by the user input in the editor to not get mapped back to the Model property.
Simply changing the name of the property in the model class (and of course fixing the corresponding database mapping and view references) immediately fixed the problem.
public virtual String web_data_content { get; set; }
Everything else being identical, this worked perfectly with the UIHint and AllowHTML attributes.
Add this attribute on your action
[ValidateInput(false)]
This should solve your problem
if you use ie7
this may has some err
<input type="submit" value="Update" />
give the button a name

In MVC view, when form is posted, request contains form values while all model fields are 0

Using Visual Studio 2010, MVC project
When my form is submitted (currently via javascript, but same results with a submit button), the action is getting an empty model with both of the fields in it being zero instead of containing the value I entered into the textbox. The Request object does contain the correct name/value pair in the Form collection.
Model values going the other way work fine - so based on my [HttpGet] CallDisplayHome() action, the form loads with the textbox value being 1.
If anyone has a clue as to why it would not work coming back via POST, I would sure appreciate it.
Model being used:
namespace TCSWeb.Models
{
public class CallDisplayModel
{
public int SelectedRowIndex;
public int SelectedLineID;
}
}
View:
#model TCSWeb.Models.CallDisplayModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<body>
/*
There a Jscript datatable here and a bunch of scripts for working with it in the header I am skipping because I am hoping they are not relevant
*/
<div>
#using (Html.BeginForm("Testing", "CallDisplay", FormMethod.Post, new { name = "submitSelLine" }))
{
#Html.TextBoxFor(m => m.SelectedLineID)
<p>
<input type="submit" value="Log On" />
</p>
}
</div>
<button onclick="SubmitSelCallRecord()">#LangRes.Strings.calldisplay_opencallrecord</button>
My controller actions:
[HttpGet]
public ActionResult CallDisplayHome()
{
TCSWeb.Models.CallDisplayModel temper = new CallDisplayModel();
temper.SelectedLineID = 1;
temper.SelectedRowIndex = 1;
return View(temper);
}
[HttpPost]
public ActionResult Testing(TCSWeb.Models.CallDisplayModel cdmodel)
{
return RedirectToAction("CallDisplayHome"); //breaking here, cmodel has zero for selectedlineid
}
You need to declare your CallDisplayModel variables as properties:
public int SelectedRowIndex { get; set; }
[Required]
public int SelectedLineID { get; set; }
You can also add a little bit of validation to make sure that the user provides the correct information.
Change your post method to the following:
[HttpPost]
public ActionResult Testing(TCSWeb.Models.CallDisplayModel temper)
{
//check if valid
if(ModelState.IsValid)
{
//success!
return RedirectToAction("CallDisplayHome");
}
//update error! redisplay form
return View("CallDisplayHome", temper);
}
And display the errors in your view like so:
#Html.ValidationMessageFor(m => m.SelectedLineID)
#Html.TextBoxFor(m => m.SelectedLineID)
I'm unsure what your submitSelCallRecord button is doing, as it is referencing the javascript that was omitted.

Asp.Net Mvc 2 Checkbox always false in model

I have a checkbox like this:
<%= Html.CheckBoxFor(x => x.IsSendingQualitySurvey) %>/>
when checking the checkbox and submitting, I get the typical 2 form values:
IsSendingQualitySurvey: true
IsSendingQualitySurvey: false
This is perfectly valid for the way the mvc modelbinder handles checkboxes.
Then in the controller action:
[HttpPost]
public ActionResult Edit(Guid id, TicketEditViewModel ticketEditViewModel)
ticketEditViewModel.IsSendingQualitySurvey (a normal bool) is always false.
I don't have any custom model binders and it works elsewhere.
Strangely enough I've had the same problem in another view quite a while ago, where I had to create the input manually, looks like this:
<input type="checkbox" value="true" name="<%=Html.NameFor(x => x.IsRequestingVisit) %>" id="<%=Html.NameFor(x => x.IsRequestingVisit) %>" />
This worked, but when I copied the exact same over to the other view, the value is still always false.
Wheres the catch?
Thanks.
EDIT Got the wrong end of the stick... sorry
Have you tried fetching the raw value out of the post data like so:
In the Controller:
[HttpPost]
public ActionResult Edit(Guid id, TicketEditViewModel ticketEditViewModel,
FormCollection fc) {
if(fc["IsSendingQualitySurvey"].Contains("true")) {
//Do something.
}
}
In the View:
<%= Html.CheckBoxFor(model => model.IsSendingQualitySurvey) %>
Hope this helps..
The model binder likely wont pickup the binding. My advice is to change your action to:
[HttpPost]
public ActionResult Edit(Guid id, TicketEditViewModel model)
The model binder wants to find properties in the Request that have a prefix that match your object name. Since there is no naming prefix on the client side, there are no properties with the prefix "ticketEditViewModel".
The alternative is to name a variable on the page:
<% var ticketEditViewModel = Model; %>
<%= Html.CheckBoxFor(model => ticketEditViewModel.IsSendingQualitySurvey) %>
For following model:
public class StartViewModel {
public string Id{ get; set; }
public string Name { get; set; }
public bool Accept { get; set; }
}
-> Accept =false.
The solution: Change public bool Accept { get; set; } to public string Accept { get; set; }
When submit, if checkbox is checked, The "Accept" value = "on". You can dectect checked value by the way.
I'm not sure whether this will work for you, but in fact it solved the same issue for me. Try adding (not replacing) a hidden field for the same model's property like this:
#Html.HiddenFor(x => x.IsSendingQualitySurvey)

How can I add "Add user link" when the username is not in the database?

I need to display the link "Add as User" in my view only when the username is not in the database. I have a method called UsernameExists in my SQL data access layer that I would like to use in the AccountController. How would I go about doing that? The logic should be on the server side, and the link shown on the view.
You can call the UsernameExists method from your controller and add the result to the ViewBag. In your view check the ViewBag and if the bool is true (the username already exists) then don't display the "Add as User" else display it.
Example-
Controller:
ViewBag.usernameExists = model.UsernameExists(username);
View:
#if(!(bool)ViewBag.usernameExists)
{
<a>Add as User</a>
//Whatever you want to display
}
Sounds to me like using remote validation is what you would want to do, then you would show the hidden link on the page. You get this almost for free with MVC, then you would do some client side script to show/hide the link.
ViewModel:
public CreateUserVM
{
[Required]
[Remote("UsernameExists","YourController")]
string Username { get; set; }
}
View:
#model CreateUserVM
#Html.LabelFor(model => model.Username, "Enter User Name:")
#Html.EditorFor(model => model.Username)
Controller
public JsonResult UsernameExists(CreateUserVM user)
{
//logic to check if user name exists
}

Resources