In my Razor view (ASP.NET MVC 4), I have two radiobuttons for showing/hiding some fields. When the first radiobutton is selected, these fields are invisible; when the second radiobutton is selected, the fields become visible. This is done by a Javascript function which is bound to the radiobuttons onclick event.
function displayHiddenFields(value) {
if (value == 'true')
$('#myDiv').removeClass('hidden');
else
$('#myDiv').addClass('hidden');
}
I'm using data annotations on the view model to perform validation. My problem is that the invisible fields are also validated. These fields only have to be validated when they are visible. I tried to manipulate the data-val attribute on the input elements but this doesn't work.
$('input1').attr('data-val', value);
How can I solve my problem? Is there a way to disable validation for the fields that are invisible by using client-side Javascript? Otherwise, I have to do a postback in order to render the fields conditionally.
I solved it by adding the following piece of JavaScript to the bottom of my page:
<script type="text/javascript">
$(function () {
var settings = $.data($('form').get(0), 'validator').settings;
settings.ignore = ".hidden";
});
</script>
This way, all the inputs that have the .hidden class applied to it will be ignored in the client-side validation.
<button id="Submit" type="submit">Submit</button>
<script type="text/javascript">
$("#Submit").on("click", function () {
var validator = $("form").data('validator');
validator.settings.ignore = "input[type=hidden]";
});
</script>
I would suggest using jQuery validation. You can conditionally validate your model:
if($("#field").is(":checked")){
//Add some validation here
}else{
//Default validation here
}
if($("form").valid()){
//Do processing
}
The problem will be on the back-end. if you are using data annotations, I would assume you are validating the model in the controller as well; something like 'Model.isValid()' or the like? As long as both your cases (radio button1 click or button2 clicked) always matches what a "valid" model should be, you will be fine. Otherwise, you may have to turn off some of the data annotations. Just from my experience. jQuery Validation Docs
By default (at least in the later versions of the unobtrusive validation) the ignore field is set to ":hidden" (evaluated by jQuery) which is way better than just checking a class="hidden" or type="hidden".
Related
Our credit card processor (Braintree Payments) requires that we not use the "name" attribute on credit card fields (card number, expiration date, and CCV) to obviously make sure they don't get POSTed to the server unencrypted. I found a custom Extension to generate a name-less text box (How to extend html.textboxfor to remove the name attribute?). This works great, since it allows us to generate a text box without the name attribute, but it still adds all the other validation attributes and such automatically. But I have run into a problem.
When I use #Html.NameLessTextBoxFor(model => model.CardNumber) in my view, it correctly generates the text box without a name attribute. We also use Data Annotations in the View Model to generate unobtrusive validation. The visible problem on the actual website is that when there is a validation error with one of these name-less fields, the ValidationMessage span doesn't display any error messages. The name-less field correctly turns red, but the error messages don't display.
I believe I have deduced why this isn't working, but I can't figure out how to fix it. I looked at the generated HTML for the ValidationMessage span, and I see this attribute:
data-valmsg-for="MyViewModel.CardNumber"
That would be correct if my name-less field had the name attribute set like normal. But since I can't set the name attribute, how do I get the ValidationMessage to still work?
Scrub the name attrributes on submit would be something like:
$("form").submit(function () {
$(this.find(":input").removeAttr("name");
});
It's possible that this may be too late in the chain of events though, so you may have to preventDefault and repost the form, something like this:
$("form").submit(function (e) {
if($(this.find(":input[name]").length > 0) {
e.preventDefault();
$(this.find(":input").removeAttr("name");
$(this).trigger("submit");
}
});
Or indeed do as I did and code a callBack into unobtrusive validation to check if validation has passed and at that point remove the name attributes. Here are my notes on adding that callBack:
//Added the following to the onErrors function:
if ($.isFunction(callBackOnError)) {
setTimeout(function () {
callBackOnError();
}, 100);
}
//Then in the exposing declarative section of the plugin
onError: function (callBack) {
callBackOnError = callBack;
}
Have a play with it and see what you find. Keen to know your eventual conclusion, so please do update. Hope this has somewhat helped you.
I'm using bootstrap CSS form styles, When a textbox gets a validation error message, I need to put the class "error" on the containg . How can I do this?
Problem is, all the validations fire on ajax before submitting the form, except for my custom validators which only fire on post. So need to make sure it happens 4 both scenarios.
http://twitter.github.com/bootstrap/base-css.html#forms
Inside the onError function in jquery.validate.unobtrusive, just add the .addClass("error") line like this:
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
container.parents(".field-encapsulator:first").addClass("error");
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
ASP.NET MVC adds the field-validation-error class to the error message element, and input-validation-error to form controls, both on the server-side and client-side via javascript. There's no containing element, depending on your code the form control and its label may or may not be under the same containing element. And, even if they do, MVC will set the mentioned classes to the form control and error message element and not the containing element.
Also, when you autogenerate a form using Html.EditorForModel() the generated markup is like this:
<div class="editor-label"><label for="foo">Foo</label></div>
<div class="editor-field"><input name="foo"/></div>
There's no containing element that could map to the control-group class on Twitter Bootstrap. You could change this template by adding an EditorTemplates/Object.cshtml template.
I'd suggest you adapt Twitter Bootstrap to ASP.NET MVC and not the other way around.
As described in some of the answers at How to add a 'submitHandler' function when using jQuery Unobtrusive Validation?, the settings can be accessed by $("form").data("validator").settings.
And you can then set any valid/invalid class you like:
var settings = $("form").data("validator").settings;
settings.errorClass += " is-invalid";
settings.validClass += " is-valid";
I'm trying to dynamically add checkbox and label elements to the document. Checkbox element has Knockout's data-bind attribute to bind its value to an observable value in the ViewModel. However when I try to style the checkboxes with jQuery Mobile by executing
$('input[type="checkbox"]').checkboxradio();
data-bind attributes will be removed. If I leave out the above line, data-bind attributes are properly set and the binding works.
Is there a way to have both jQuery Mobile styling and Knockout bindings at the same time?
I'm using jQuery Mobile RC1 and Knockout 1.2.1.
I have also encountered this problem. Unfortunately, all the suggestions here either did not work for me or had other issues. So I have created a simple custom binding that works in all versions of KO (including the latest v3):
ko.bindingHandlers.jqmChecked = {
init: ko.bindingHandlers.checked.init,
update: function (element, valueAccessor) {
//KO v3 and previous versions of KO handle this differently
//KO v3 does not use 'update' for 'checked' binding
if (ko.bindingHandlers.checked.update)
ko.bindingHandlers.checked.update.apply(this, arguments); //for KO < v3, delegate the call
else
ko.utils.unwrapObservable(valueAccessor()); //for KO v3, force a subscription to get further updates
if ($(element).data("mobile-checkboxradio")) //calling 'refresh' only if already enhanced by JQM
$(element).checkboxradio('refresh');
}
};
Should be used like this:
<input type="checkbox" data-bind="jqmChecked: someValue" id="checkbox1"/>
See a complete working example here:
http://jsfiddle.net/srgstm/ub6sq/
See: https://gist.github.com/1006808
Then you can do something like the following:
var $checkbox = $('input[type="checkbox"]');
$checkbox.checkboxradio();
$checkbox.dataBind({
your options..
});
Hope this'll help!
There is a problem with using knockouts default checked binding with styled objects like jQuery mobile does. It has the same issues that jQueryUi's Button/Buttonset functions. There is a label over the checkbox that indicates what is happening and it doesn't get updated properly via standard knockout checked binding.
It is discussed at http://therunningprogrammer.blogspot.com/2011/10/how-to-use-jquery-uis-button-with.html.
To use knockout directly with these styled objects from jQuery Mobile, the demonstrated code will have to be modified to handle the different DOM context. I'll post an update to the code when I can get some free time to do it.
EDIT
In Google Groups - Knockout, luv2hike posted a solution. You can see it working at http://jsfiddle.net/luv2hike/nrJBC/. Looks like a working fix for your problem.
I created a simple binding that works with jQuery Mobile 1.2.0 and Knockout 2.2.1 and works with default jQuery mobile checkboxes. This binding has no dependency on custom icons or JQuery Mobile's CSS styles. It also allows the use of regular checkbox markup in your HTML (<input type="checkbox" ... />) as opposed to using an alternate markup element like a div.
Here's the fiddle: http://jsfiddle.net/thedude458/52baX/
Note: Presently, the example only supports a single checkbox, not a list, as that is all I currently have a need for. It also assumes that the bound property is an observable.
Here is my heavily commented code on a custom handler I built for jQueryMobile checkboxes:
ko.bindingHandlers.checkbox = {
init: function(element, valueAccessor) {
// set the dom element to a checkbox and initialize it (for jquerymobile)
var checkbox = $(element);
checkbox.checkboxradio();
checkbox.attr('type', 'checkbox');
// register change event to update the model on changes to the dom
ko.utils.registerEventHandler(element, "change", function() {
valueAccessor()(
// off because it is before the ui has refreshed
$(this).siblings('label.ui-checkbox-off').length > 0
);
});
},
update: function(element, valueAccessor) {
// update the checked binding, i.e., check or uncheck the checkbox
ko.bindingHandlers.checked.update(element, valueAccessor)
// and refresh the element (for jquerymobile)
var checkbox = $(element);
checkbox.checkboxradio('refresh')
}
};
I'm running into a problem where I have a simple add/edit form and using client-side validation (jQuery/MicrosoftMvcJQueryValidation.js) which is generated from data annotations and enabled client side by calling the following in my view:
<% Html.EnableClientValidation(); %>
This seems to work fine for most elements, however I have an instance where I have a boolean property which is rendered as a checkbox using:
<%= Html.EditorFor(model => model.Chargeable)%>
Which can be either true/false (ticked/unticked).
As the bool is a value type, and not nullable, it is being rendered as a required property and displays an error (client side) when the form is submitted reading "The Chargeable field is required.", however, as the HTML that is generated is two part (both checkbox and hidden value) it will pass the post back validation.
After browsing the MVC 2 source code, I've managed to put a "quick and dirty" fix in for the moment, which is to set:
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Any one else got any ideas or suggestions on how I can get around this?
IMO, I dont think MVC should be setting the client-side required validator for checkboxes rendered using the Html.EditorFor/Html.CheckBox(For) methods.
Note: I'm using the ASP.NET MVC 2 RC2 and the MicrosoftMvcJQueryValidation.js from the matching MVC Futures release.
I suppose the easiest way of handling it is to call the rules("remove", [rules]) function on the elements (mainly checkboxes) that I want to remove the client-side validation from:
<script type="text/javascript">
$(document).ready(function() {
$('#Chargeable').rules('remove', 'required');
});
</script>
I'm new to ASP.NET MVC, but I need to perform a search for articles that match a selected category. The results of this query need to be written into a "search results" div overlay with DHTML- jquery, probably.
So, I need the results of an Action, but not to render a view. I was thinking I could use Json and then iterate over the resulting records, somehow.
Or is it easier to use RenderPartial... but how would I use this in this DHTML scenario?
Thanks.
I like the way Steve Sanderson describes in his ASP.NET MVC book. It dosnt work with JSON, but returns a partial. This makes it easier to have both: An Ajax and a non-Ajax version.
The cotroller returns a View or Partial depending on the type of request:
public ActionResult GetArticles(string category)
{
...
if(Request.IsAjaxRequest())
{
return PartialView("ArticleListPartial",articleModel)
}
else
{
return View("ArticleListPage",articleModel)
}
}
The search by default submits the from with with a Non-Ajax post:
<form id="articleSearch" method ="post" action="/Article/GetArticles" >
...
<input type="submit" value="Get the articles!" />
<form>
Then there is a Jquery snippet that kicks in when Javascript is available and submits the request via Ajax
<script language="javascript" >
$(function() {
$("#articleSearch").submit(function() {
$.post($(this).attr("action"), $(this).serialize(), function(modelResponse) {
("#articleResultContainer").html(modelResponse);
});
return false;
});
});
</script>
Hmmm, sounds like you are trying to do a filter?
If this is the case I think it's a bad idea trying to search within your html. I think a better approach would be to post back using jQuery, get your result set from whatever database you are using, and return that back to the view as apartial view.
When you are searching your database you should apply the filter at that point using sql, Linq2Sql or whatever you're using.
If you are still Hell bent on searching the HTML then I'd give each relevant div a class name of say class="DivSearchable". Then in jQuery you can do something like;
$('.DivSearchable").each(function() {
var text = $(this).val();
"Now test text for contents of your seach string"
if (BoolIfFound == true)
$(this).addClass("highlightClassName");
});
highlightClassName would set the background-color to something so you can see which divs contains the search string.
make sense?