bvaughn / angular-form-for Goto Github PK
View Code? Open in Web Editor NEWSet of Angular directives to simplify creating and validating HTML forms.
Home Page: http://bvaughn.github.io/angular-form-for/
License: MIT License
Set of Angular directives to simplify creating and validating HTML forms.
Home Page: http://bvaughn.github.io/angular-form-for/
License: MIT License
I see then following error in the console, when I submit a form.
TypeError: Cannot read property 'then' of undefined
at $scope.validateAll.then.$scope.disable (http://localhost:8080/fw/form-for.js:372:24)
it appear the error is on this line:
promise.then(
function(response) {
// $scope.submitComplete is wrapped with a virtual function so we must check via attributes
if ($attributes.submitComplete) {
$scope.submitComplete({data: response});
} else {
I set up an angular page just as the gitHub page mentions along with the service js. I get this in the chrome console. I tried to see what I was doing wrong before asking a question but i am lost. Help please.
TypeError: Cannot read property 'email' of undefined
at setter (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:10841:23)
at token.fn.extend.assign (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:10296:18)
at Object.fn (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/node_modules/angular-form-for/dist/form-for.js:409:17)
at Scope.$digest (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:12434:29)
at Scope.$apply (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:12699:24)
at file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:1418:15
at Object.invoke (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:3917:17)
at doBootstrap (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:1416:14)
at bootstrap (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:1430:12)
at angularInit (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:1343:5) angular.js:9959
TypeError: Cannot read property 'password' of undefined
at setter (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:10841:23)
at token.fn.extend.assign (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:10296:18)
at Object.fn (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/node_modules/angular-form-for/dist/form-for.js:409:17)
at Scope.$digest (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:12434:29)
at Scope.$apply (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:12699:24)
at file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:1418:15
at Object.invoke (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:3917:17)
at doBootstrap (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:1416:14)
at bootstrap (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:1430:12)
at angularInit (file:///C:/inetpub/sites/workspace/pupav2/test/forms/formFor/angular.js:1343:5)
In IE 8, no matter what debounce options I set on a text field, it always behaves as if it's set to 0.
For our automated integration tests (using capybara), we are filling in values into fields. Capybara finds the inputs by CSS selectors by id or by name. Unfortunately it does not seem to by possible to specify names or ids for the inputs, they seem to be auto-genrated. Is there a specific reason for this or is this just a missing feature that has not been implemented yet?
On the formFor example at http://bvaughn.github.io/angular-form-for/#/demo/advanced-form there is a custom validation the determines if the email address is [email protected] and rejects with an error message if it is. This doesn't seem to be working here or on a similar fiddle http://jsfiddle.net/mcheever/bg234odu/
Not sure what is wrong. Thank you for any help.
Hi Again,
Is there any valid mechanism to update Labels after the form was loaded?
I´m using pascal precht angular-translate for the labels and they doesn´t update.
Maybe exposing a new method in the controller, like:
$scope.formController.reloadLabels();
Thanks for any comment.
Hi,
I realized that I can assign events to some fields, but no for all.
For input:text, input:check works perfectly, but not for select
Thanks!
This template is somewhat complex (~60 lines). It would be nice if users could customize the loading indicator used by select-field without having to fork such a large template.
If this indicator were split out into its own template, then a more focused override would be possible using $templateCache
.
The latest version has changed the styles of the input field - it is now half the width of the previous version and the label is higher up and no longer bold -image below: It was fine in the previous version and no other changes has been made other than update the 'form for' js and css file to 1.1.0.
<form form-for="organisation" service="organisationValidation">
<text-field label="Full name:"
attribute="name"
placeholder="Full name used by organisation"
help="Name used to describe your organisation">
</text-field>
<text-field label="Short name:"
attribute="shortName"
placeholder="Short name used by organisation"
help="Short Name used to describe your organisation">
</text-field>
When I add the autofocus
attribute to a text-field
I expect it to receive focus when the form loads but this doesn't happen.
<text-field autofocus label="Email" attribute="email" placeholder="[email protected]"></text-field>
Something like:
<form form-for submit-with="save(data)" validation-failed="warn()">
Where the custom warn() method would allow the user to display a "please check the form for errors" alert, highlight error fields, or whatnot. Ideally this would receive a parameter containing invalid fields?
Perhaps make the label optional? You could use underscore string to humanize the attribute (e.g. myVar > My Var or my_var > My Var). What do you think?
I use Browserify to require angular-form-for
. I got no errors when I included the module formFor
.
Now when I have in my view a simple form, it couldn't be rendered. No errors in the console. Nothing.
{{ user }} <!-- prints {} now -->
<form form-for="user" service="UserSignUp">
<text-field attribute="email"></text-field>
<text-field attribute="password" type="password"></text-field>
<submit-button label="Sign Up"></submit-button>
</form>
UserSignUp
service is defined, $scope.user
is set to {}
When you compress the JS code, it will not work because it will rename angular injectors. You need to annotate them. I suggest using https://github.com/olov/ng-annotate
I'd contribute to this if you like.
It'd be nice to be able to have custom messages when using true/false custom validation functions. I've made some additions that allows this in two ways:
if (rules.custom) {
try {
if (_.isFunction(rules.custom)) {
var returnValue = rules.custom(value, model);
if (_.isObject(returnValue) && _.isFunction(returnValue.then)) {
return returnValue.then(function(reason) {
return $q.resolve(reason);
}, function(reason) {
return $q.reject(reason
|| FormForConfiguration.validationFailedForCustomMessage);
});
} else if (returnValue) {
return $q.resolve(returnValue);
} else {
return $q.reject(FormForConfiguration.validationFailedForCustomMessage);
}
} else if (_.isObject(rules.custom)
&& _.isFunction(rules.custom.validationFunction)) {
var returnValue = rules.custom.validationFunction(value, model);
if (returnValue)
return $q.resolve(returnValue);
else
return $q.reject(_.isString(rules.custom.message) ? rules.custom.message
: FormForConfiguration.validationFailedForCustomMessage);
}
} catch (ex) {
var message = ex ? ex.toString() : null;
return $q.reject(message ? message
: FormForConfiguration.validationFailedForCustomMessage);
}
}
The developer can either have their validation function throw an exception and have a stringified version of that returned as the error-message, or they can supply the validation rule in the following format:
confirmPassword: {
custom: {
validationFunction: doPasswordsMatch,
message: "Passwords must match"
}
}
The select field will default the value to the first option if allow-blank is not set.
In my case, I don't want to allow blank to let user choose the blank option. But I also don't think form-for should select a default value. It should just display the placeholder in that case.
Hi,
I want to disable a text field conditionally to the value of another field (say a checkbox)
<text-field attribute="myAttribute" disable="{{myObject.myOtherAttribute !== 1}}">
</text-field>
The problem is that the disable attribute is a one way binding and it doesn't toggle to the enabled/disabled state as expected.
Is there a different way to have this behavior ?
Why not making a two way binding for the disable attribute ?
Hey,
Nice work ! It makes my form templates much more readable !
I think these templates would be even more maintainable if we could define a html string in configuration that would be automatically appended to all required field labels
What do you think ?
Many thanks !
It seems like the skeleton code shown for creating a custom field needs updating since disabledByForm
is gone and FieldHelper.manageFieldRegistration()
is now preferred to calling formForController.registerFormField()
directly.
EDIT: I just realized that FieldHelper
is not currently exposed to users. IMHO it is so useful that it should be so I've created issue #43.
This would be a nice addition to the module!
I'm adding the focus
attribute to a text-field
and am specifying a function to call but this isn't happening.
Controller
$scope.clearErrors = function () {
$scope.loginError = null
}
Form
<text-field label="Email" attribute="email" placeholder="[email protected]"
focus="clearErrors()" autofocus></text-field>
I get a empty white page with the top bar only.
I think theres a issue with the script import
This can be reproduced using the example sign-up form here:
http://bvaughn.github.io/angular-form-for/
Once a field has been modified (dirtied) then clearing errors doesn't affect it.
In a select field, clicking on the label or help icon opens the select dropdown. If you are to following the html select field, I should just focus on the select box instead of opening it. But I think not doing anything is also fine.
I was wondering if I can set validation for some fields without requiring it...
For example, 'age' is optional field, but it must be an integer if value exists.
age: {
type: 'integer'
}
In the current implementation adding any validation rule will add "somehow" required
rule.
I think I've identified a problem with type-ahead-field. If the field that it's bound to already has a value when the form is shown then I'd expect it to look up the value in its options array and display the related label. Instead it seems to clear the field.
Please take a look this plunk. Notice that formData is pre-populated as follows:
$scope.formData = {
typeAheadLanguage: 'en',
dummy: 'en'
};
The second two fields on the form are plain input elements whose values are set using jQuery. Their values should both be 'en'. Instead the one that's showing the value of the field that's bound to the type-ahead-field - is blank. If you change the value of the type-ahead-field you'll notice that it changes the one labelled 'formData.typeAheadLanguage' as it should, but it doesn't initialize properly.
Hello. I'm using the latest version (1.2.16) and I got this error:
Controller 'formFor', required by directive 'textField', can't be found!
Sample HTML:
<form form-for="quote" service="Quote">
<text-field label="Title" attribute="title"></text-field>
</form>
Loading:
angular.module('testApp', ['formFor']);
Is this a bug, or am I missing something?
This looks promising.
It was giving errors. It was obvious that it needed lodash. This dependency is not documented in the install. Why the lodash dependency? I didn't took a look a the code yet. Would it be easy?
It would be nice to have a field-error directive like the field-label so I can override the errors all at once instead of having to override individual templates.
Hi Brian,
I previously had the directive below that converts US numbers into French one
.directive('smartFloat', function($filter) {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {t
ctrl.$parsers.unshift(function(viewValue) {
return viewValue.replace(',', '.');
});
ctrl.$formatters.unshift(function(modelValue) {
return $filter('number')(modelValue);
});
}
};
})
The problem is that I can't use this directive with my new text-field anymore, because ngModel is required
The only solution I came up with is to create a new directive based on textField (actually it's a copy/paste ... apparently it is not possible to inherit directives ) with a new template (also copy/pasted from the text-field template ...) where I can put my directive on the input
It is not very elegant nor maintainable, do you have another way to do that ?
Thanks !
Hi Brian,
Very nice work. The ability to write our own types of form fields is a big plus.
Just wondering if you have played with Google's Polymer objects, and if there is a way to make bi-directional data flow from these in/out of a form field with your solution ?
The few attempts to "glue" together Polymer with AngularJS have not worked out so well. Would be nice to create forms with Polymer's tools, which then can work seamlessly with AngularJS.
First check is rules.custom is actually a function, then wrap the result in $q.when in case it's not a promise.
if (_.isFunction(rules.custom)) {
return $q.when(
rules.custom(value, model),
function(reason) {
return $q.resolve(reason);
},
function(reason) {
return $q.reject(reason || FormForConfiguration.validationFailedForCustomMessage);
});
}
Hey,
I want to disable a form based on the value of an attribute but it doesn't seem to work
Here's the plunker : http://plnkr.co/edit/l28sCabqBHzqmjVbR6uZ?p=preview
I think that the fields are not yet registered when the watcher tied to the disable attribute fire for the first time (it works when the attribute changes afterwards)
Thanks
Have you thought about removing the custom styling? Most people would probably be using bootstrap, so there's really little need for any custom CSS? Field styles, help text, errors are all available in bootstrap.
Having custom CSS normally makes it a bit more difficult to fit into peoples asset pipeline / deployment, even with bower. For example, you use styl whereas I use sass.
Hi Brian,
I'm really liking formFor, but am running into a small problem. I have some nested properties on the model bound via form-for="modelName", but I can't find any obvious way to connect these to validation objects. I've also looked at the NestedObjectHelper reference and implementation to see if I could figure it out, but so far no luck.
Here's a simplified example of my form:
<form class="signup-form"
ng-switch="section"
form-for="newUser"
validation-rules="validationRules"
submit-with="submit(data)">
<text-field label="Email address"
attribute="credentials.userName"></text-field>
<text-field label="New password"
attribute="credentials.password"
type="password"></text-field>
<text-field label="First Name"
attribute="firstName"></text-field>
<text-field label="Last Name"
attribute="lastName"></text-field>
<submit-button label="Sign Up"></submit-button>
</form>
In my validationRules object I've tried various things unsuccessfully, including:
$scope.validationRules = {
credentials: {
email: { required: true },
password: { required: true }
},
firstName: { required: true },
lastName: { required: true }
};
and
$scope.validationRules = {
'credentials.email': { required: true },
'credentials.password': { required: true },
firstName: { required: true },
lastName: { required: true }
};
I would appreciate any pointers - or fresh documentation - you can provide on this.
cheers,
-stuart
Hello,
I have a problem with some radio field that is not correctly checked, see the code below:
<div>
<radio-field attribute="type.id" label="{{database.name}}" value="{{database.id}}" ng-repeat="database in databases"></radio-field>
</div>
type.id is an integer and in the file directives/radio-field.js at line 87, newValue is an integer whereas $scope.value is a string and the condition fails. (with == instead of === the radio is correctly checked)
Am I doing something wrong ?
Is there a way to prevent (other than modifying the rule set) validation from running if a text field is hidden? Currently if you have a text field that is required but hidden it will still not let you submit if it has no value.
Not sure what the best way to do this is at the moment. Would be nice to be able to simply trigger validation on all fields, with an appropriate success / failure callback.
A good example is a publishing workflow, where you have a saveDraft() that is your actual submit-with handler, but in your publish() function, called from a separate button on the form, you first want to ensure that the form is valid and then either publish an article or warn the user as appropriate.
I have two field newPassword and newPasswordMatch. And here's what my validation rules look like:
newPassword: {
required: {
rule: true,
message: 'error_password_field_empty'
},
minlength: {
rule: 6,
message: 'error_password_too_short'
}
},
newPasswordMatch: {
required: {
rule: true,
message: 'error_password_field_empty'
},
custom: function(value, model) {
if (model.newPassword.length < 6 && value.length < 6) {
return $q.reject('error_password_too_short');
} else if (value !== model.newPassword) {
return $q.reject('error_passwords_dont_match');
} else {
return $q.resolve(value);
}
}
}
The problem is if user entered newPassword and newPasswordMatch, and then went back to change newPassword again, form-for doesn't validate newPasswordMatch at this time and the error is not updated.
Is there a way to dynamically update the rule set? I need to be able to turn on/off a field being required.
Thanks
Allow an autofocus attribute on the text-input directive. If autofocus is set, the input is focused after directive is linked.
Hi - Sorry to report a bug!
I am trying to extend the sign up example to actually getting it to log into a real server. However a error (see below) is being generated when the submit function is called I think this might be because you cannot inject a service with the $scope property:
code use:
app.service('UserSignIn', function($rootScope, httpi, $location) {
var login = httpi.resource("api/login/( :listCommand | :id/:itemCommand )");
return {
validationRules: {
email: {
required: true,
pattern: /\w+@\w+\.\w+/
},
password: {
required: true,
pattern: {
rule: /[0-9]/,
message: 'Your password must contain at least 1 number'
}
}
},
submit: function(data) {
login.post({data: {email: data.email, password: data.password}})
.then(function(user) {
$rootScope.currentUser = user.data;
$location.path('/home');
});
}
};
});
error reported:
TypeError: Cannot read property 'then' of undefined
at $scope.validateAll.then.$scope.disable (http://localhost:8080/vendor/form-for.js:363:24)
at wrappedCallback (http://localhost:8080/vendor/angular.js:11506:81)
at http://localhost:8080/vendor/angular.js:11592:26
at Scope.$eval (http://localhost:8080/vendor/angular.js:12683:28)
at Scope.$digest (http://localhost:8080/vendor/angular.js:12487:31)
at http://localhost:8080/vendor/angular.js:12721:26
at completeOutstandingRequest (http://localhost:8080/vendor/angular.js:4474:10)
at http://localhost:8080/vendor/angular.js:4775:7
I would like to change the icon-before or icon-after icon to a check mark icon or something when the field is validated.
formFor should support attributes that contain collections of items. Validation should be possible on the collection as a whole as well as on individual items.
ngForm supports collections with the following syntax:
<form>
<label>My name</label>
<input type="text" ng-model="formData.name">
<label>My things</label>
<ul>
<li ng-repeat="thing in formData.things">
<!-- Items are wrapped with inner ngForms -->
<ng-form name="thingForm">
<input type="text" ng-model="thing.description">
</ng-form>
</li>
</ul>
</form>
formFor HTML might look like this for the case of collections:
<form form-for="formData" validation-rules="validationRules">
<text-field label="name" attribute="name"></text-field>
<label>My things</label>
<!-- Wrap collections with a formForCollection -->
<ul>
<li ng-repeat="thing in formData.things"
form-for="things" validation-rules="thingValidationRules">
<text-field attribute="description"></text-field>
</li>
</ul>
</form>
Validation rules for top-level object may look like this:
$scope.validationRules = {
name: {
required: true
},
things: {
// Signifies that 'things' is a validatable collection
collection: {
min: 1, // Require at least 1 'thing'
max: 4, // Allow no more than 4 'things'
}
}
};
And validation rules for individual items within the collection might then look something like this:
$scope.thingValidationRules = {
description: {
required: true,
minlength: 10
}
};
formFor HTML might look like this for the case of collections:
<form form-for="formData" validation-rules="validationRules">
<text-field label="name" attribute="name"></text-field>
<label>My things</label>
<ul>
<li ng-repeat="thing in formData.things">
<!-- The bracket syntax notifies formFor that 'things' is a collection -->
<text-field attribute="things[].description"></text-field>
</li>
</ul>
</form>
Validation rules would then look like:
$scope.validationRules = {
name: {
required: true
},
things: {
// The 'collections' attribute signifies that 'things' is a validatable collection
// Collections support custom validation rules
collection: {
min: 1, // Require at least 1 'thing'
max: 4, // Allow no more than 4 'things'
// Validation rules for individual 'thing' objects go inside of 'fields'
// All formFor validation types are supported here
fields: {
description: {
required: true,
minlength: 10
}
}
}
}
};
Would the icons benefit from being able to be linked to some action - i.e. change the data in the input field or open some extra function - an example would be the http://angular-ui.github.io/bootstrap/ date picker where the icon is used to enter a date in the field.
Please vote - yes or no
Is there some way how to submit form with button which is outside form?
General example:
<div class='wrapper'>
<form></form>
<button ng-click='submit()'>Save form above</button>
</div>
I especially need to trigger validation and show validation messages. I saw your implementation of manual validation, but it doesn't show validation messages.
The demo here seems to exhibit this problem:
http://bvaughn.github.io/angular-form-for/#/demo/collections
To reproduce: Add a couple fields, fill them out, submit to validate. Now remove one or more fields, and try to resubmit / revalidate. Looks like the references are never removed from the mapping, and therefore the form is invalid, but no errors are actually highlighted because the fields aren't visible.
FieldHelper
is so incredibly useful that it should be exposed via the formFor directive's scope so that people creating custom fields can inject formForFieldHelper
and use getLabel()
and manageFieldRegistration()
.
Menus should not drop outside of the visible range of the window.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.