I have a problem in using knockout.js validation plug in. when I try to define 'errors' in newPerson viewmodel the compiler says that newPerson is undefined. Totally, is it correct to use knockout-validation with object type of viewmodels instead of function type?
var clientModel = {
newPerson: {
EmailAddress: ko.observable().extend({
required: {
params: true,
message: "This field is required"
},
emailFormatCheck: {
params: true,
message: ""
}
}),
errors: ko.validation.group(newPerson, {
deep: true
})
}
}
ko.extenders.emailFormatCheck = function(target, overrideMessage) {
target.hasError = ko.observable();
target.validationMessage = ko.observable();
function validate(newValue) {
var matches = /^([\w-]+(?:\.[\w-]+)*)#((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i.exec(newValue);
if (matches == null) {
target.hasError(true);
target.validationMessage("The email format is wrong!!!");
} else {
target.hasError(false);
}
}
validate(target());
target.subscribe(validate);
return target;
};
ko.validation.init({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true
});
ko.applyBindings();
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<div class="panel panel-primary">
<div class="panel-heading"></div>
<div class="panel-body">
<form role="form" data-bind="with: clientMode.newPerson">
<div class="form-group">
<p data-bind="css: { error: EmailAddress.hasError }">
<label>Email</label>
<br />
<input class="form-control" data-bind="value: EmailAddress, valueUpdate: 'afterkeydown'" /> <span data-bind="visible: EmailAddress.hasError, text: EmailAddress.validationMessage"> </span>
</p>
</div>
<br />
</form>
</div>
<div class="panel-footer">
<button type="submit" class="btn btn-default" data-bind=" enable:!clientModel.errors().length">Creat</button>
</div>
</div>
Thank you in advance
Related
I need to find a way to basically show "per Month" in the assessments_period input if the assessments fee input has a typed-in value.
I've tried bindings and components but can't pull this off.
<div class="col-lg-6">
<div class="form-group">
<label>Assessment Fee <span class="note">C</span></label>
<input type="text" class="form-control" v-model="document.assessments_fee" placeholder="$">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label>Assessment Period <span class="note">C</span></label>
<input type="text" class="form-control" v-model="document.assessments_period" placeholder="(per month/quarter/etc.)">
</div>
</div>
data() {
return {
now: new Date().toISOString(),
document: {
assessments_fee: '',
assessments_period: '',
}
}
},
components: {
assessments_fee: function() {
if(this.assessments_fee != null || '') this.assessments_period = "per Month";
}
},
you can create a watcher for assessments_fee so when its not null assessments_period= 'per Month'.
Here is how you can do it:
new Vue({
el: '#app',
data() {
return {
now: new Date().toISOString(),
document: {
assessments_fee: '',
assessments_period: '',
}
}
},
computed: {
assessmentsFee() {
return this.document.assessments_fee
}
},
watch: {
assessmentsFee() {
this.document.assessments_fee ?
this.document.assessments_period = "per Month" :
this.document.assessments_period = ""
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="col-lg-6">
<div class="form-group">
<label>Assessment Fee <span class="note">C</span></label>
<input type="text" class="form-control" v-model="document.assessments_fee" placeholder="$">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label>Assessment Period <span class="note">C</span></label>
<input type="text" class="form-control" v-model="document.assessments_period" placeholder="(per month/quarter/etc.)">
</div>
</div>
</div>
I have a contact form that uses vuelidate to validate fields. The problem is - the validation works, but the errors don't render.
$v.name.dirty is TRUE and $v.name.required is FALSE.
Logging $v.name.dirty && !$v.name.required returns TRUE which is the same condition in the v-if directive but the error elements still don't show.
However, when .$touch() is called and $v.name.dirty becomes true and $v.name.required false, anything I type in the input fields will show the errors.
JS:
import translationsBus from "../../app/translations";
export default {
name: "contactForm",
beforeMount() {
this.$store.dispatch("updateTranslations", translationsBus.translations);
},
data: function () {
return {
name: '',
email: '',
subject: '',
message: ' ',
errors: [],
isSuccessful: ''
}
},
mounted() {
var my_axios = axios.create({
baseURL: '/'
});
Vue.prototype.$http = my_axios;
},
computed: {
isLogged: function () {
return isLoggedOn;
},
shouldShowSubjectOption: function () {
return showSubjectOption;
},
translations: function () {
return this.$store.state.translations.translations;
},
},
methods: {
onContactUsClick: function onContactUsClick() {
const _this = this;
this.$v.$touch();
if (!this.$v.$error) {
let model = {
senderName: _this.name,
senderEmail: _this.email,
subject: _this.subject,
message: _this.message
};
this.$http.post('/home/contactus', model)
.then(response => {
console.log(response);
_this.isSuccessful = response.data;
})
.catch(e => {
console.log(e);
});
}
}
},
validations: {
email: {
required: required,
isValidEmail: function isValidEmail(value) {
var re = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
return re.test(value);
}
},
name: {
required: required
},
subject: {
required: required
},
message: {
required: required
}
}
}```
HTML:
<div v-bind:class="{ 'col-lg-6' : shouldShowSubjectOption, 'col-lg-12' : !shouldShowSubjectOption }">
<div id="form-contact">
<h1 class="lead">Get in touch...</h1>
<form class="text-center" >
<div class="form-group">
<label for="name">{{translations['contact_Form_Name']}}</label>
<div class="input-group">
<span class="input-group-addon"><span class="fa fa-user"></span></span>
<input type="text" class="form-control" name="senderName" id="senderName" v-model:bind="name" v-bind:placeholder="translations['contact_Form_NamePlaceholder']" />
</div>
<div class="has-error" v-cloak>
<label class="control-label" v-if="$v.name.$dirty && !$v.name.required">{{translations['shared_Validation_ReuiredField']}}</label>
</div>
</div>
<div class="form-group">
<label for="email">{{translations['contact_Form_EmailAddress']}}</label>
<div class="input-group">
<span class="input-group-addon"><span class="fa fa-envelope"></span></span>
<input type="email" class="form-control" name="senderEmail" id="senderEmail" v-model:bind="email" v-bind:placeholder="translations['contact_Form_EmailAddressPlaceholder']" />
</div>
<div class="has-error" v-cloak>
<label class="control-label" v-if="$v.email.$dirty && !$v.email.required">{{translations['shared_Validation_ReuiredField']}}</label>
<label class="control-label" v-if="$v.email.$dirty && $v.email.required && !$v.email.isValidEmail">{{translations['contact_Form_EmailAddressValidationMessage']}}</label>
</div>
</div>
<div class="form-group" v-if="shouldShowSubjectOption">
<label for="subject">{{translations['contact_Form_Subject']}}</label>
<select id="subject" name="subject" class="form-control" v-model:bind="subject" v-bind:title="translations['contact_Form_SubjectPickerText']">
<option value="service">1</option>{{translations['contact_Form_SubjectOption_GCS']}}
<option value="suggestions">2</option>{{translations['contact_Form_SubjectOption_Suggestions']}}
<option value="product">3</option>{{translations['contact_Form_SubjectOption_ProductSupport']}}
</select>
</div>
<div class="has-error" v-cloak>
<label class="control-label" v-if="$v.subject.$dirty && !$v.subject.required" v-cloak>{{translations['shared_Validation_ReuiredField']}}</label>
</div>
<div class="form-group">
<label for="name">{{translations['contact_Form_Message']}}</label>
<textarea name="message" id="message" class="form-control" v-model:bind="message" rows="9" cols="25"
placeholder="">{{translations['contact_Form_Message']}}</textarea>
</div>
<div class="has-error" v-cloak>
<label class="control-label" v-if="$v.message.$dirty && !$v.message.required">{{translations['shared_Validation_ReuiredField']}}</label>
</div>
<div class="form-group" v-if="isLogged">
<div class="g-recaptcha" data-sitekey=""></div>
</div>
<button type="button" class="btn btn-primary btn-block" v-on:click="onContactUsClick" id="btnContactUs">{{translations['contact_Form_SendMessageButton']}}</button>
</form>
</div>
</div>
</div>
</div>
I expect error elements to appear on submit.
I have a form that has userID and screen name input fields.
When validating I need to make sure that at least one of them is entered (if both were entered I only take one). The html:
this.addFormValidators = function () {
$('#editCreatePipeForm').formValidation({
framework: 'bootstrap',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
ConsumerKey: {
validators: {
notEmpty: {
message: 'The Consumer Key is required'
}
}
},
ConsumerKeySecret: {
validators: {
notEmpty: {
message: 'The Consumer Key Secret is required'
}
}
},
CollectionIntervalSec: {
validators: {
notEmpty: {
message: 'The collection interval is required'
},
between: {
message: 'The collection interval must be a number greater than 10',
min: 10,
max: 1000000000
}
}
},
//KeepHistoricalDataTimeSec: {
// validators: {
// notEmpty: {
// message: 'The retain data value is required'
// },
// between: {
// message: 'The retain data value must be a number greater than 1000',
// min: 1000,
// max: 1000000000
// }
// }
//},
Description: {
validators: {
stringLength: {
max: 500,
message: 'The description must be less than 500 characters long'
}
}
}
}
}, null);
};
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="ScreenName" class="col-md-4 YcdFormLabel" title="screen name of user to retrieve">Screen name</label>
<div class="col-md-8">
<input type="text" placeholder="Screen Name" class="form-control user" autocomplete="off"
name="screenName"
id="screenName" data-bind="value: screenName, valueUpdate: 'keyup'"/>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4"/>
<div class="col-md-6">
<div class="form-group">
#*<div class="col-md-8">*#
<label for="or" class="col-md-10">or</label>
#*</div>*#
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="userID" class="col-md-4 YcdFormLabel" title="user_ID of user to retrieve">User ID</label>
<div class="col-md-8">
<input type="text" placeholder="User ID" class="form-control user" autocomplete="off"
name="userID"
id="userID" data-bind="value: userID, valueUpdate: 'keyup'"/>
</div>
</div>
</div>
</div>
I added another function which I called it before submitting instead of using Bootstrap and jQuery form validation.
private hasTimelineAndUsername = (): boolean => {
if (this.viewModel.searchSelection() == "timeline"
&& ((this.viewModel.userID() == "" ||
this.viewModel.userID() == null) &&
(this.viewModel.screenName() == "" ||
this.viewModel.screenName() == null))) {
return false
}
return true;
}
The submitting function:
public getCollectionParameters() {
var fv = $('#editCreatePipeForm').data('formValidation')
fv.validate();
var isValid = fv.isValid();
if (!isValid) {
toastr.error("Please fix all problems before saving");
return null;
}
if (!this.hasTimelineAndUsername()) {
toastr.clear();
toastr.error("Please type username/userID");
return null;
}
if (!this.validateData()) {
return null;
}
return JSON.stringify(ko.mapping.toJS(this.viewModel));
}
I hope my code will help you.
JSFiddle: https://jsfiddle.net/aice09/3wjdvf30/
CodePen: https://codepen.io/aice09/pen/XgQyem
GitHub: https://github.com/Ailyn09/project102/blob/master/chooseintwoinput.html
function verify() {
var screenName = document.getElementById("screenName").value;
var userID = document.getElementById("userID").value;
if (userID === '' && screenName === '') {
alert('Add value to any field');
}
if (userID !== '' && screenName === '') {
alert('Your screen name are currently empty. The value you will be taken is your screen name');
document.getElementById("takedvalue").value = userID;
}
if (userID === '' && screenName !== '') {
alert('Your user id are currently empty. The value you will be taken is your user identification');
document.getElementById("takedvalue").value = screenName;
}
if (userID !== '' && screenName !== '') {
document.getElementById("mainbtn").style.display = "none";
document.getElementById("backbtn").style.display = "initial";
document.getElementById("choosescreenName").style.display = "initial";
document.getElementById("chooseuserID").style.display = "initial";
}
}
//Reset Form
$('.backbtn').click(function () {
document.getElementById("mainbtn").style.display = "initial";
document.getElementById("backbtn").style.display = "none";
document.getElementById("choosescreenName").style.display = "none";
document.getElementById("chooseuserID").style.display = "none";
});
//Choose First Input
$('.choosescreenName').click(function () {
var screenName = document.getElementById("screenName").value;
document.getElementById("takedvalue").value = screenName;
});
//Choose Second Input
$('.chooseuserID').click(function () {
var userID = document.getElementById("userID").value;
document.getElementById("takedvalue").value = userID;
});
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://code.jquery.com/jquery-1.12.3.min.js"></script>
<div class="container">
<form action="POST">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="screenName">Screen name</label>
<input type="text" placeholder="Screen Name" class="form-control " autocomplete="off" name="screenName" id="screenName" />
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label for="userID">User ID</label>
<input type="text" placeholder="User ID" class="form-control user" autocomplete="off" name="userID" id="userID" />
</div>
</div>
<div class="col-md-12">
<button type="button" class="btn btn-primary" id="mainbtn" onclick="verify();">SUBMIT</button>
<button type="reset" class="btn btn-primary backbtn" id="backbtn" style="display:none;">BACK</button>
<button type="button" class="btn btn-primary choosescreenName" id="choosescreenName" style="display:none;">CHOOSE SCREEN NAME</button>
<button type="button" class="btn btn-primary chooseuserID" id="chooseuserID" style="display:none;">CHOOSE USER ID</button>
</div>
<div class="col-md-12">
<hr>
<div class="form-group">
<label for="userID">Value</label>
<input type="text" placeholder="Taken Value" class="form-control" id="takedvalue" readonly />
</div>
</div>
</div>
</form>
</div>
I have example web application with knockout.validation. I need show tooltip with message for required property - requiredText. I want create tooltip in viewmodel, not in html, but I can't?
HTML:
<!DOCTYPE html>
<html>
<head>
<title>ko.validation.test</title>
<link href="Content/bootstrap.css" rel="stylesheet" />
<link href="Content/bootstrap-theme.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<h2>Required field validation</h2>
<div class="bs-docs-example">
<form>
<fieldset>
<div class="control-group" data-bind="validationElement: requiredText">
<label>Example 1 required</label>
<div class="input-append">
<input type="text" data-bind="value: requiredText" />
<button class="btn" data-bind="click: validateExample1Clicked">Validate</button>
</div>
<span class="label label-success" data-bind="visible: showExample1Success">Example 1 is valid</span>
<span class="label label-important" data-bind="visible: showExample1Failed">Example 1 is not valid</span>
<span class="help-inline" data-bind="validationMessage: requiredText"></span>
</div>
<div class="control-group" data-bind="validationElement: requiredTextUsingAttributes">
<label>Example 2 required attribute</label>
<div class="input-append">
<input type="text" data-bind="value: requiredTextUsingAttributes" required />
<button class="btn" data-bind="click: validateExample2Clicked">Validate</button>
</div>
<span class="label label-success" data-bind="visible: showExample2Success">Example 2 is valid</span>
<span class="label label-important" data-bind="visible: showExample2Failed">Example 2 is not valid</span>
<span class="help-inline" data-bind="validationMessage: requiredTextUsingAttributes"></span>
</div>
<div class="control-group">
<label>Optional</label>
<input type="text" data-bind="value: optionalText" />
</div>
<div class="form-actions">
<button class="btn btn-primary" data-bind="click: validateAllClicked">Validate all</button>
</div>
<div class="alert alert-error" data-bind="visible: showValidationErrors">
<strong>Not valid</strong> All the fields in the form are not valid.
</div>
<div class="alert alert-success" data-bind="visible: showValidationSuccess">
<strong>Valid</strong> All the fields are valid.
</div>
<div class="alert alert-info" data-bind="visible: errors().length > 0">
<strong>Form is not valid</strong> The form has following errors:
<ul data-bind="foreach: errors">
<li data-bind="text: $data"></li>
</ul>
</div>
</fieldset>
</form>
</div>
</div>
<script src="Scripts/jquery-2.1.1.js"></script>
<script src="Scripts/knockout-3.2.0.js"></script>
<script src="Scripts/knockout.validation.js"></script>
<script src="Scripts/bootstrap.js"></script>
<script src="ts/TestViewModel.js"></script>
</body>
</html>
JavaScript:
/// <reference path="../scripts/typings/knockout/knockout.d.ts" />
/// <reference path="../scripts/typings/knockout.validation/knockout.validation.d.ts" />
/// <reference path="../scripts/typings/bootstrap/bootstrap.d.ts" />
var TestViewModel = (function () {
function TestViewModel() {
var _this = this;
this.requiredText = ko.observable().extend({ required: true });
this.optionalText = ko.observable();
this.requiredTextUsingAttributes = ko.observable();
this.errors = ko.validation.group(this);
this.showValidationErrors = ko.observable(false);
this.showValidationSuccess = ko.observable(false);
this.showExample1Success = ko.observable(false);
this.showExample2Success = ko.observable(false);
this.showExample1Failed = ko.observable(false);
this.showExample2Failed = ko.observable(false);
this.validateExample1Clicked = function () {
if (!ko.validation.validateObservable(_this.requiredText)) {
alert("rrrrrr");
// Create tooltip
};
this.validateExample2Clicked = function () {
if (ko.validation.validateObservable(_this.requiredTextUsingAttributes)) {
_this.showExample2Success(true);
_this.showExample2Failed(false);
} else {
_this.showExample2Success(false);
_this.showExample2Failed(true);
}
};
this.validateAllClicked = function () {
if (_this.errors().length == 0) {
_this.showValidationSuccess(true);
_this.showValidationErrors(false);
} else {
_this.showValidationSuccess(false);
_this.showValidationErrors(true);
}
};
}
return TestViewModel;
})();
ko.validation.init({
parseInputAttributes: true,
decorateElement: true,
errorElementClass: 'error'
});
ko.applyBindings(new TestViewModel());
//# sourceMappingURL=TestViewModel.js.map
HTML:
<script src="Scripts/jquery-2.1.1.min.js"></script>
<script src="Scripts/knockout-3.2.0.js"></script>
<script src="Scripts/knockout.validation.js"></script>
<link href="Content/bootstrap.min.css" rel="stylesheet" />
<script src="Scripts/bootstrap.min.js"></script>
<script src="Scripts/ViewModel.js"></script>
<style>
body {
font-family: Helvetica, Arial, sans-serif;
padding: 10px;
}
fieldset {
padding: 10px;
border: solid 1px #ccc;
width: 500px
}
label {
display: block;
width: 100%;
padding: 5px
}
.validationMessage {
color: Red;
}
.Warning {
border-color: red;
}
.customMessage {
color: Orange;
}
input {
border:1px solid #ccc
}
</style>
<div id="contain" class="container">
<h2>Required field validation</h2>
<input data-bind="value: lastName, tooltip: isValidField" data-placement="below" data-title="Alert" data-content="We have identified this information is incorrect and must be updated." />
<button type="button" data-bind='click: submit'>Submit</button>
</div>
JavaScript:
ko.validation.rules.pattern.message = 'Invalid.';
ko.validation.configure({
//decorateInputElement: true,
decorateElement: true,
registerExtenders: true,
messagesOnModified: false,
insertMessages: false,
parseInputAttributes: true,
messageTemplate: null,
errorClass: 'Warning'
// errorAsTitle: true
});
var ViewModel = function () {
var self = this;
self.lastName = ko.observable().extend({ required: true });
self.isValidField = ko.observable();
this.submit = function () {
if (self.errors().length === 0) {
alert('Thank you.');
} else {
self.errors.showAllMessages();
self.isValidField(self.lastName.isValid());
}
};
self.errors = ko.validation.group(self);
};
ko.bindingHandlers.popover = {
init: function (element, valueAccessor, allBindingsAccessor) {
var value = valueAccessor(),
valueUnwrap = ko.unwrap(value),
allBindings = allBindingsAccessor(),
isValid = allBindings.value;
if (isValid) {
$(element).popover({
trigger: "hover"
});
} else {
$(element).popover("hide");
}
},
update: function (element, valueAccessor, allBindingsAccessor) {
var value = valueAccessor(),
valueUnwrap = ko.unwrap(value),
allBindings = allBindingsAccessor(),
isValid = allBindings.value;
if (isValid) {
$(element).popover({
trigger: "hover"
});
} else {
$(element).popover("hide");
}
}
};
ko.bindingHandlers.tooltip = {
init: function(element, valueAccessor) {
var local = ko.utils.unwrapObservable(valueAccessor()),
options = {};
ko.utils.extend(options, ko.bindingHandlers.tooltip.options);
ko.utils.extend(options, local);
$(element).tooltip(options);
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).tooltip("destroy");
});
},
options: {
placement: "right",
trigger: "hover"
}
};
$(document).ready(function () {
ko.applyBindings(new ViewModel());
});
You can use extenders on observables to implement this kind of validation. Here's a sample implementation using the extender code from the Knockout documentation, just click "Run code snippet" to see a working demo:
JS & HTML:
ko.extenders.required = function(target, overrideMessage) {
//add some sub-observables to our observable
target.hasError = ko.observable();
target.validationMessage = ko.observable();
//define a function to do validation
function validate(newValue) {
target.hasError(newValue ? false : true);
target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
}
//initial validation
validate(target());
//validate whenever the value changes
target.subscribe(validate);
//return the original observable
return target;
};
function TestViewModel() {
var self = this;
self.name = ko.observable('').extend({ required: "Required" });
}
ko.applyBindings(new TestViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<label for="name">Name:</label>
<p data-bind="css: { error: name.hasError }">
<input data-bind='value: name, valueUpdate: "afterkeydown"' />
<span data-bind='visible: name.hasError, text: name.validationMessage'> </span>
</p>
ko.validation has property: "insertMessages".
by defalut is true = show error in span near the element. for display error message in toolTip set value 'false' like this:
ko.validation.init{
insertMessages: false
}
I'd like to use Knockout.js to highlight errors on a form.
Currently i see all errors when i get the form,
I want to get them only if the user press on Save button.
So I'm try to set a flag that will be true only if the user press on it, and then to use it in all form but i don't have success with that.
I will apreciate some help with that. (or any other way to do it)
so i will need someting like that on my html:
<div class='liveExample' data-bind="css: {hideErrors: !hasBeenSubmittedOnce()">
and somewhere in my js file:
this.hasBeenSubmittedOnce = ko.observable(false);
this.save = function(){
this.hasBeenSubmittedOnce(true);
}
that my files
HTML
<div class='liveExample' data-bind="css: {hideErrors: !hasBeenSubmittedOnce()">
<form class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">Store:</label>
<div class="col-sm-3" data-bind="css: { error: storeName.hasError() }">
<input data-bind='value: storeName, valueUpdate: "afterkeydown"' />
<span data-bind='text: storeName.validationMessage'> </span>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Company ID:</label>
<div class="col-sm-3" data-bind="css: { error: companyId.hasError }">
<input data-bind='value: companyId, valueUpdate: "afterkeydown"' />
<span data-bind='text: companyId.validationMessage'> </span>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Address</label>
<div class="col-sm-3" data-bind="css: { error: address.hasError }">
<input data-bind='value: address, valueUpdate: "afterkeydown"' />
<span data-bind='text: address.validationMessage'> </span>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Phone:</label>
<div class="col-sm-3" data-bind="css: { error: phone.hasError }">
<input data-bind='value: phone, valueUpdate: "afterkeydown"' />
<span data-bind='text: phone.validationMessage'> </span>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-4">
<button class="btn btn-primary" data-bind="click: save">Add store</button>
</div>
</div>
</form>
Store:
Company ID:
Address
Phone:
Add store
</form>
js
define(['knockout'], function (ko){
ko.extenders.required = function(target, overrideMessage) {
//add some sub-observables to our observable
target.hasError = ko.observable();
target.validationMessage = ko.observable();
//define a function to do validation
function validate(newValue) {
target.hasError(newValue ? false : true);
target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
}
validate(target());
target.subscribe(validate);
return target;
};
function AppViewModel(storeName, companyId, address, phone) {
this.storeName = ko.observable(storeName).extend({ required:"" });
this.companyId = ko.observable(companyId).extend({ required: "" });
this.address = ko.observable(address).extend({ required: "" });
this.phone = ko.observable(phone).extend({ required: ""});
this.hasError = ko.computed(function(){
return this.storeName.hasError() || this.companyId.hasError();
}, this);
this.hasBeenSubmittedOnce = ko.observable(false);
this.save = function(){
this.hasBeenSubmittedOnce(true);
}
}
return AppViewModel;
});
CSS file
.form-group span {
display: inherit;
}
.hideErrors .error span {
display: none;
}
I did some work around for this and not sure it is better way or not.
var showError=ko.observableArray([]);//it will store show Error Message
ko.extenders.required = function(target, overrideMessage) {
//add some sub-observables to our observable
target.hasError = ko.observable();
target.validationMessage = ko.observable();
//define a function to do validation
function validate(newValue) {
target.hasError($.trim(newValue) ? false : true);
target.validationMessage($.trim(newValue) ? "" : overrideMessage || "This field is required");
}
showError.push(function(){validate(target());});
target.subscribe(validate);
return target;
};
function AppViewModel(storeName, companyId, address, phone) {
this.storeName = ko.observable(storeName).extend({ required:"" });
this.companyId = ko.observable(companyId).extend({ required: "xcxcx" });
this.address = ko.observable(address).extend({ required: "" });
this.phone = ko.observable(phone).extend({ required: ""});
this.hasError = ko.computed(function(){
return self.storeName.hasError() || self.companyId.hasError();
}, this);
this.hasBeenSubmittedOnce = ko.observable(false);
this.save = function(){
ko.utils.arrayForEach(showError(),function(func){
func();
});
}
}
ko.applyBindings(new AppViewModel());
Fiddle Demo
You can use the visible knockout binding:
<div data-bind="visible: hasBeenSubmittedOnce">
As for the error class, you can use the define the default knockout validation class: 'validationElement' and call
ko.validation.init({ decorateElement: true});
Here you can find more:
https://github.com/Knockout-Contrib/Knockout-Validation/wiki/Configuration
(please note that decorateElement has been renamed 2013-11-21 to 'decorateInputElement')