I have a input element which I am trying to name dynamically, but I had no luck so far using angular js.
neither
<input type="text" name="resource.Name" ng-model="resource.Value" ng-required="resource.IsRequired">
nor
<input type="text" name="{{resource.Name}}" ng-model="resource.Value" ng-required="resource.IsRequired">
works for me. When I try to access name attribute it always es back as resource.Name instead of the value it contains. The main reason I am trying to name this input control is validation, if user does not enter text in the field, I would like to tell them which textbox is required. If there is any angular directive I can use for that purpose I am ready to use them as well.
Can anyone tell me how to achieve this.
My validation function is as follows:
window.resourcesValidation = function ($scope, $rootScope, $alert) {
var subscriptions = $scope.scopeData.Subscriptions;
var isValidated = true;
if ($scope.resourceDataForm && $scope.resourceDataForm.$error && $scope.resourceDataForm.$error.required) {
var missingFields = [];
angular.forEach($scope.resourceDataForm.$error.required, function (value, key) {
isValidated = false;
missingFields.push("-" + value.$name);
});
$alert.error("Please fill in the all required fields.\r\n" + missingFields.join("\r\n"));
}
if (isValidated)
$scope.saveChanges(subscriptions);
return isValidated;
};
I have a input element which I am trying to name dynamically, but I had no luck so far using angular js.
neither
<input type="text" name="resource.Name" ng-model="resource.Value" ng-required="resource.IsRequired">
nor
<input type="text" name="{{resource.Name}}" ng-model="resource.Value" ng-required="resource.IsRequired">
works for me. When I try to access name attribute it always es back as resource.Name instead of the value it contains. The main reason I am trying to name this input control is validation, if user does not enter text in the field, I would like to tell them which textbox is required. If there is any angular directive I can use for that purpose I am ready to use them as well.
Can anyone tell me how to achieve this.
My validation function is as follows:
window.resourcesValidation = function ($scope, $rootScope, $alert) {
var subscriptions = $scope.scopeData.Subscriptions;
var isValidated = true;
if ($scope.resourceDataForm && $scope.resourceDataForm.$error && $scope.resourceDataForm.$error.required) {
var missingFields = [];
angular.forEach($scope.resourceDataForm.$error.required, function (value, key) {
isValidated = false;
missingFields.push("-" + value.$name);
});
$alert.error("Please fill in the all required fields.\r\n" + missingFields.join("\r\n"));
}
if (isValidated)
$scope.saveChanges(subscriptions);
return isValidated;
};
Share
Improve this question
edited May 25, 2014 at 14:37
erin c
asked May 25, 2014 at 14:17
erin cerin c
1,3552 gold badges21 silver badges39 bronze badges
4
- What does $scope.resourceDataForm look like? Any chance you can make a demo in plunker or something? – Jerrad Commented May 25, 2014 at 14:41
- Why are you putting resourcesValidation in a global function and not inside of a module's controller? – Josh Beam Commented May 25, 2014 at 14:49
-
Put a breakpoint in the resourcesValidation function and look at
$scope.resourceDataForm
. Is$scope.resourceDataForm.$error.required
an array? Do its items have a$name
property? Can you post what the entire object looks like? – Jerrad Commented May 25, 2014 at 15:23 - Yes Jerrad that's an array. first element has a $name property, which has the following value: {{subscriptionResource.Name}}, I think angularjs's ng-required validation uses name of the control before it is binded. – erin c Commented May 25, 2014 at 15:44
5 Answers
Reset to default 2Try this:
<input type="text" ng-attr-name="{{resource.Name}}" ng-model="resource.Value" ng-required="resource.IsRequired">
From the docs:
If an attribute with a binding is prefixed with the ngAttr prefix (denormalized as ng-attr-) then during the binding will be applied to the corresponding unprefixed attribute.
Although name="{{resource.Name}}"
should work in this case as well.
Update
I found a solution here: Dynamic validation and name in a form with AngularJS
Here's a plunker that I made.
Sounds like this issue may be fixed in Angular 1.3.
Quoting another answer on a very similar issue:
This happens because the control's name (the one with which it is registered on its parent form) is retrieved during the
ngModelController
's instantiation, which according to the docs takes place before the pre-linking phase* (so no interpolation yet).
In other words, validation relies on forms.$error
object, which is bound to the controls that are registered with that form.
A control's ngModelController
is responsible for registering a control with its parent form and it is instantiated at the pre-linking phase (when the name-expression is not interpolated yet).
This can be solved by a custom directive that manually registers the control with its parent form, but only after it's actual name is determined (after insterpolating the name-expression).
You can find the whole answer here.
Look for the UPDATE 2 section for a working solution.
(This is the link to the working demo.)
Can you show the rest of your code? (HTML, relevant controllers, etc.)
Sometimes the issue can center around asynchrony. For example, the HTML might be piled by Angular's piler before your $scope.resource
object gets its data (perhaps, with an AJAX call).
Two-way data binding sometimes doesn't always work how you would expect. Therefore, after "putting" your data into $scope.resource
with whatever function, you might need to call $scope.$apply()
.
<input ng-model="resource.model" name="{{resource.name}}" ng-required="{{resource.required}}"/>
seems to be working for me. Please see this plnkr .
I could not find the answer that satisfied some or all of these needs. This is what I came up with.
There may be a better way, so please share your thoughts.
I am using Angularjs 1.3.0-beta.8
I have a form with multi-nested directives that all contain input(s), select(s), etc... These elements are all enclosed in ng-repeats, and dynamic string values.
This is how to use the directive:
<form name="myFormName">
<nested directives of many levels>
ex: <input ng-repeat=(index, variable) in variables" type="text"
my-name="{{ variable.name + '/' + 'myFormName' }}"
ng-model="variable.name" required />
ex: <select ng-model="variable.name" ng-options="label in label in {{ variable.options }}"
my-name="{{ variable.name + '/' + 'myFormName' }}"
</select>
</form>
Note: you can add and index to the string concatenation if you need to serialize perhaps a table of inputs; which is what I did. However, dynamic name inputs means you may not know the name of the form input, so how would you call $scope.formName.??????. You could iterate of the $scope.formName object to get keys that match a certain value. That means string concatenation like this:
my-name="{{ dynamicString + hello + '/' + 'myFormName' }}"
Then in $scope.myFormName you would find any form input name by just iterating over the object and gathering any keys that included 'hello'.
app.directive('rsName', function(){
var rsNameError = "rsName directive error: "
return {
restrict:'A', // Declares an Attributes Directive.
require: 'ngModel', // ngModelController.
link: function( scope, elem, attrs, ngModel ){
if( !ngModel ){ return } // no ngModel exists for this element
// check rsName input for proper formatting ex. something/something
checkInputFormat(attrs);
var inputName = attrs.rsName.match('^\\w+').pop(); // match upto '/'
assignInputNameToInputModel(inputName, ngModel);
var formName = attrs.rsName.match('\\w+$').pop(); // match after '/'
findForm(formName, ngModel, scope);
} // end link
} // end return
function checkInputFormat(attrs){
if( !/\w\/\w/.test(attrs.rsName )){
throw rsNameError + "Formatting should be \"inputName/formName\" but is " + attrs.rsName
}
}
function assignInputNameToInputModel(inputName, ngModel){
ngModel.$name = inputName
}
function addInputNameToForm(formName, ngModel, scope){
scope[formName][ngModel.$name] = ngModel; return
}
function findForm(formName, ngModel, scope){
if( !scope ){ // ran out of scope before finding scope[formName]
throw rsNameError + "<Form> element named " + formName + " could not be found."
}
if( formName in scope){ // found scope[formName]
addInputNameToForm(formName, ngModel, scope)
return
}
findForm(formName, ngModel, scope.$parent) // recursively search through $parent scopes
}
});
This should handle many situations where you just don't know where the form will be. Or perhaps you have nested forms, but for some reason you want to attach this input name to two forms up? Well, just pass in the form name you want to attach the input name to.
What I wanted, was a way to assign dynamic values to inputs that I will never know, and then just call $scope.myFormName.$valid.
This may be an overkill, and a better solution exists in 1.3+. I couldn't find it in the time I had. This works for me now.
Good luck! Hope this helps someone!!!!