I am implementing knockout validation for my form, and I want to make a field required only if it is showing. Depending on the selection of other fields in the form, some controls may be hidden by visibility:hidden or display:none. How can I make these fields required only if shown? I have tried this
var name = ko.observable().extend({
required: {
onlyIf: function () {
return ($('#name').is(':visible'));
},
message: '*** Required'
}
});
But it doesn't seem to work, and I'm not sure if it should (can you write custom logic like that in knockout onlyIf params?).
Thanks for any help.
As mentioned in comments all you need to do is
Declare a observable in ViewModel per say self.nameVisible=ko.observbale() set the value it True/False from anywhere (either from DB or based on other control selection) . Later on you should use the self.nameVisible() in your validations i.e with .extend & onlyIf combo to make things(hide/show element+dynamic conditional validation) work .
Html:
<input type="text" data-bind="value:name,visible:nameVisible"/>
viewModel:
var ViewModel = function () {
var self = this;
self.nameVisible = ko.observable(true); //Set it dynamically
self.name = ko.observable().extend({
required: {
message: '*** Required',
onlyIf: self.nameVisible
}
});
};
ko.applyBindings(new viewModel());
Related
I am using the jQuery Validate plugin for a ajax form.
To validate each field I have used data-rule-required="true".
Now I have four fields (read as 4 credit card fields). Now for all those fields separate am getting required error.
I want to combine their values and send throw a single error attached to the one erroneous field.
I have tried the following:
form3_validation.showErrors({
"field_name1": "This is error"
});
But it is throwing an error for every field even if they are valid. I want to target only that field.
First, remove data-rule-required="true" from these fields.
The way this is normally handled is with the require_from_group method. This method allows you to treat several fields as one. Combine it with the groups option to get one single message for all fields in this group.
$(document).ready(function() {
$('#myform').validate({
groups: {
creditcard: "foo1 foo2 foo3 foo4"
},
rules: {
// some other rules here
},
errorPlacement: function(error, element) {
error.insertBefore(element);
}
});
var myGroup = $('.mygroup');
myGroup.each(function() {
$(this).rules('add', {
require_from_group: [4, myGroup],
messages: {
require_from_group: "credit card number required"
}
});
});
});
All four fields share a class name called mygroup that is used to
identify these.
The require_from_group method is part of the
additional-methods.js file, so don't forget to include this
too.
I used the .rules() method simply to avoid having to define the
same rule four separate times within the rules object of the
.validate() method.
DEMO: jsfiddle.net/9sxt9u1a/
The above answers your question as per your client's requirements. However, the additional-methods.js file already contains several ready-to-use rules for credit card fields. It would be cleaner and easier to implement than having four boxes of numbers in a grouping.
Update: OP clarified that the user was about the jQuery Validate plugin, not generic data-validation in JS. Leaving this answer up because it is not totally relevant but may still be helpful to someone.
You can add an identified for every field (e.g., data-attribute data-field-id), and then go through each of the input fields and report an error if one is empty.
This will go through each input box and report specifically which one is the problem, because they are all marked by identifiers.
var fields = $(".field");
$("button[type=submit]").click(function() {
var error = false;
fields.each(function() {
if(error) {
return;
}
if($(this).val() === "") {
error = "Error: required field " + $(this).data("field-id") + " is blank.";
}
});
if(error) {
alert(error);
} else {
alert("All good!");
}
});
.field {
width: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input class="field" data-field-id="1" type="number">-
<input class="field" data-field-id="2" type="number">-
<input class="field" data-field-id="3" type="number">-
<input class="field" data-field-id="4" type="number">
<button type="submit">Submit</button>
I have model in a page that is bound to several controls. Based on some condition some of these controls will be visible or invisible. And on the final submit I should only validate those which are visible.
The following is a sample code to explain my requirement
<script src="knockout-3.4.0.js" type="text/javascript"></script>
<input type="checkbox" data-bind="checked:requireAge" >Age Required</input><br />
Name : <input data-bind="value:Name" /><br />
<div data-bind="visible:requireAge">
Age: <input data-bind="value:Age,visible:requireAge" />
</div>
<button type="button" onclick="validateModel();">Validate</button>
<script type="text/javascript">
var viewModel = { Name: ko.observable(), Age: ko.observable(),requireAge:ko.observable(false) };
ko.applyBindings(viewModel);
function validateModel() {
//validate visible properties and throw a common message that all visible fields should be filled
}
</script>
My suggestion is to use the knockout-validation library (you made no mention of it in your question so I assume you're not using it already) It ties in seamlessly with knockout and makes validation far more convenient. I've used it extensively over the past year and its make my life a whole lot easier. No need to create computeds to keep track of whether an observable contains a valid value or not. You can find the knockout-validation library on github.
In your case you can simply do the following:
var viewModel = function(){
var self = this;
self.name = ko.observable();
self.requireAge = ko.observable(false);
self.age = ko.observable().extend({
required: {
onlyIf: function() { return self.requireAge(); }
}
});
};
Validation error messages are inserted automatically below the element the observable is bound to. You can also create your own validation rules but there are many that work straight out the box including the one demonstrated above. You can even use some data attributes for some rules. This is probably the best way to go about validation in conjunction with knockout.
Based on some condition some of these controls will be visible or invisible.
It would be better if these conditions are contained in the model. And validation method too.
See snippet:
var viewModel = function() {
this.Name = ko.observable("");
this.Age = ko.observable("");
this.requireAge = ko.observable(false);
this.isValid = ko.computed(function() {
if (ko.unwrap(this.Name).length === 0) return false;
if (ko.unwrap(this.requireAge) &&
ko.unwrap(this.Age).length === 0) return false;
return true;
}, this);
};
window.onload = function() {
ko.applyBindings(new viewModel());
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="checkbox" data-bind="checked:requireAge" >Age Required</input><br />
Name : <input data-bind="value:Name" /><br />
<div data-bind="visible:requireAge">
Age: <input data-bind="value:Age,visible:requireAge" />
</div>
<div>is valid: <span data-bind="text: isValid"></span></div>
Sorry for keep asking this, but I just can't figure it out. I've reduced the question to just the bare minimum.
How can I validate a dynamically generated form? Below is my attempt, but as seen, it shows up as passing validation.
https://jsfiddle.net/j2pgobze/1/
<form id="myForm">
<input type="text" name="email" id="email" value="bademail" >
</form>
<button id="validate">validate</button>
var myValidateObj = {
rules: {
email: {
email: true
}
}
};
$(function () {
jQuery.validator.setDefaults({
debug: true,
success: "valid"
});
$('#validate').click(function () {
//Validate the traditional form
var validate1 = $('#myForm').validate(myValidateObj);
console.log('Option 1', $('#myForm'), $('#email'), $('#email').val(), validate1.element('#email'), $('#email').valid(), $('#myForm').valid());
//Validate dynamically created form
var input = $('<input />', {
type: 'text',
name: 'email',
value: 'bademail'
});
//input.prop('value', 'bademail');
var form = $('<form />').append(input);
var validate = form.validate(myValidateObj);
console.log('Option 2', form, input, $('#email').val(), validate.element(input), input.valid(), form.valid());
});
});
The button needs to be inside the form and be a type="submit" in order for the plugin to capture the click.
Do not put .validate() within a click handler (See item 1). It's only used to initialize the plugin on a form. Exception, below we are creating the new form within a click handler and then immediately calling .validate() on the new form.
With these two small changes, the validation on the static form is working: jsfiddle.net/j2pgobze/3/
I rewrote your DOM manipulation code for clarity. I simply duplicated the HTML for the form and gave it a new ID: http://jsfiddle.net/zem84tfp/
$(function () {
// INITIALIZE plugin on the traditional form
var validate1 = $('#myForm').validate(myValidateObj);
$('#newform').one('click', function () {
// code here to create new form; give it new ID
// do not duplicate ID on anything else
// INITIALIZE plugin on the new form
var validate = $('#myForm2').validate(myValidateObj);
});
});
I'm trying to leverage some form validation to do something it really wasn't designed to do. I have a table in my form and each row has a checkbox. I want to ensure that at least one of a specific type of checkbox is selected, if not I want to show a validation error. I am doing something similar with a text box with logic that looks like this:
function ValidateName() {
var $nameTextbox = $("#Name");
var $originalName = $("#OriginalName");
var nameText = $nameTextbox.val().toLowerCase();
var originalNameText = $originalName.val().toLowerCase();
//check to see if original name and group name match
if (nameText != originalNameText) {
//This isn't the same name we started with
if (uniqueNames.indexOf(nameText) > -1) {
//name isn't unique, throw validation error
var currentForm = $nameTextbox.closest("form");
//trigger validation
var errorArray = {};
errorArray["Name"] = 'Name must be unique';
currentForm.validate().showErrors(errorArray);
}
}
}
I've written something similar for the table and it works as long as I point the errorArray's index to the id of an input. However, I want to display the error somewhere more generic like the validation summary at the top of the form. How do I set up the error array to show on the form or the validation summary instead of a specific input? Is that even possible?
One way you could do this is you set a hidden input that is false when none are check and true if 1 or more are checked. You then listen to all the checkboxes by giving them all a class. I have an example shown below
http://jsfiddle.net/95acw2m9/
Html
<input type="hidden" id="IsCheckValue" name="IsCheckedValue" value="false"/>
<input type="checkbox" class="someCheckbox"/>
<input type="checkbox" class="someCheckbox"/>
<input type="checkbox" class="someCheckbox"/>
Jquery
$(document).ready(function(){
$(".someCheckbox").change(function(){
if($(".someCheckbox:checked ").length > 0){
$("#IsCheckValue").val("True")
}else{
$("#IsCheckValue").val("False")
}
})
})
Then pass that bool value in your model. In your controller method you can check the value of the bool. If the bool is false set the model to false like this
ModelState.AddModelError("Checkbox", "Must select one checkbox");
You can use the #Html.ValidationSummary() to display the error in your view.
I'm working on a Durandal JS SPA application, and I wish to use Knockout Validation.
The problem is that validation is being triggered on page load, which is not what I want - I'd like to trigger the validation myself.
I have tried using
ko.validation.init({
registerExtenders: true,
messagesOnModified: true,
insertMessages: false
});
as well as ko.validation.configure with the same parameters, followed by ko.validation.init();
Here is a snippet of my viewmodel.
function ViewModel(){
var self = this;
self.username = ko.observable().extend({
required: true
});
self.errors = ko.validation.group(self);
}
I also tried delaying the call to ko.validation.group(self) till a button is clicked, but then it wont validate at all.
assuming you only want to show a summary of validation errors per some action, you could do something like this:
html
<input type="text" data-bind='value: username' />
<br/>
<button data-bind="click: submit">Submit</button>
<div data-bind="visible: showErrors, text: errors" />
js
function ViewModel() {
var self = this;
self.username = ko.observable().extend({
required: true
});
self.showErrors = ko.observable(false);
self.submit = function () {
self.showErrors(true);
if (self.isValid()) {
// save data here
}
}
self.errors = ko.validation.group(self);
}
sample fiddle
http://jsfiddle.net/LvHUD/1/