Knockout Validation onlyif object no function and pattern validation - validation

I want to the priceMax was required, when title is empty.
I have code
self.searchParameters = {
title: ko.observable().extend({
refreshCountOffers: 500
}),
priceMax: ko.observable().extend({
required: {
onlyIf: function() {
return title==null;
}
},
refreshCountOffers: 500
})
};
,but I get error 'title is not defined'.
How to disable option, which show error for pattern validation, when user input first letter?
postCode: ko.observable().extend({
required: true,
pattern: {
message: 'Post code is not valid',
params: '[0-9]{2}-[0-9]{5}'
},
refreshCountOffers: 500
})
my jsfiddle

There are 2 problems with the onlyIf check:
you need to qualify the title property
title is observable so you need to access the value
The code below resolves both:
onlyIf: function() {
return self.searchParameters.title();
}

Related

How can I cause adding an invalid item to an observableArray to invalidate the validatedObservable with Knockout-Validation

I have a form with some fields and a list of items which a user can add to. For the form to be valid, all of the fields on the form and in all items of the list must be valid. When a new item is added to the list it will be invalid because all of the required fields will be blank.
Unfortunately, knockout-validation doesn't seem to see this and reports the form as valid. The individual fields in the list items will validate independently and show the "This field is required." message but the validatedObservable which contains everything reports isValid() as true. Even stranger, if I cause the form to become invalid by editing one of the fields that existed before the list addition, suddenly everything starts to work properly.
Here's an example of the issue I'm working with: http://jsfiddle.net/97Lr15zq/5/
ko.validation.init({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
messageTemplate: null,
grouping: {
deep: true,
live: true
}
},
true);
var viewModel = {
items: ko.observableArray([]),
test: ko.observable('e').extend({ required: true }),
add: function(){
viewModel.items.push({
firstName: ko.observable('').extend({ required: true }),
lastName: ko.observable('').extend({ required: true })
});
},
submit: function() {
if (viewModel.errors.isValid()) {
alert('Thank you.');
}
else {
alert('Please check your submission. Errors: ' + viewModel.errors.errors().length);
viewModel.errors.errors.showAllMessages();
}
}
};
viewModel.errors = ko.validatedObservable({items: viewModel.items, test: viewModel.test});
ko.applyBindings(viewModel);
How can I get knockout-validation to start monitoring the new list items as soon as they're added?
This isn't ideal and I'm still hoping to find a cleaner solution but for now what I ended up doing is adding an observable to the viewModel and the validatedObservable who's only purpose is to be invalidated so that knockout-validate will start picking up the changes in the new list item.
http://jsfiddle.net/97Lr15zq/6/
var viewModel = {
items: ko.observableArray([]),
test: ko.observable('e').extend({ required: true }),
invalidator: ko.observable('a').extend({ required: true }),
add: function(){
viewModel.items.push({
firstName: ko.observable('').extend({ required: true }),
lastName: ko.observable('').extend({ required: true })
});
viewModel.invalidator('');
viewModel.invalidator('a');
},
submit: function() {
if (viewModel.errors.isValid()) {
alert('Thank you.');
}
else {
alert('Please check your submission. Errors: ' + viewModel.errors.errors().length);
viewModel.errors.errors.showAllMessages();
}
}
};
viewModel.errors = ko.validatedObservable({
items: viewModel.items,
test: viewModel.test,
invalidator: viewModel.invalidator
});

Form validation + api call with semantic ui

I've been banging my head on this one for the whole day.
I have this JS code for semantic ui. Simple validation + api (ajax) call.
$('.ui.form')
.form({
fields: {
comment: {
identifier: 'comment',
rules : [
{
type : 'empty',
prompt: 'Please enter you comment.'
}
]
}
}
});
$('.ui.form .submit.button')
.api({
action : 'new lead comment',
method : 'POST',
serializeForm: true,
urlData : {
id: $('#lead_id').val()
},
onSuccess : function(response) {
alert('success');
console.log(response);
},
onFailure : function(response) {
alert('failure');
console.log(response);
}
});
The problem is that after (failed) form validation, API is called and that should not happen. Both .form and .api work great on their own but not in "team" like this. I am aware of few workarounds (using beforeSend to do jquery $.ajax call) but I know there HAS to be a "semantic" way of doing this otherwise someone coded all this logic for nothing :)
For future reference (and because semantic ui docs are not clear in this part) the solution (that's working for me) is to attach .form and .api on the semantic ui form element like this:
$('.ui.form')
.form({
fields: {
comment: {
identifier: 'comment',
rules : [
{
type : 'empty',
prompt: 'Please enter you comment.'
}
]
}
}
})
.api({
action : 'new lead comment',
method : 'POST',
serializeForm: true,
urlData : {
id: $('#lead_id').val()
},
onSuccess : function(response) {
alert('success');
console.log(response);
},
onFailure : function(response) {
alert('failure');
console.log(response);
}
});
onSuccess callback is what you need.
$('.ui.form')
.form({
fields: {
comment: {
identifier: 'comment',
rules : [
{
type : 'empty',
prompt: 'Please enter you comment.'
}
]
}
},onSuccess:function(event){
event.preventDefault();
alert('valid but not submitted');
//you can use api or ajax call here
}
});

Validator Rule from addMethod always returning true

This is driving me nuts. Doing a simple check for whether or not an email address exists in my database via php using ajax in an addMethod rule to my validator. I've confirmed the php file is outputting "true" or "false" properly upon finding the email or not but the rule always returns true even though the response is correct and the value is false.
This is the rule:
$.validator.addMethod("isExisting", function() {
var checkemail=$("#email").val();
console.log('Email: '+checkemail); // shows email populated correctly
if(checkemail){
$.ajax({
type: 'post',
url: 'checkemail.php',
data: {email:checkemail,},
success: function(response){
console.log(response); // properly returns text "false" when email not found
var exists = (response=="false") ? false : true;
console.log('exists = '+exists); // is properly false
return exists; // returns false
}
});
}
});
And in the validator -
(the "isExisting" error message always pops up regardless of whether the email really exists or not):
$("#signupform").validate({
errorLabelContainer: "#errors",
errorPlacement: function (error, element) {
error.insertAfter(element);
$(element).addClass(errorClass).removeClass(validClass);
},
rules: {
fullname: {
required: true,
minlength: 2
},
email: {
required: true,
email: true,
isExisting: true
},
areacode: {
required: true,
digits: true,
minlength: 3
},
prefix: {
required: true,
digits: true,
minlength: 3
},
num: {
required: true,
digits: true,
minlength: 4
},
address: {
required: true,
},
city: {
required: true,
},
noRobot: {
isCaptcha: true,
}
},
messages: {
fullname: {
required: "Please enter your full name.<br />",
minlength: "Please enter your First and Last name.<br />"
},
email: {
required: "Please enter your email address.<br />",
email: "Please enter a valid email address.<br />",
isExisting: "There is already an account with that email address.<br />"
},
areacode: {
required: "Please enter your areacode.<br />",
minlength: "Your areacode should be 3 digits. »XXX« XXX-XXXX<br />"
},
prefix: {
required: "Please enter your phone number prefix.<br />",
minlength: "Your phone number Prefix should be 3 digits. XXX »XXX«-XXXX<br />"
},
num: {
required: "Please enter your phone number suffix.<br />",
minlength: "Your phone number Suffix should be 4 digits. XXX XXX-»XXXX«<br />"
},
address: {
required: "Please enter your Street Address for pick-up service.<br />"
},
city: {
required: "Please enter your town or city.<br />"
},
noRobot: {
isCaptcha: "Please verify that your are not a spam Robot.<br />"
}
}
});
I would think the "isExisting: true" would only validate true if the true value was returned from the response. (scratches head in frustration...)
checkemail.php:
else{
$result = mysqli_query($connect, "SELECT * FROM `customer_info` WHERE `email`='$email' LIMIT 1");
$num = mysqli_num_rows($result);
if($num > 0){
echo "true";
}
else {
echo "false";
}
}
mysqli_close($connect);
My understanding is that the validator methods should return true when the response is valid. In your case, the valid response is to not have a matching email, so you want to return true if the AJAX call returns false.
It would probably be less confusing to make this method isUnused rather than isExisting to avoid the boolean confusion, but you would need to change checkemail.php as well.
Edit: Disregard my answer above, I clearly misunderstood the problem.
I think the real issue is to do with asynchronous calls. Try setting async: false in your ajax call.

How to validate model using collection.create()

I'm trying to make a form validated before submit. For this, I defined a create method within the View which is responsible to call collection.create() method to create the model.
Here is a sample code:
app.ContactCreateView = Backbone.View.extend({
template: _.template($('#tpl-create-contact').html()),
initialize: function () {
this.router = new app.ContactsRouter();
this.contacts = new app.ContactsCollection();
},
events: {
'click #btn-create' : 'create',
'click #btn-cancel' : 'cancel',
},
render: function() {
this.$el.html(this.template());
return this;
},
getAttributes: function () {
console.log('getAttributes()');
var attr = {
name: $('#input-name').val().trim(),
category: $('#input-category').val().trim(),
phone: $('#input-phone').val().trim(),
email: $('#input-email').val().trim(),
};
console.log('attr : ' + JSON.stringify(attr))
return attr;
},
create: function () {
console.log('create()');
// Create the Model
this.contacts.create(this.getAttributes(), {
wait : true,
success: function () {
console.log('success');
//this.hideErrors();
var router = new app.ContactsRouter();
router.navigate('contacts', true);
},
error: function () {
console.log('error(s)')
//this.showErrors(errors);
}
});
},
The 'success' callback is well called but I don't manage to get the 'error' callback called once the model.validate() method is failing.
Here is the model with the validate method :
app.ContactModel = Backbone.Model.extend({
urlRoot: '/user',
// Default attributes for the Contact
defaults: {
name: null,
phone: null,
email: null,
category: null,
photo: "/images/placeholder.png"
},
validate: function(attrs) {
console.log('validate() : ' + JSON.stringify(attrs));
var errors = [];
if (!attrs.name) {
errors.push({name: 'name', message: 'Please fill name field.'});
}
if (!attrs.category) {
errors.push({name: 'category', message: 'Please fill category field.'});
}
console.log('errors : ' + JSON.stringify(errors));
return errors.length > 0 ? errors : false;
}
});
And the collection:
app.ContactsCollection = Backbone.Collection.extend({
model: app.ContactModel,
url: '/user',
//localStorage: new Backbone.LocalStorage('contacts-backbone'),
getById: function (iId) {
return this.where({id: iId});
},
getByName: function (iName) {
return this.where({name: iName});
}
});
I really don't understand what I'm doing wrong... If somebody can help me :-(
Regards,
when the validation is failed error callback is not called , it trigger an "invalid" event on model, and set the validationError property on the model.
method 1(listening on model):
app.ContactModel = Backbone.Model.extend({
urlRoot: '/user',
//your error catched here
initialize : function(){
this.on("invalid",function(model,error){
alert(error);
});
defaults: {
name: null,
phone: null,
email: null,
category: null,
photo: "/images/placeholder.png"
},
validate: function(attrs) {
console.log('validate() : ' + JSON.stringify(attrs));
var errors = [];
if (!attrs.name) {
errors.push({name: 'name', message: 'Please fill name field.'});
}
if (!attrs.category) {
errors.push({name: 'category', message: 'Please fill category field.'});
}
console.log('errors : ' + JSON.stringify(errors));
return errors.length > 0 ? errors : false;
}
});
method 2 (check whether validationError property is set in your view):
create: function () {
console.log('create()');
// Create the Model
this.contactModel.save(this.getAttributes(), {
wait : true,
success: function () {
console.log('success');
this.contacts.add(this.contactModel);
var router = new app.ContactsRouter();
router.navigate('contacts', true);
},
error: function () {
console.log('error(s)')
}
});
//your error catched here
if (this.contactModel.validationError) {
alert(this.contactModel.validationError)
}
},
So I played around with this for a while in an app I'm currently working on and found it kind of irritating and never really got it to work.
Instead I went the jQuery validation route and found it very helpful for doing validations. I highly recommend checking it out! It has a lot of built in validations you can just use and you can also override the error messages that display (also built in).
Example - I wanted a number only text field (excuse the coffeescript) :).
jQuery.validator.setDefaults(
debug: true,
success: "valid")
if #model.get('number_only')
$('#number_only').validate({
debug: true,
rules: {
"number[entry]": {
required: true,
range: [#model.get('min_number'), #model.get('max_number')],
number: true
}
},
messages: {
"number[entry]": {
required: "This field is required. Please enter a numeric value.",
min: jQuery.validator.format("Please enter a value greater than or equal to {0}."),
max: jQuery.validator.format("Please enter a value less than or equal to {0}."),
number: "Please enter a numeric value"
range: jQuery.validator.format("Please enter a value between {0} and {1}.")
}
}
})
If that doesn't really get what you want (seemed like you maybe are more interested in displaying the errors your server sends back whereas this route would more be validating the content before saving your model) let me know and I can see if I can figure out your problem.

Knockout Validation Only If a specific button is pressed

https://github.com/ericmbarnard/Knockout-Validation/wiki/Native-Rules
I am using the knockout validation on my MCV3 page. The situation I have is that I have two buttons. one is Add To Collection, and other is Save. The Add to collection looks for following properties as they are required:
FirstName: ko.observable().extend({ required: true }),
LastName: ko.observable().extend({ required: true }),
Title: ko.observable(),
Email: ko.observable().extend({ required: true, email: true }),
Date1: ko.observable(new Date()).extend({ required: true }),
I have two functions defined that check if the page is valid:
first:
AddToCollection: function () {
if (!viewModel.isValid()) {
viewModel.errors.showAllMessages();
return false;
} else {
this.Collection.push(new Item(this.FirstName(), this.LastName(), this.Title(), this.Email()));
viewModel.clear();
}
},
and second:
save: function () {
if (!viewModel.isValid()) {
viewModel.errors.showAllMessages();
return false;
} else {
$.ajax({
url: '#Url.Action("DoSomethinn")',
type: "POST",
data: ko.toJSON(this),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
}
});
}
}
The thing that I am trying to do is that I don't want the FirstName, LastName, and Email to be required if Save is called, only Date1 is validated, but FirstName, LastName, and Email is required when AddToCollectoin is called, but Date1 is not. How do set up the Only If Native Rule, or is there a better way of doing this.
Any help is much appreciated!
The onlyIf option could work here:
FirstName: ko.observable().extend({
required: {
params: true,
onlyIf: function(){ return someFlagIsTrue; }
}
You would need to set the someFlagIsTrue from your click event or other means.

Resources