I have a simple view-model with a few required attributes... I want each input to highlight red if the corresponding property is not valid, but I don't want this highlighting to display when the page is initially loaded... only when a value changes or when the user tries to save / continue...
Right now it's validating the view-model on initial load because I'm specifying data-bind="css: { error: name.isValid() == false }", but I don't know of any other way to get this to work dynamically (similar to how jQuery unobtrusive validation works)...
var foo = { name: ko.observable().extend({required: true}) };
<div data-bind="css: { error: !name.isValid() }">
<input type="text" data-bind="value: name" />
</div>
Any ideas on how to make this work would be appreciated... Thanks!
A better approach is to configure knockout validation to decorate the element with the validationElement class. This is done by adding this configuration option:
ko.validation.configure({ decorateElement: true });
Click here to see a jsfiddle demonstrating this.
****EDIT, IN RESPONSE TO COMMENT FROM QUESTION ASKER***
If you need to decorate the parent element, a more elegant and reusable solution is to apply this custom binding to the parent element.
Javascript
ko.bindingHandlers.parentvalElement = {
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var valueIsValid = valueAccessor().isValid();
if(!valueIsValid && viewModel.isAnyMessageShown()) {
$(element).addClass("parentError");
}
else {
$(element).removeClass("parentError");
}
}
};
And apply the binding in your HTML like so:
<form data-bind='submit:OnSubmit'>
<label data-bind='parentvalElement:name'>
<span>Name</span>
<input data-bind="value: name" />
</label>
<input type='submit' value='submit' />
<form>
Take a look at this updated jsfiddle to see it in action.
So, here is the solution I came up with:
var Foo = function()
{
this.name = ko.observable().extend({required: true}).isModified(false);
this.validate: function()
{
if (!this.isValid())
{
//... loop through all validated properties and set .isModified(true)
return false;
}
return true;
};
ko.validation.group(foo);
};
var Bar = function()
{
this.foo = new Foo();
this.errors = ko.observableArray([]); //<-- displays errors for entire page
this.save = function()
{
if (!this.foo.validate())
{
this.errors(ko.toJS(this.foo.errors()));
}
};
}
ko.applyBindings(new Bar());
And here is the markup...
<div data-bind="with: foo">
<div class="control-group"
data-bind="css: { error: name.isModified() && !name.isValid() }">
<label class="control-label">Name<span class="help-inline">*</span></label>
<div class="controls">
<input type="text" class="input-block-level" placeholder="Name"
data-bind="value: name, event: { blur: function () { name.isModified(true); }}" />
</div>
</div>
<div class="alert alert-error"
data-bind="visible: $parent.errors().length > 0">
<h5>Errors!</h5>
<ul data-bind="foreach: $parent.errors()">
<li data-bind="text: $data"></li>
</ul>
</div>
</div>
<button type="submit" class="btn btn-primary" data-bind="click: save">Save</button>
and here is the CSS
.error { color: Red; font-weight: bold; }
.help-inline { display: none; }
.error .help-inline { display: inline-block; }
.error input { border-color: Red; }
Related
As soon as the Excel file is uploaded and clicked on Submit button, the data in the Excel file will be populated as shown in the below screenshot. Some checkboxes will be selected while some others are not, based on the conditions written in the program. Till here everything is working fine.
End user selects/un-selects checkboxes, and clicks on Process Hold Reasons button. Now, I want updated model with modified checkboxes values. I'm not even understanding how and where to write the code to achieve this. Tried number of ways, but unable to succeed.
Can someone please suggest me on this!
Below is the code in Index.cshtml page.
#model SupportTool.Models.ViewModels.EligibilityIssuesViewModel
#{
ViewData["Title"] = "Eligiblity Issues";
}
<style>
.Success {
font-weight: bold;
color: green;
font-size: 15px;
}
.Error {
font-weight: bold;
color: red;
font-size: 15px;
}
td {
height: 20px;
}
</style>
<br />
<br />
<div>
<span class="Success">#ViewBag.Success</span>
<span class="Error">#ViewBag.Error</span>
</div>
<form asp-controller="EligibilityIssues" asp-action="Index" method="post" class="form-horizontal" role="form" enctype="multipart/form-data">
<div class="form-group">
<div class="row">
<div class="alert-danger" asp-validation-summary="ModelOnly"></div>
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<p>Upload Excel file:</p>
<div class="custom-file">
<input asp-for="ExportedExcelFile" class="form-control custom-file-input" />
<label class="custom-file-label">Choose file...</label>
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Submit" class="btn-success" />
</div>
</div>
</div>
#section Scripts {
<script>
$(function () {
$('.custom-file-input').on('change', function () {
var fileName = $(this).val().split('\\').pop();
$(this).next('.custom-file-label').html(fileName);
});
});
</script>
}
#if (Model != null && Model.HoldReasons != null)
{
<h1>Eligibility issues should be shown here</h1>
<table>
<thead>
<tr>
<th> </th>
<th>Hold Reasons</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.HoldReasons.Count; i++)
{
<tr>
<td>
#Html.CheckBox("holdReason[" + i + "].HoldReasonShouldBeChecked", Model.HoldReasons[i].HoldReasonShouldBeChecked)
#if (!Model.HoldReasons[i].HoldReasonShouldBeChecked)
{
<span style="border: 1px solid red">
(#Model.HoldReasons[i].StateName)#Model.HoldReasons[i].HoldReason
</span>
}
else
{
<span>(#Model.HoldReasons[i].StateName)#Model.HoldReasons[i].HoldReason</span>
}
#Html.Hidden("holdReason[" + i + "].WorkOrderId", Model.HoldReasons[i].WorkOrderId)
</td>
</tr>
}
</tbody>
</table>
<input type="submit" asp-action="ProcessHoldReasons" value="Process Hold Reasons" class="btn btn-primary" />
}
</form>
Below is the Code in HomeController
namespace SupportTool.Controllers
{
public class EligibilityIssuesController : Controller
{
private readonly IEligibilityIssuesBLL _bll;
private readonly IWebHostEnvironment _hostEnvironment;
public EligibilityIssuesController(IEligibilityIssuesBLL bll, IWebHostEnvironment hostEnvironment)
{
_bll = bll ?? throw new ArgumentNullException(nameof(bll));
_hostEnvironment = hostEnvironment ?? throw new ArgumentNullException(nameof(hostEnvironment));
}
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(EligibilityIssuesViewModel model)
{
try
{
if (ModelState.IsValid)
{
if (model.ExportedExcelFile != null)
{
var folder = Path.Combine(_hostEnvironment.WebRootPath, "uploaded_excel_files");
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
var incomingFileName = model.ExportedExcelFile.FileName;
model.UploadedExcelFileName = Path.Combine(folder, incomingFileName);
using (var fileStream = new FileStream(model.UploadedExcelFileName, FileMode.Create))
{
model.ExportedExcelFile.CopyTo(fileStream);
}
model.HoldReasons = _bll.GetHoldReasons(model);
}
return View(model);
}
return View(model);
}
catch (Exception ex)
{
ViewBag.Error = new HtmlString(#"Unexpected error occurred. Below is the message for your verification:<br />"
+ ex.Message);
return View(model);
}
}
}
}
I'm new to vueJS.
I want to add a required validator in image using vee-validate.
Built-in required validador isn't working so I created a custom validator img_required.
here's what I've done so far.
.vue html part
<ValidationProvider rules="image|img_required" bail="false" v-slot="{ errors, validate }">
<div class="row row-xs mg-t-20 mx-0">
<label class="col-sm-4 form-control-label">
<span class="tx-danger">*</span> Image:
</label>
<div
#dragover.prevent
#change="validate"
#drop.prevent
class="file-wrapper col-sm-8 mg-t-10 mg-sm-t-0"
>
<div v-if="imgUrl">
<button #click="imageNull" class="img-close">
<b-icon icon="x"></b-icon>
</button>
<img style="height: 127px" :src="imgUrl" />
</div>
<input type="text" hidden v-model="imgUrl" />
<div v-if="!imgUrl" #drop="handleImage($event, 'drop')">
<input
type="file"
class="form-control"
name="file"
accept="image/*"
#change="handleImage($event, 'input'); validate()"
/>
Drop image
</div>
</div>
</div>
<div v-for="error in errors" :key="error">{{ error }}</div>
</ValidationProvider>
I can't use v-model in input type file so I created a dummy hidden input field and passed imgUrl in v-model <input type="text" hidden v-model="imgUrl" />
imgUrl gets image src from file drop or input file.
I added a close button to nullify imgUrl variable.
<button #click="imageNull" class="img-close">
<b-icon icon="x"></b-icon>
</button>
I pass this imgUrl to vee-validate extend method.
.vue script part
data() {
return {
imgUrl: ""
}
},
methods: {
handleImage(e, action) {
var file;
if (action == "input") file = e.target.files[0];
else if (action == "drop") file = e.dataTransfer.files[0];
var reader = new FileReader();
reader.onload = (e) => {
this.imgUrl = e.target.result;
};
reader.readAsDataURL(file);
},
imageNull() {
this.imgUrl = "";
},
}
here's validation.js file
extend('img_required', {
validate(imgUrl) {
console.log(imgUrl);
return imgUrl !== "";
},
message() {
return "Image is required!";
}
});
Here I'm checking if imgUrl is an empty base64 string or not.
And when I hit close button, imgUrl nullifies.
The issue here is when I print this imgUrl it shows event.target.files.
I'm new to vue.js. Please tell me if I'm doing something wrong
I think the problem is that you're handleImage function is not correct
Try this;
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
this.imgUrl = reader.result;
};
Hello im trying to post my blog comments the function works. but the whole site refreshes inside the div, i tried playing around with the partialview in the controller but im not sure what to do can anybody here point me in the right directtion, i want div to refresh with ajax request not the whole site intro the div.
<!-- Blog Comments -->
<!-- Comments Form -->
<div class="well">
<h4>Leave a Comment:</h4>
#if (Members.GetCurrentLoginStatus().IsLoggedIn)
{
using (Html.BeginUmbracoForm("CreateComment", "CommentSurface", FormMethod.Post, new { #id = "comment-form" }))
{
// use this where every display profile image is needed
var user = User.Identity.Name;
var imgUrl = Url.Content("~/media/profileimage/" + user.Replace(".", "") + ".png");
<input name="CommentOwner" type="text" value="#Members.GetCurrentMember().Name" class="form-control hidden" readonly="readonly" />
<input name="ownerid" type="text" value="#Members.GetCurrentMember().Id" class="form-control hidden" readonly="readonly" />
<div class="form-group">
<textarea name="Message" rows="3" placeholder="Type your message here" class="form-control"></textarea>
</div>
<input name="profileimage" type="text" value="#imgUrl" class="hidden" readonly="readonly" />
<button type="submit" class="btn btn-primary">Submit</button>
}
}
else
{
<p> You are not logged in Register here</p>
}
</div>
<hr>
<!-- Posted Comments -->
<div class="blog-comments">
#Html.Partial("_BlogComments")
</div>
<!-- Comment -->
#section scripts {
<script>
$(function () {
// Find the form with id='well-form'
$('#comment-form').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (data) {
$(".blog-comments").html(data);
},
error: function (result) {
alert('Comment was not successful!');
}
});
// return false to cancel the form post
// since javascript will perform it with ajax
return false;
});
});
</script>
}
</div>
SurfaceController:
public class CommentSurfaceController : SurfaceController
{
[HttpPost, ValidateInput(false)]
public ActionResult CreateComment(CommentViewModel model)
//public PartialViewResult CreateComment(CommentViewModel model)
{
if (!ModelState.IsValid)
{
return CurrentUmbracoPage();
}
var contentService = Services.ContentService;
var newContent = contentService.CreateContent(DateTime.Now.ToShortDateString() + " " + model.CommentOwner, UmbracoContext.PageId.Value, "BlogComment");
newContent.SetValue("CommentOwner", model.CommentOwner);
newContent.SetValue("Message", model.Message);
newContent.SetValue("profileimage", model.profileimage);
newContent.SetValue("ownerid", model.ownerid);
//Change .Save if u want to allow the content before publish
contentService.SaveAndPublishWithStatus(newContent);
return RedirectToCurrentUmbracoPage();
//return PartialView("BlogComments", model);
}
public ActionResult DeleteComment(int commentid)
{
var service = ApplicationContext.Current.Services.ContentService;
var content = service.GetById(commentid);
service.Delete(content);
return RedirectToCurrentUmbracoPage();
}
}
Partial View:
#foreach (var item in Model.Content.Children().OrderByDescending(m => m.CreateDate))
{
<div class="media">
<a class="pull-left" href="#">
<img class="media-object" width="64" src="#item.GetPropertyValue("profileimage")" alt="profile image">
</a>
<div class="media-body">
<h4 class="media-heading">
#item.GetPropertyValue("CommentOwner")
<small>#item.CreateDate</small>
</h4>
#item.GetPropertyValue("Message")
</div>
#item.Id
</div>
if (Members.GetCurrentLoginStatus().IsLoggedIn)
{
if (#Members.GetCurrentMember().Id.ToString() == item.GetPropertyValue("ownerid").ToString())
{
#Html.ActionLink("Delete", "DeleteComment", "CommentSurface", new { commentid = item.Id }, null)
}
else
{
#*<p> not ur comment</p>*#
}
}
else
{
//blank cant delete comment if not logged in
}
}
The problem is that UmbracoSurfaceController is loosing his context if you are not rendering the complete page.
If you work with ajax, you should not render out html and post this back. Only POST the data and update your layout in javascript when you get a 200 (ok) back from the server.
To do so, use the UmbracoApiController. This is a WebApi controller allowing you to send back json (or xml) serialized data.
More information about the UmbracoApiController can be found in the documentation.
I have a Kendo Datepicker that worked perfectly on a div while I was beginning development of a page.
After I got everything all set and working the way it was supposed, I moved the datepicker to a Durandal Modal as was the requirement. The modal works fine, and other databinding is working on the modal, but not the datepicker.
I have tried loading the datepicker at various times in the Durandal lifecycle such as activate, compositionComplete and attached, as well as changing the Z Index to 20000. I am not quite user what I might be missing.
Here is the latest pertinent code:
define([
'durandal/app',
'plugins/router',
'plugins/dialog',
'services/datacontext',
'services/dialogs',
'viewmodels/helpers/vc',
'services/logger',
'services/settings'
],
function (app, router, dialog, datacontext, dialogs, vc, logger, settings) {
var featureSetToEdit;
var startFeaturesDatePicker = null;
var endFeaturesDatePicker = null;
var today = new Date();
var featList = ko.observableArray(['']);
var saving = ko.observable(false);
var isUserInReadOnlyRole = ko.observable(true);
function attached() {
loadDatePickers();
};
function compositionComplete() {
isUserInReadOnlyRole(vc.isUserReadOnly(datacontext.userRole));
};
function loadDatePickers() {
startFeaturesDatePicker = $("#startDateFeatureSet").kendoDatePicker({
value: today,
format: 'dd-MMM-yyyy',
change: setStartDate,
}).data('kendoDatePicker');
endFeaturesDatePicker = $("#endDateFeatureSet").kendoDatePicker({
value: today,
format: 'dd-MMM-yyyy',
change: setEndDate,
}).data('kendoDatePicker');
};
var setStartDate = function () {
startFeaturesDatePicker.value($("#startDateFeatureSet").val());
};
var setEndDate = function () {
endFeaturesDatePicker.value($("#endDateFeatureSet").val());
};
function checkboxDivId(featuresKey) {
return 'checkboxDivId' + featuresKey;
};
function edit(featureSetToEdit, fList) {
self = this;
self.featList(fList);
return dialog.show(self);
};
function save() {
};
function cancel() {
dialogs.confirmYesNo('Discard changes to this feature Set?', 'Confirm cancel',
function () {
dialog.close(self, false);
},
function () {
return;
}
);
};
// Definition of viewmodel (list of exposed properties and methods)
var vm = {
featList: featList,
edit: edit,
save: save,
saving: saving,
cancel: cancel,
isUserInReadOnlyRole: isUserInReadOnlyRole,
checkboxDivId: checkboxDivId
};
return vm;
});
HTML
<div class="messageBox autoclose" style="min-height: 330px" >
<div class="modal-header">
<h3>Edit Feature Set</h3>
</div>
<div class="modal-body" style="padding: 2px 5px 2px 5px; background-color: #ddd; min-height: 250px; width: 400px; border: 1px solid silver;">
<table class="k-grid">
<tr class="dataRow" style="padding: 2px;">
<td><span>Start Date</span></td>
<td><input id="startDateFeatureSet" style="width:150px;" class="highZIndex" /></td>
</tr>
<tr class="dataRow" style="padding: 2px;">
<td><span>End Date</span></td>
<td><input id="endDateFeatureSet" style="width:150px;" class="highZIndex" /></td>
</tr>
<tr class="dataRow" style="padding: 2px;">
<td><span>Features</span></td>
<td id="featuresCheckbox" style="font-size: 10pt; text-align: left" data-bind="foreach: featList">
<input data-bind="attr: { id: $parent.checkboxDivId($data.keyChar), value: $data.keyChar }" type="checkbox" style="margin-bottom:6px;" /> <span data-bind="text: $data.name" style="margin-top:6px;"></span> <br />
</td>
</tr>
</table>
</div>
<div class="modal-footer">
<div style="float: right">
<span class="icon-spin icon-spinner waiting" data-bind="visible: saving"> </span>
<button class="btn btn-primary" data-bind="click: save, enable: !saving() && !isUserInReadOnlyRole()">Save</button>
<button class="btn btn-default" data-bind="click: cancel, enable: !saving()">Cancel</button>
</div>
</div>
</div>
Can you please take a look and let me know what I might be missing?
So after finding I still needed to load it through the usual Kendo initialization, I searched more until I found that to load it properly I needed the following code in the modal js page:
self = this;
self.compositionComplete = function () {
loadDatePickers();
};
return dialog.show(self);
Now it works exactly the same as a datepicker on a non-modal page.
I hope this helps others to!
I'm using html5/Razor/MVC3 leveraging the Bootstrap template from Twitter. I want to have form validation that looks slick like they've documented (http://twitter.github.com/bootstrap/#forms). So if we take a look at how the standard boiler-plate MVC3 for account registration, the markup would look like:
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class="form-stacked" })) {
#Html.ValidationSummary(true, "Snap! Something went wrong")
<div>
<fieldset>
<legend>Account Information</legend>
<div class="clearfix error">
#Html.LabelFor(m => m.UserName)
<div class="input">
#Html.TextBoxFor(m => m.UserName)
<span class="help-inline">#Html.ValidationMessageFor(m => m.UserName)</span>
</div>
</div>
<div class="clearfix">
#Html.LabelFor(m => m.Email)
<div class="input">
#Html.TextBoxFor(m => m.Email)
<span class="help-inline">#Html.ValidationMessageFor(m => m.Email)</span>
</div>
</div>
<div class="clearfix">
#Html.LabelFor(m => m.Password)
<div class="input">
#Html.PasswordFor(m => m.Password)
<span class="help-inline">#Html.ValidationMessageFor(m => m.Password)</span>
</div>
</div>
<div class="clearfix">
#Html.LabelFor(m => m.ConfirmPassword)
<div class="input">
#Html.PasswordFor(m => m.ConfirmPassword)
<span class="help-inline">#Html.ValidationMessageFor(m => m.ConfirmPassword)</span>
</div>
</div>
</fieldset>
<div class="actions">
<button class="btn large primary" type="submit">Register</button>
</div>
</div>
What I want to do is have the container div inject the "error" class like I've hard-coded in the first input. (So upon entering the page, the div would have a class of "clearfix" but if that input block failed validation, it would tag it as "clearfix error"). I figure I'm going to have to update the div block to include an id of some sort and perhaps add a new data- attribute to the ValidationMessage. I don't have a problem extending the ValidationMessageFor helper. I'm just not 100% sure what the approach should be for extending the library that's there. Any suggestions on how to approach this?
TIA.
UPDATE:
I am thinking this approach is reasonable:
<div id="UserNameContainer" class="clearfix error">
#Html.LabelFor(m => m.UserName)
<div class="input">
#Html.TextBoxFor(m => m.UserName)
<span class="help-inline">#Html.ValidationMessageFor(m => m.UserName, null, new { #data_container = "UserNameContainer" })</span>
</div>
</div>
By decorating my validation message with a data-container name, I could then target the container div. Now I just need to figure out how to intercept the validation message.
The $.validator.setDefaults method solved this issue for me with Bootstrap from Twitter. I'm usingjquery.validate.js and jquery.validate.unobtrusive.js.
Since unobtrusive validation on DOM ready scans your document and caches unobtrusive validation options for each form it encounters, it is needed to call the $.validator.setDefaults method before document scan occurs.
// setup defaults for $.validator outside domReady handler
$.validator.setDefaults({
highlight: function (element) {
$(element).closest(".clearfix").addClass("error");
},
unhighlight: function (element) {
$(element).closest(".clearfix").removeClass("error");
}
});
$(document).ready(function() {
// do other stuff
});
Came accross the same issue. I am tackling it by adding and extesion to the HtmlHelper Class.
This is what I did for the ValidationSummary:
public static class TwitterBootstrapHelperExtensions
{
public static MvcHtmlString BootstrapValidationSummary(this HtmlHelper helper,
bool excludePropertyErrors,
string message)
{
if(helper.ViewData.ModelState.Values.All(v => v.Errors.Count == 0)) return new MvcHtmlString(string.Empty);
string errorsList = "<ul>";
foreach (var error in helper.ViewData.ModelState.Values.Where(v => v.Errors.Count >0))
{
errorsList += string.Format("<li>{0}</li>", error.Errors.First().ErrorMessage);
}
errorsList += "</ul>";
return new MvcHtmlString(string.Format("<div class=\"alert-message error\"><span>{0}</span>{1}</div>",message,errorsList));
}
}
And in the .cshtml file I replace Html.ValidationSummary with this:
#Html.BootstrapValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.")
Remember to add the namespance of your extension class in the views folder web.config file.
I will post here later if I tackle the individual input item before you.
HTH
Rather than reinventing this particular wheel, check the validationEngine plugin available at http://www.position-absolute.com/articles/jquery-form-validator-because-form-validation-is-a-mess/.
You can customize the popup elements as you want, and it is trivial to connect to jQuery.validate.js.
I prefere to change the CSS of bootstrap.
Just added the classes of jQuery validate in the right place.
field-validation-error and input-validation-error
form .clearfix.error > label, form .clearfix.error .help-block, form .clearfix.error .help-inline, .field-validation-error {
color: #b94a48;
}
form .clearfix.error input, form .clearfix.error textarea, .input-validation-error {
color: #b94a48;
border-color: #ee5f5b;
}
form .clearfix.error input:focus, form .clearfix.error textarea:focus, .input-validation-error:focus {
border-color: #e9322d;
-webkit-box-shadow: 0 0 6px #f8b9b7;
-moz-box-shadow: 0 0 6px #f8b9b7;
box-shadow: 0 0 6px #f8b9b7;
}
You can integrate MVC3 validation with Bootstrap framework by adding the following javascript to your page (View)
<script>
$(document).ready(function () {
/* Bootstrap Fix */
$.validator.setDefaults({
highlight: function (element) {
$(element).closest("div.control-group").addClass("error");
},
unhighlight: function (element) {
$(element).closest("div.control-group").removeClass("error");
}
});
var current_div;
$(".editor-label, .editor-field").each(function () {
var $this = $(this);
if ($this.hasClass("editor-label")) {
current_div = $('<div class="control-group"></div>').insertBefore(this);
}
current_div.append(this);
});
$(".editor-label").each(function () {
$(this).contents().unwrap();
});
$(".editor-field").each(function () {
$(this).addClass("controls");
$(this).removeClass("editor-field");
});
$("label").each(function () {
$(this).addClass("control-label");
});
$("span.field-validation-valid, span.field-validation-error").each(function () {
$(this).addClass("help-inline");
});
$("form").each(function () {
$(this).addClass("form-horizontal");
$(this).find("div.control-group").each(function () {
if ($(this).find("span.field-validation-error").length > 0) {
$(this).addClass("error");
}
});
});
});
</script>
Besides, on the Views (for example "Create.cshtml") make sure that the fields in the form are formatted as the following...
<div class="editor-label">
#Html.LabelFor(Function(model) model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(Function(model) model.Name)
#Html.ValidationMessageFor(Function(model) model.Name)
</div>
With this solution, it will most likely be enough to just add a javascript without edit the View.
What I've done is taken the css classes for the validation errors and created a new css file with the same classes but with bootstrap values.
You can find it in a nuget package at: http://nuget.org/List/Packages/MahApps.Twitter.Bootstrap
That also provides some scaffolding templates to autocreate new views.
I needed to solve this using Bootstrap 3.1 and Razor. This is what I used:
$.validator.setDefaults({
highlight: function (element) {
$(element).parents(".form-group").addClass("has-error");
},
unhighlight: function (element) {
$(element).parents(".form-group").removeClass("has-error");
}
});
$(function () {
$('span.field-validation-valid, span.field-validation-error').each(function () {
$(this).addClass('help-block');
});
$('form').submit(function () {
if ($(this).valid()) {
$(this).find('div.form-group').each(function () {
if ($(this).find('span.field-validation-error').length == 0) {
$(this).removeClass('has-error');
}
});
}
else {
$(this).find('div.form-group').each(function () {
if ($(this).find('span.field-validation-error').length > 0) {
$(this).addClass('has-error');
}
});
}
});
$('form').each(function () {
$(this).find('div.form-group').each(function () {
if ($(this).find('span.field-validation-error').length > 0) {
$(this).addClass('has-error');
}
});
});
});
This is a combination of #german's answer and help from this post by "theBraindonor". Updated to use new Bootstrap 3 classes.