MVC4 validation does not work - c#

I have simple 1 page application to send email out to users. I have 3 fields for name, email and phone number. The code seems to work with input button, with validations firing and throwing proper error message. But I am more inclined towards using anchor tag (ActionLink) for my UI. The data still posts when I click on anchor tag (using jQuery) but the validations don't fire. Is there anything that I am missing or there's a better way of doing it?
I have used this post as reference.
Model
public class Contact
{
[Required(ErrorMessage = "Name is required")]
public string Name { get; set; }
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; }
[Required(ErrorMessage = "Phone is required")]
public string PhoneNumber { get; set; }
}
View
<div>
#Html.TextBoxFor(model => model.Name, new { #class = "form-control", placeholder="Name" })
#Html.ValidationMessageFor(model=>model.Name)
</div>
<div>
#Html.TextBoxFor(model => model.Email, new { #class = "form-control", placeholder="Email" })
#Html.ValidationMessageFor(model=>model.Email)
</div>
<div>
#Html.TextBoxFor(model => model.PhoneNumber, new { #class = "form-control", placeholder="Phone" })
#Html.ValidationMessageFor(model=>model.PhoneNumber)
</div>
<div>
<input type="submit" value="Give me Free Advice" />
<div class="btn">
#Html.ActionLink("I want free advice", "designerhome")
</div>
</div>
<script>
$(function () {
$('.btn').click(function (e) {
$.post("/campaign/designerhome", { Name: $("#Name").val(), Email: $("#Email").val(), PhoneNumber: $("#Phone").val() }, function (result) {
//do whatever with the response
if (result.status == true) {
alert('Email submitted successfully');
}
});//end of post
});//end of click
});
</script>
Controller
[HttpPost]
public ActionResult designerhome(Contact contact)
{
if (ModelState.IsValid)
{
}
return View("Advert1");
}

We have some reasons why validation not working
1. Check appsettings in web config
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
Both Should be true if you want to run client side validation.
2. Seems in your code you are not using Form tag as it is posted in the question
Form tag is must for validation
3. Jquery is not properly refrenced on layout page
please check following jquery refrence on your layout page
jquery.unobtrusive*.js
jquery.validate*.js
Hope it will help you.

I would force the validation in your click handler, as jQuery seems to do that only for the automatic submit of the form (and not for the manual post() you are doing):
$('.btn').click(function (e) {
if ($('#YourFormIdHere').valid()) { // Will force validation
$.post(...);
}
});

As your making an Ajax request to the Action, your validations will not be reflected as the view is not rendered again. To stay on the same track you can return the JSON like
return Json(new {Valid = validState,
Errors = Get Errors FromModel State,
});
and then repopulate using the JavaScript.
Another Way could be around making custom Helpers which will |make a POST request to the desired Action.Code Reference for the same is here.
And at last what you can do is create a HTML button and make a POST request.

Simply style your input button to look like a link with the following CSS:
input[type=submit] {
background:none!important;
border:none;
padding:0!important;
color:#069;
text-decoration:underline;
cursor:pointer;
}
<input type="submit" value="Give me Free Advice" />
This will allow all the built in validation to work as is, with no difference to the user other than the appearance.
If your requirement is to use ajax to post you must manually call the validate method within the JavaScript with jquery unobtrusive.
This can be done with the following:
// replace the `formId` with the one defined in your view
var $form = $('#formId');
$.validator.unobtrusive.parse($form);
$form.validate();
if ($form.valid()) {
// Do post
}
In order to manually pull out the error messages you can use this:
$.each($form.validate().errorList, function (key, value) {
$errorSpan = $("span[data-valmsg-for='" + value.element.id + "']");
$errorSpan.html("<span style='color:red'>" + value.message + "</span>");
$errorSpan.show();
});
Which replaces the ValidationMessageFor markup with the failure messages.

Related

Trouble with checkbox validation in Razor form

I am currently at an internship and am completely new to Razor and C# MVC. I am currently building a simple Razor form, but my validation is giving me grief for a check box.
Here is my model code:
[DisplayName("Sign me up for spam* ")]
[Range(typeof(bool), "true", "true", ErrorMessage = "You must sign up for spam.")]
public bool Check { get; set; }
Here is my Razor markup:
#Html.LabelFor(model => model.Check, new { #class = "" })
#Html.CheckBoxFor(model => model.Check, new { #class = "example1"})
Here is the generated HTML:
<input class="example1" data-val="true" data-val-range="You must sign up for spam." data-val-range-max="True" data-val-range-min="True" data-val-required="The Sign me up for spam* field is required." id="Check" name="Check" type="checkbox" value="true">
<input name="Check" type="hidden" value="false">
I know that Razor will generate both inputs automatically. My problem is that the validation is simply not working on the check box. The model state is always invalid because of it, and on the client side the error message appears when the box is checked and disappears when the box is unchecked. I have been googling for answers, but have come up short and my mentor doesn't know what is going screwy either.
It looks like a client side reversed issue. Add this jquery in your page and I think it will be fixed:
<script>
// extend range validator method to treat checkboxes differently
var defaultRangeValidator = $.validator.methods.range;
$.validator.methods.range = function(value, element, param) {
if(element.type === 'checkbox') {
// if it's a checkbox return true if it is checked
return element.checked;
} else {
// otherwise run the default validation function
return defaultRangeValidator.call(this, value, element, param);
}
}
</script>

asp.net mvc remote validation with jquery

I need a help.
I have a User registration form and I have to map "Customer" with user.
Now I want to validate user "customer" which is came from another source and I put the "customer" in Select list "customer" are more then 2000 that's why I use JQuery Chosen plugin to search in select list
but "customer" Field depend on "roles" that's why on page load "customer" field is hidden by default when I change the role "customer" field(chosen select list) display and when i am Selecting customer its not firing remote validation.
I tried to make it visible on "inspect element" and I change the display:none to display:bock and try to change value from chosen its not working when i change the orignal select list value from clicking on select list then its working fine i mean its firing my remote validator method here is full code example what i am doing.
please help i want to validate on when chosen select list value change.
This is RegisterViewModel
public class RegisterViewModel
{
[Required]
[Display(Name = "Role")]
public string Role { get; set; }
//for edit view model additionalFields which will only require for edit mode
//[System.Web.Mvc.Remote("DoesCustomerCodeExist", "Account", AdditionalFields = "OldCustomerCode")]
[Required(AllowEmptyStrings = false, ErrorMessage = "Customer Code is required.")]
[Display(Name = "Customer Code", Description = "A customer code come from our oracle system.")]
[System.Web.Mvc.Remote("DoesCustomerCodeExist", "Account")]
[Range(0, int.MaxValue, ErrorMessage = "Please enter valid Customer Code in number only.")]
public string CustomerCode { get; set; }
}
Here is my view cshtml in this file also have js code to display customers chosen Select list when role changed.
//select Role
<div class="form-group">
#Html.LabelFor(m => m.Role, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.Role, ViewBag.Roles as SelectList,"", new { #class = "form-control chosen-select", data_placeholder = "Select a Role" })
#Html.ValidationMessageFor(m => m.Role, "", new { #class = "text-danger" })
</div>
</div>
//Customer Code
<div class="form-group condition-div user hidden ">
//this hidden field is only for edit mode
//#Html.Hidden("OldCustomerCode", Model.CustomerCode)
#Html.LabelFor(m => m.CustomerCode, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.CustomerCode, (SelectList)ViewBag.Customers, "", new { #class = "form-control chosen-customers", data_placeholder = "Select Customer" })
#Html.ValidationMessageFor(m => m.CustomerCode, "", new { #class = "text-danger" })
</div>
</div>
#section Styles{
#Styles.Render("~/Content/chosen")
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/chosen")
<script type="text/javascript">
$('input[type=text]').tooltip(
{
placement: "right",
trigger: "focus"
}
);
$(".chosen-select").chosen({ allow_single_deselect: true});
$('#Role').change(function () {
if (this.value == "") {
$('.condition-div').addClass('hidden'); // hide all the conidional divs
} else if (this.value == "NBP User" || this.value == "NBP Head" ) {
$('.condition-div.admin').addClass('hidden'); /// hide admin conditional divs
$('.condition-div.user').removeClass('hidden'); // show user role conditioanl div
//configure selectlist to Chosen select and if i remove this line and show orignal select list its working fine mean remote validating on change but if i use this is not working on change.
$(".chosen-customers").chosen({ allow_single_deselect: true, search_contains: true });
$.validator.setDefaults({ ignore: ":hidden:not(.chosen-customers)" });
} else if (this.value == "ICIL User" || this.value == "ICIL Head" || this.value == "FIO User" ) {
$('.condition-div.user').addClass('hidden'); /// hide user role conditional divs
$('.condition-div.admin').removeClass('hidden'); // show admin role conditional divs
$(".chosen-branch").chosen({ allow_single_deselect: true });
$.validator.setDefaults();
}
});
</script>
}
Controller Action to validate Customer Code
public ActionResult DoesCustomerCodeExist(string CustomerCode, string OldCustomerCode)
{
//the oldCustomerCode will come null in this case cause its register view and in edit view OldCustomerCode will be use
if (CustomerCode == OldCustomerCode)
return Json(true, JsonRequestBehavior.AllowGet);
if (DbContext.Users.Any(x => x.CustomerCode == CustomerCode))
return Json("Customer code already exists in application. Please verify user details.", JsonRequestBehavior.AllowGet);
if (DbOracle.IsCustomerCodeExist(CustomerCode))
return Json(true, JsonRequestBehavior.AllowGet);
else
return Json("The customer code does not exist in database.", JsonRequestBehavior.AllowGet);
}
All code working fine if i did not use jquery chosen plugin.
In short issue is when I use chosen plugin for select list remote validation is stop validating values.
I can share images if u guys need now I have a limited account so i cant upload snaps shots....
Please help me.
you should have to put some JQuery on client side to track the "CustomerCode" field when change of customer field jsut call "focusout()" event of "CustomerCode" e.g:
$('#CustomerCode').change(function () {
$(this).focusout();
});

Update partial view from drop down list selection using MVC 5 EF 6

I am working on my third year project and I'm struggling with this one section so badly, I have looked around and found some answers but I really done know how to implement in my code because it always just doesn't work. So I don't know what I'm doing wrong.
What i would like is for the partial view to change when the drop down selected item has changed.
This is what was generated in the view for this section.
<div class="form-group">
#Html.LabelFor(model => model.TypeID, "TypeID", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("TypeID", String.Empty)
#Html.ValidationMessageFor(model => model.TypeID)
</div>
</div>
Most solutions I have seen use a #html.dropdownlistfor().
Any help would be appreciated even if you could just point me to the right place.
The drop down list is filled from the database relationships.
I have got this to work if i use labels in an "a" tag with an href but they are hard coded onto the page. I want to use the drop down list so that if i update the database it will have the updated list instead of me going to change it in the code, its also more user friendly in my eyes.
Thanx in advance
You could retrieve the data from the server and construct/change the DOM via JQuery, or you could use a partial view that is appropriate for each question type, attaching an event handler to the change event of the drop-down via JQuery.
One approach, loading partial views:
yourNamespace.yourScript.js file (include the file in your main view via the <script> tag with the src attribute):
(function ($) {
if (!window.yourNamespace) {
window.yourNamespace = {};
}
if (!window.yourNamespace.yourPageScript) {
window.yourNamespace.yourPageScript = function () {
var populateView = function (dropDown) {
if (dropDown && dropDown.length) {
var value = dropdown.val();
$.ajax({
method: "GET",
cache: false,
url: "some.url/PopulateType",
dataType: "HTML"
data: { selectedValue: value }
})
.done(function (response) { // jQuery 1.8 deprecates success() callback
var div = $('#partialViewDiv');
div.html('');
div.html(response);
});
}
};
return {
populateView: populateView
};
};
}
}(jQuery));
Your main view could have something like this:
<script type="text/javascript">
// put the script section somewhere appropriate in the page
$(document).ready(function () {
var dropDown = $('#TypeId'); // assuming the ID of this element is 'TypeId'
dropDown.change(function () {
yourNamespace.yourPageScript.populateView(dropDown);
});
});
</script>
<div id="partialViewDiv">
#Html.RenderPartial("path to initial partial view", model);
</div>
partial view example (adjust to be proper for any particular dropdown selection):
#model namespaceName.QuestionTypeModel
<div class="form-group>
#* put controls appropriate to the particular partial views here, such as radio buttons for the multiple choice question type, etc. *#
<div>
<div class="form-group">
#Html.LabelFor(model => model.TypeID, "TypeID", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("TypeID", Model.QuestionTypeValues)
#Html.ValidationMessageFor(model => model.TypeID)
</div>
</div>
Part of the controller:
[HttpGet]
public ActionResult Index()
{
var model = new MainViewModel();
// populate the model with data here for the initial display, including the initial drop-down values,
// presumably the same way you do now
// into model.QuestionTypeValues
return View(model); // the main view
}
[HttpGet]
public ActionResult PopulateType(int selectedValue) // could use an enum for the selectable values
{
var model = new QuestionViewModel();
string partialViewName = null;
// populate with data appropriate to the partial views
switch (selectedValue)
{
case 0:
partialViewName = "partial view name for item 0";
// populate "model" with the appropriate data
break;
case 1:
partialViewName = "partial view name for item 1";
// populate "model" with the appropriate data
break;
// and so on...
default:
throw new ArgumentException("unknown selected value", "selectedValue");
break;
}
return PartialView(partialViewName, model);
}
The approach to use jQuery to build the DOM elements instead of using partial views is left as an exercise.

How to define Html.BeginForm for action with attribute routing?

Controller
[HttpGet]
[Route("~/search/{clause}/{skip?}")]
public async Task<ActionResult> Search(string clause, int skip = 0)
{
...
}
View
#using (Html.BeginForm("Index", "search", FormMethod.Get))
{
#Html.TextBox("clause", null, new { #class = "form-control col-md-4" })
...
}
Rendered Html
<form action="/search" method="get">
<input id="clause" name="clause" type="text" value="test">
</form>
I am using [HttpGet] partly because i want the search to be accessing via http://myapp.com/search/<search values>
When i navigate to http://myapp.com/search/test, everything seems fine, but when i try to enter my new search term in the textbox and hit enter or submit, it navigates to http://myapp.com/search?clause=newsearch
What should I do so that my textbox will navigate to http://myapp.com/search/newsearch instead?
Your form generates http://myapp.com/search?clause=newsearch because a browser has no knowledge of your routes (c# code running on your server).
In order to generate your preferred url (http://myapp.com/search/newsearch), you need javascript to intercept and cancel the default submit, and build a url to navigate to. Using jQuery:
$('form').submit(function() {
var baseUrl = $(this).attr('action'); // or var baseUrl = '#Url.Action("Index", "search")';
var url = baseUrl + '/' + $('clause').val(); // add value for skip if required
location.href = url; // redirect
return false; // cancel the default submit
});

Razor view engine - How can I add Partial Views

I was wondering what, if it is possible, is the best way to render a partial using the new razor view engine. I understand this is something that wasn't finished completely by the time
Right now I am using RenderPage to render the user control:
#RenderPage("~/Views/Shared/LocaleUserControl.cshtml",ViewData.Model)
The page calling RenderPage uses a layout (master) page with three sections defined: TitleContent, HeadContent and Maincontent. When I attempt to render my locale control from this page it appears that these sections are also required - they should only be required in the calling page and are present. I receive the following message, regardless of whether or not I include the sections in my partial view (obviously I dont want to include these sections but it seemed like an interesting debugging point...).
The following sections have been
defined but have not been rendered on
the layout page
'~/Views/Shared/LocaleUserControl.cshtml':
TitleContent; HeadContent; MainContent
My partial view is as follows (adapted from the following link):
#inherits System.Web.Mvc.WebViewPage<LocaleBaseModel>
#using System.Web.UI;
<p>
#Html.LabelFor(model => Model.CountryName)
<br />
#Html.DropDownListFor(model => Model.CountryName,null, string.Empty, new { #class = "text", accesskey="u"})
</p>
<p>
#Html.LabelFor(model => Model.StateProvince)
<br />
#Html.DropDownListFor(model => Model.StateProvince, null, string.Empty, new { #class = "text", accesskey="t" })
</p>
<script type="text/javascript">
$(function () {
var countries = $("#CountryName");
var statesprovinces = $("#StateProvince");
countries.change(function () {
statesprovinces.find('option').remove();
var url = '#Url.Action("GetStatesProvinces", "Base")';
$.getJSON(url, { countryId: countries.val() }, function (data) {
$(data).each(function () {
$("<option value=" + this.ID + ">" + this.Name + "</option>").appendTo(statesprovinces);
});
});
});
});
</script>
You partial looks much like an editor template so you could include it as such (assuming of course that your partial is placed in the ~/views/controllername/EditorTemplates subfolder):
#Html.EditorFor(model => model.SomePropertyOfTypeLocaleBaseModel)
Or if this is not the case simply:
#Html.Partial("nameOfPartial", Model)
If you don't want to duplicate code, and like me you just want to show stats, in your view model, you could just pass in the models you want to get data from like so:
public class GameViewModel
{
public virtual Ship Ship { get; set; }
public virtual GamePlayer GamePlayer { get; set; }
}
Then, in your controller just run your queries on the respective models, pass them to the view model and return it, example:
GameViewModel PlayerStats = new GameViewModel();
GamePlayer currentPlayer = (from c in db.GamePlayer [more queries]).FirstOrDefault();
[code to check if results]
//pass current player into custom view model
PlayerStats.GamePlayer = currentPlayer;
Like I said, you should only really do this if you want to display stats from the relevant tables, and there's no other part of the CRUD process happening, for security reasons other people have mentioned above.

Categories