Backbone validateAll - backbone.js

Question 1
I'm trying to add a form validation using the following link.
https://github.com/gfranko/Backbone.validateAll/blob/master/demos/index.html
The sample code is working perfectly. But in my case I have a form with corresponding View, when I click on the submit button how can I validate?
In my View's initialize() I have added the following code to enable validation for the fields.
var user = new User;
$('input').each(function() {
new Field({el: this, model: user});
});
this.model.set({route: formData.route}, {validate: true, validateAll: false});
But it is not validating.
My idea is validate a form with backbone and submit to PHP.
Using the code in the link how can I achieve it?
Question 2
I tried some other kind fo validations, Model save() error callback is not working for it.
this.model.save({route:formData.route}, {
error: function(){
console.log('error!!!'); // Not showing for failed validation
},
success: function(){
console.log('success!!!!!');
}
});
What could be the reason?

The main ideia is you have validators to perform when you set something on Model.
To do that, you'll need a code like this:
For example inside the model, you can check if the attribute has some value.
validation:
route : [
required: true
]
setNewValue:->
#set("route":"AnyValue")
The validation function will validate all the rules before the value be attached on model.
keep on mind that it's really important do this kind of thing inside your model. Avoiding your views to have theses rules.
To perform the validation before you save, try to add.
postData:->
validateModel = true
if #isValid(validateModel)
#save()....

Related

angular formly read-only mode for radio , multiCheckbox and checkbox

I need to display the form in read-only mode , I am creating the form based on Json using angular-formly . Checked the link http://angular-formly.com/#/example/other/read-only-form which works for text input , please suggest how to set read-only for radio , multicheckbox and checkbox
we do it via jQuery:
$(document).ready(function () {
$('input').click(function (e) {
e.preventDefault();
});
});
OR if you want to "pretend" you are using "angular" to do this, even though you are actually using jQuery, and want to type out a whole lot more code to write the exact same thing(literally, it will simply run the above code in jQuery as angular.element is an "alias" for jQuery---straight out of the angular docs: https://docs.angularjs.org/api/ng/function/angular.element), you can do:
angular.element(function() {
angular.element('input').trigger('click')(function(e) {
e.preventDefault();
};
});
This way you can look cool and spout off nonsense like "It's bad practice to run angular and jQuery together" because you have no clue what you are talking about and just read that somewhere.
This works for all input fields. If you have buttons or datepickers with buttons, etc the easiest way to do it is to set a readOnly property on the model in the form and then set it to true on page where you want it to be read only then set the ng-show on the buttons to: ng-show="!model.readOnly"

angularjs - streamline form (automatic) submission based on dirty scope

Problem space
I have a problem where I'm submitting a form based on criteria being fulfilled, rather than having a form submission button.
Let's say I have 3 drop downs, the first two are grouped but one needs to be selected, meaning I can select one or the other but I can't leave them empty, the 3rd one is a required field.
After that, the page automatically fetches in results.
Lets say I have checkboxes and a few more dropdowns. Any future selections on the 3 dropdowns mentioned, checkboxes, and dropdowns automatically filters the results.
What I know
Now after reading angular documentation, I was checking up on $dirty, $pristine and operations on both, like $setDirty and $setPristine; however, it seems that this is for a FormController
So I'm assuming this is useful for an entire scope. I didn't see any inclination that I can figure out for selected scopes.
What I have so far
So basically, I was hoping that I'd be making use of the scope's tracking features, but I don't know much about it. I created a single controller for my application and a single scope, since that's what seemed easiest for me. I have 3rd party plugins that play a role into the scope like:
$scope.3rdpartyConfig = {
prop1: [],
prop2: getData()
}
I don't think something like that would be useful in checking to see form submission if I was going to check the $dirty state of my form.
Then I thought about the old way I used to do things, but "angularlizing" it:
so I'd have something like:
<input type="checkbox" ng-model="state.Checked" ng-change="checkIfWeCanSubmitThenSubmit()" id="ng-change-example1" />
So I'd be having ng-changes and ng-clicks all over my html form, hitting that function, where the function would look like this pseudocode:
$scope.checkIfWeCanSubmitThenSubmit= function() {
var validated = false;
//check to see if dropdown1 or dropdown2 are selected
//check to see if dropdown3 is selected
// add more here per requirement
//if the above are true, then validated = true
if (validated)
{
//add dropdown4 and 5, and checkbox groups into filter
}
submit();
}
But I was thinking this isn't the angular way of doing things since this certainly isn't facilitated.
I was hoping that the scope would offer some kind of way, where I can check to see what pieces of my scope is dirty or not before I can submit and fetch data, or if there is a better way than appending this function to every html element; like having some kind of scope tracker that I can check up on and watch.
Which reminds me, I don't want to have a series of $scope.$watch either, its just that it'd be way too much work to bind to every piece of html code, unless there's way to watch the scope of a collection of specific scope variables, then, I wouldn't mind.
like (forgive the pseudocode):
$scope.$watch('dropdown1, dropdown2, dropdown4', function(dirty, pristine)
{
if (dirty)
{ blah blah blah }
});
Edit (2/28/2013):
I tried doing it this way:
$scope.masterCriteria =
[
{ DropDown1: $scope.AppModel.Dropdown1},
{ DropDown2: $scope.AppModel.Dropdown2 },
{ DropDown3: $scope.AppModel.Dropdown3 },
{ Checkbox1: $scope.AppModel.Checkbox1 },
{ Checkbox2: $scope.AppModel.Checkbox2 }
];
$scope.$watch('masterCriteria', function (newVal) {
if (newVal) { logger.info("did I change?"); }
}, true);
The watcher detected nothing, and any values I changed to the scope of AppModel wasn't being picked up in the $watch. Was worth a try, still trying to figure this out.
You can slightly change your model and group fields related to input form together. Put them into single object. Like this:
$scope.state = { checkbox1: false, checkbox2: true, ... }
Later bind input boxes to field of state object:
<input ng-model="state.checkbox1" ... >
And watch state object to catch all updates of nested fields:
$scope.$watch('state', ...
JsFiddle example here

Backbone Validation with Backbone stickit - All attributes being validated when one is changed

I am attempting to use Backbone Validation with Backbone Stickit, I wish to validate one attribute at a time as the user enters them. However, when a user enters a value all attributes on the model get validated instead of just the one the user has changed. What am I doing wrong?
My View:
bindings:{
'#username' : {
observe:'username',
setOptions: {
validate:true
}
},
'#email' : {
observe:'email',
setOptions: {
validate:true
}
},
'#firstname' : {
observe:'firstName',
setOptions: {
validate:true
}
},
.......
onShow: function(){
Backbone.Validation.bind(this, {
valid: function(view, attr) {
alert('VALID - ' + attr);
},
invalid: function(view, attr, error) {
alert('INVALID - ' + attr);
}
});
this.stickit();
},
Everything you pass through setOptions is used when setting the value in the model (1). When you pass validate: true to the set function of a Backbone model it will validate the values in the model as well as the values passed to the set function (2) meaning it will validate the whole model every time you set a new value causing the problem you're seeing now. You're not doing anything wrong.
You could probably solve this by splitting up your validation into multiple separate functions and calling only the required ones on attribute change and then changing the validate function to call all those separate functions to validate the entire model.
This happened to me as well. In my case, I was setting default values in the model as '' (blank). Removed them and it worked
For this to work you should remove defaults (at least for the attributes your validating) values from your model
Try using the backbone.validation forceUpdate parameter on your backbone.stickit setOptions object in yout view bindings. That worked for me and I had a kind of similar problem.
Just like yousefcisco mentioned, backbone will validate all the attributes in the model on set or save, depending of your options passed, but in my case is not that I needed to validate each attribute separately, but the attributes didn't get set even if only one attribute was invalid, then I tried the forceUpdate: true, and it did its magic.
check it here: http://thedersen.com/projects/backbone-validation/#configuration/force-update

AngularJS - How to programmatically fire validation

I have a custom validation, for example, blacklisted. My model value and blacklisted array are the following:
model = "not_blacklisted_yet"
blacklisted = ["foo", "bar"]
I want to add "not_blacklisted_yet" to blacklisted, and to fire the validation programmatically. If I just add the element, the validation is not triggered because I have not changed the models viewValue.
How can I achieve this?
EDIT, atach plunker: http://plnkr.co/edit/L2sJY9VOJ7s8lKCm88sM?p=preview
I agree with what #Atrix1987 said in his comment. Your requirements need two entry points to trigger the said validation - one is when the form controller's modelValue changes and the other is when the blacklisted changes. The former has already been taken care of by the use of ui-validation, so that leaves us to deal with the latter scenario.
We want to trigger the validation whenever blacklisted changes, so we need to monitor it via the use of $watch. In your controller add the following:
$scope.$watch('blacklisted', function(content) {
if (content) {
$scope.form.model.$setValidity(
'blacklist',
$scope.notBlackListed($scope.form.model.$modelValue)
);
}
}, true);
Or here is the plunkr

How can I call validate on no change in Backbone?

Set data that will fail validation
Model.set({phoneNumber : 'meow meow'})
Validation that applies a border color
validate: function(attr){
if(attr.phoneNumber){
var phoneNumber = attr.phoneNumber,
regex = /^\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}/;
if(!regex.test(val)){
View.showError('businessNumber');
}
}
Later the user focus on the input field, I remove the error styling
The user doesn't change anything and the blur event is fired
Validation doesn't run because nothing changed.
Do not reference your view directly from your model. This is a completely deep and fundamental violation of the core tenet of the Model/View/* design. When you call set and validation fails, the model will emit an error event (as of Backbone 0.9.9) which your view should listen for and respond to by updating the view accordingly. You may also alternately pass a callback to set to handle the error, but events are the better choice in most situations. Note that your model needs to actually return an error object from validate, which will refuse to update the data, so after the user fixes the input and blur occurs, the data will actually change. With your code as is, Backbone thinks the validate call succeeded since no error is returned.
In your view, here's some pseudocode showing how to translate the model's error object into UI warnings:
initialize: function () {
_.bindAll(this);
this.model.on('error', this.showError);
},
showError: function (error) {
if (error.businessNumber) {
this.$businessNumber.addClass('error');
}
}
As a side note, don't feel bad about being confused with how to use backbone for forms. The fact that out of the box set won't accept invalid data is a huge stumbling block and non-intuitive. There are plugins to help with both forms and validation (https://github.com/documentcloud/backbone/wiki/Extensions,-Plugins,-Resources), but out of the box this is not one of the obvious/easy parts of backbone.

Resources