Validate a field from a directive in AngularJS - javascript

I am trying to wrap an input and some markup into an AngularJS directive.
However the fields are supposedly always validated which they shouldn't be.
Please check out my example # http://plnkr.co/edit/TivmuqQI4Y5K56gwcadW
here is the code for those who do not wish to look at Plunker
my directive
app.directive('myInput', function() {
return {
restrict: 'E',
require: '^ngModel',
templateUrl: 'form_control.html',
scope: {
label: '#',
placeholder: '#',
name: '#',
form: '=',
ngModel: '=ngModel'
},
}
});
this is my template
<div class="form-group" ng-class="{'has-error': form.{{name}}.$invalid && form.{{name}}.$dirty, 'has-success': form.{{name}}.$valid }">
<label for="{{name}}" class="col-sm-2 control-label">{{label}}</label>
<div class="col-sm-10">
<input type="{{type}}" class="form-control col-sm-10" id="{{name}}" name="{{name}}" ng-model="ngModel" placeholder="{{placeholder}}" ng-maxlength="10" ng-required="true">
</div>
</div>
and this is in my index.html
<my-input ng-model="website.url" name="url" label="URL" placeholder="http://example.com" form="form"></my-input>
Even though the input inside the template is required, the field is validated, which it shouldn't be if it's empty.
What am I doing wrong?

Required fields are immediately invalid on DOM load, as they are not valid until they have a value.
Also, in your plunker the top input is green, with an illusion of valid while the lower input is red showing invalid as it should.
You can't do this...
<div class="form-group" ng-class="{'has-error': form.{{name}}.$invalid && form.{{name}}.$dirty, 'has-success': form.{{name}}.$valid }">
The issue is with the form name field. When you do this...
<input type="{{type}}" class="form-control col-sm-10" id="{{name}}" name="{{name}}" ng-model="ngModel" placeholder="{{placeholder}}" ng-maxlength="10" ng-required="true">
name="{{name}} will actually compile to name: {{name}} in the form object. exmaple:
{{name}}: Constructor$dirty: false
$error: Object
$formatters: Array[1]
$invalid: true
$isEmpty: function (value) {
$modelValue: undefined
$name: "{{name}}"
$parsers: Array[1]...
This was taken from your plunker. Play around with console.log($scope.form) and look at the object.
under $error you will find that there are two inputs THIS form references, and neither of them are the expected input named 'url', they are in fact the 'title' input and your directive input '{{name}}' as seen here...
form: Constructor
$addControl: function (control) {
$dirty: false
$error: Object...
$name: "title"...
$name: "{{name}}"
Here is a forked plunker where I have already set up to console.log the form
Plunker
This shows that the form has no idea about any 'url' input. To get around this, you can write a custom directive for the input name field. Or just use the one I wrote below.
app.directive('myName', function(){
var myNameError = "myName directive error: "
return {
restrict:'A', // Declares an Attributes Directive.
require: 'ngModel', // ngModelController.
link: function( scope, elem, attrs, ngModel ){
if( !ngModel ){ return } // if no ngModel exists for this element
checkInputFormat(attrs); // check myName input for proper formatting.
var inputName = attrs.myName.match('^\\w+').pop(); // match upto '/'
assignInputNameToInputModel(inputName, ngModel);
var formName = attrs.myName.match('\\w+$').pop(); // match after '/'
findForm(formName, ngModel, scope);
} // end link
} // end return
function checkInputFormat(attrs){
if( !/\w\/\w/.test(attrs.myName )){ // should be in format "wordcharacters/wordcharacters"
throw myNameError + "Formatting should be \"inputName/formName\" but is " + attrs.myName
}
}
function assignInputNameToInputModel(inputName, ngModel){
ngModel.$name = inputName // adds string to ngModel.$name variable.
}
function addInputNameToForm(formName, ngModel, scope){
scope[formName][ngModel.$name] = ngModel; return // add input name and input object.
}
function findForm(formName, ngModel, scope){
if( !scope ){ // ran out of scope before finding scope[formName]
throw myNameError + "<Form name=" + formName + "'> element 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
}
});
// DIRECTIVE NOTES:
// This directive is used by simply including the following HTML element:
// <input my-name="email/profileForm">.
// In the example above, the input name is "email" and the form name
// that this input would be attached to would be named "profileForm"
// Like this...
// <form name="profileForm">
// <input my-name="email/profileForm">
// </form>
// Notice this "/" dividing the input name from the form name. This directive uses the '/'
// to separate the input name from the form name.
// Although it has not been tested yet, this directive should work with multi nested forms
// as well, as the recursive search only looks for the form name that was passed in, inwhich
// to bind the ngModel to.
// In this example, other form names would be skipped.
// <form name="profileForm">
// <form name="miniFormOne">
// <form name="miniFormTwo">
// <input my-name="email/profileForm">
// </form>
// </form>
// </form>
// The above example may not be the best behavior, but was just added as an example.
With this directive, you could use your nested directive input like this
<input type="{{type}}" class="form-control col-sm-10" id="{{name}}" my-name="{{ variableName + '/' + yourformnamevariable }}" ng-model="ngModel" placeholder="{{placeholder}}" ng-maxlength="10" ng-required="true">
The myName directive will get this: "url/form" in your case, then it will add the $name variable which will be 'url' to the ngModel for THAT input, as well as search up scope for the form named "form" and attach the ndModel to THAT form. The directive uses the '/' to separate names. The search is recursive and will travel until it finds the form name or error out with a message.
Of course when you create dynamic input names, how are you to call out
formName.dynamicInputName.$valid? as you don't know what the dynamic input names ARE!!!
So using form.{{name}}.$invalid && form.{{name}}.$dirty doesn't work unless you do this...
form.$valid && form.$dirty
But that won't work for each individual input. You can figure out your own way to do that...
I use another directive inside the input
Then in my-errors I just listen to the ngModel like after requiring ngModel, you can now call ngModel.$invalid then set a variable to change the CSS. If I get some time, I'll make a jsFiddle and link it here at the bottom. However, you can just use the class input.ng-invalid { border-color: red; } and the inputs will be red until they are valid.
If this doesn't clear things up, ask some more questions... We'll get it.
Hope this helpy's

Related

Angularjs server side validation of multiple parameters

I have made an attempt to create a custom validation directive to validate two items simultaneously at server side.
I have two values regNumber and regDate that have to be validated along with each other. So when user enters both of them correctly,they are validate. But, if one of them is entered incorrectly, they both have to be invalidated.
To accomplish the goal, I have written a the following directive base on this post.
Everything is working fine except When I enter both together regNumber and regDate incorrectly. Then, even If I change them both to correct values, still they are invalidated.
By "Everythin is working fine" I mean when I enter an invalid value for regNumber and a valid value for regDate, and change the regNumber back to a valid value, it works fine and vice versa(first regDate and then regNumber).
I think $setValidatity will be set for the latest input which has been changed and not for both of them but even if my guess is true, I don't know how to solve it. :D
Directive:
osiApp.directive('uniqueOrder', function ($http, $rootScope) {
var toId;
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attr, ctrl) {
scope.$watch(attr.ngModel, function (value) {
if (scope.osiRequest.regDate) {
ctrl.$setValidity('uniqueOrder', true);
if (toId) clearTimeout(toId);
toId = setTimeout(function () {
$http({
method: 'GET',
url: $rootScope.baseAddress + '/ValidateOrderRegistrationNumber/Get',
params: {
orderRegistrationDate: scope.osiRequest.regDate ,
orderRegistrationNumber: scope.osiRequest.regNumber
}
}).success(function (isValid) {
ctrl.$setValidity('uniqueOrder', isValid);
});
}, 200);
}
});
}
}
});
HTML:
<div class="form-group" ng-class="myForm.regNumber.$error.uniqueOrder ||
myForm.regDate.$error.uniqueOrder ? 'has-error' : ''">
<input class="form-control"
name="regNumber" ng-model="osiRequest.regNumber" unique-order>
</div>
<div class="form-group" ng-class="myForm.regNumber.$error.uniqueOrder ||
myForm.regDate.$error.uniqueOrder ? 'has-error' : ''">
<input class="form-control"
name="regDate" ng-model="osiRequest.regDate " unique-order>
</div>
As mentioned by #NicolasMoise you have to be able to access both model in your directive, few ways to achieve this :
Adding both ng-model osiRequest.regDate & osiRequest.regNumber as your directive attributes unique-order. Check "scope" parameter for directive.
Access parent controller scope from directive by using $parent ( not ideal )

AngularJS Multiple directives asking for ngModel

Here's a jsfiddle example of what I'm trying to accomplish.
I'm trying to build a US phone number input where the view displays as (333) 555-1212, but the model binds to the numeric integer 3335551212.
My intention is to add custom validators to NgModelController which is why I have require: ng-model; there are simpler solutions without the isolate scope and NgModelController, but I need both.
You'll see an immediate error in the console: Error: Multiple directives [ngModel, ngModel] asking for 'ngModel' controller on: <input ng-model="user.mobile numeric" name="telephone" type="tel"> -- thought I was using an isolate scope here...
Thank you for looking #mimir137 but I appear to have solved it:
http://jsfiddle.net/hr121r18/8/
The directive was using replace: true, which ends up with this structure:
<form ng-controller="FooCtrl" class="ng-scope">
<p>Enter US phone number</p>
<input ng-model="user.mobile numeric" name="telephone" type="tel">
</form>
Both the template and the markup called for ng-model which led to the symptomatic error in the problem description. Once I removed that, it leads to this markup (note the wrapper element phone-number):
<form ng-controller="FooCtrl" class="ng-valid ng-scope ng-dirty ng-valid-parse" abineguid="BC0D9644F7434BBF80094FF6ABDF4418">
<p>Enter US phone number</p>
<phone-number ng-model="user.mobile" class="ng-untouched ng-valid ng-isolate-scope ng-dirty ng-valid-parse">
<input ng-model="numeric" name="telephone" type="tel" class="ng-valid ng-dirty ng-touched">
</phone-number>
</form>
But removing this required changes to $render; the elem passed into the link function is now phone-number and so you need to dig to grab the input inside it and set the value on that:
ngModel.$render = function () {
elem.find('input').val($filter('phonenumber')(ngModel.$viewValue));
};
There were a few other issues. $render() also needed to be called from the watcher.
Final:
var app = angular.module('myApp', []);
// i want to bind user.mobile to the numeric version of the number, e.g. 3335551212, but
// display it in a formatted version of a us phone number (333) 555-1212
// i am trying to make the directive's scope.numeric to have two-way binding with the controller's
// $scope.user.mobile (using isolate scope, etc.).
app.controller('FooCtrl', function ($scope) {
$scope.user = {
mobile: 3335551212
};
});
app.directive('phoneNumber', ['$filter', function ($filter) {
return {
restrict: 'E',
template: '<input ng-model="numeric" name="telephone" type="tel">',
require: 'ngModel',
scope: {
numeric: '=ngModel'
},
link: function (scope, elem, attrs, ngModel) {
// update $viewValue on model change
scope.$watch('numeric', function () {
ngModel.$setViewValue(scope.numeric);
ngModel.$render();
});
// $modelValue convert to $viewValue as (999) 999-9999
ngModel.$formatters.push(function (modelValue) {
return $filter('phonenumber')(String(modelValue).replace(/[^0-9]+/, ''));
});
// $viewValue back to model
ngModel.$parsers.push(function (viewValue) {
var n = viewValue;
if (angular.isString(n)) {
n = parseInt(n.replace(/[^0-9]+/g, ''));
}
return n;
});
// render $viewValue through filter
ngModel.$render = function () {
elem.find('input').val($filter('phonenumber')(ngModel.$viewValue));
};
}
};
}]);
app.filter('phonenumber', function () {
return function (number) {
if (!number) {
return '';
}
number = String(number);
var formattedNumber = number;
var c = (number[0] === '1') ? '1 ' : '';
number = number[0] === '1' ? number.slice(1) : number;
var area = number.substring(0, 3),
exchange = number.substring(3, 6),
subscriber = number.substring(6, 10);
if (exchange) {
formattedNumber = (c + '(' + area + ') ' + exchange);
}
if (subscriber) {
formattedNumber += ('-' + subscriber);
}
return formattedNumber;
}
});
HTML
<form ng-controller="FooCtrl">
<p>Enter US phone number</p>
<phone-number ng-model='user.mobile'></phone-number>
</form>
I created this fiddle that gets rid of most of your errors coming up in the console. Hopefully this will at least be able to put you on the right track.
I changed the template so that you can see that the filter is actually working.
It now has the typical {{ngModel | FilterName}} in plain text underneath the textbox.
The only real issue is displaying it in the textbox. I'm sure you will have no problem with that. I will check in the morning just in case you still have questions regarding this.
Edit: Alright it appears you have solved it already. Great job!

Dynamic form name attribute <input type="text" name="{{ variable-name }}" /> in Angularjs

How would someone use formName.inputName.$valid when the "inputName" was dynamically created?
<form name="formName">
<input ng-repeat="(variable) in variables"
type="text" name="variable.name"
ng-model="variable.name" required />
</form>
The output of the HTML input attribute 'name' would be the string "variablename", which would applied to ALL repeated inputs.
If we tried this
<form name="formName">
<input ng-repeat="(variable) in variables"
type="text" name="{{ variable.name }}"
ng-model="variable.name" required />
</form>
The output of the HTML input attribute 'name' would be the string"{{ variable.name }}", which would be applied to ALL repeated inputs.
In either of these two conditions, a name attribute for each of the repeated input elements would not be created dynamically; ALL inputs would share the same input name. Not much good if you wanted to call a specific input based on a specific name.
need to use dynamic name values
need to be able to call $scope.formName.dynamicName.$valid
need to be able to call $scope.formName.$valid
need dynamic name input fields to be added to nested form, or master form
Looks like Angular 1.3 fixed this (https://stackoverflow.com/a/32907176/3854385)
This is now possible with Angular 1.3+:
<form name="vm.myForm" novalidate>
<div ng-repeat="p in vm.persons">
<input type="text" name="person_{{$index}}" ng-model="p" required>
<span ng-show="vm.myForm['person_' + $index].$invalid">Enter a name</span>
</div>
</form>
Demo
In some cases an inner form is a good solution if you can just pass the information: (https://stackoverflow.com/posts/12044600/)
To solve the 'dynamic name' problem you need to create an inner form (see ng-form):
<div ng-repeat="social in formData.socials">
<ng-form name="urlForm">
<input type="url" name="socialUrl" ng-model="social.url">
<span class="alert error" ng-show="urlForm.socialUrl.$error.url">URL error</span>
<button ng-click="doSomething(urlForm.socialUrl.$valid)">Test</button>
</ng-form>
</div>
The other alternative would be to write a custom directive for this.
Here is the jsFiddle showing the usage of the ngForm: http://jsfiddle.net/pkozlowski_opensource/XK2ZT/2/
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('myName', function(){
var myNameError = "myName 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 myName input for proper formatting ex. something/something
checkInputFormat(attrs);
var inputName = attrs.myName.match('^\\w+').pop(); // match upto '/'
assignInputNameToInputModel(inputName, ngModel);
var formName = attrs.myName.match('\\w+$').pop(); // match after '/'
findForm(formName, ngModel, scope);
} // end link
} // end return
function checkInputFormat(attrs){
if( !/\w\/\w/.test(attrs.rsName )){
throw myNameError + "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 myNameError + "<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!!!!
work for me with angular 1.2.7
directive:
var DynamicName = function() {
return {
restrict: 'A',
priority: -1,
require: ['ngModel'],
link: function (scope, element, attr, ngModel) {
ngModel[0].$name = attr.name;
}
};
};
app.directive('dynamicName', DynamicName);
howtouse:
<div ng-repeat="phone in hrModel.phones">
<input type="text"
name="phones[{{$index}}]"
ng-model="phones[$index]"
dynamic-name
/>
</div>
Don't forget that you can access javascript objects using array notation with string indexes. Given the following arbitrary form definition object :
$scope.form_def = {
form_name : 'BallForm',
variables : [
height : { name : 'Height', type : 'text' },
width : { name : 'Width', type : 'text' },
color : { name : 'Color', type : 'multi', options : ['red', 'green', 'blue'] }
]
};
$scope.form_values = {};
... and the html snippet ...
<form name="{{ form_def.form_name }}">
<div ng-repeat="variable in form_def.variables">
<input ng-if="variable.type==='text'" type="text" name="{{ variable.name }}" ng-model="form_values[variable.name]">
<select ng-if="variable.type==='multi'" name="{{ variable.name }}" ng-model="form_values[variable.name]">
<option ng-repeat="opt in variable.options" value="{{ opt }}">{{ opt }}</option>
</select>
</div>
</form>
Inside the controller you then would have a nice form_values object for every field which you can access by iterating over the keys in the form_def.variables hash.
There is a lot more involved once you get down into writing these sort of generic form processing scripts and you end up with a hell of a lot of spaghetti code in my opinion and you would probably be better of going with a less general solution, but thats another SO question.

Angular : Adding Attribute directive on Element Directive

For my project, i'm currently developping custom form / inputs directive.
For example, I have the following directive :
angular.module('myApp').directive("textField", function() {
return {
restrict: 'E',
replace: true,
templateUrl : "/common/tpl/form/text-field.html",
scope : {
label : "#",
model : "="
}
};
});
with the associated template :
<div class="form-group">
<label for="{{fieldId}}" class="col-lg-2 control-label">{{label |translate}}</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="{{fieldId}}" ng-model="model" placeholder="{{label|translate}}">
</div>
</div>
I have many more custom fields ( date, select, double select, and so on... )
The usage is simple :
<text-field label="app.myLabel" model="myObj.myAttribute"></text-field>
The idea is to cleanup the main template by avoiding to verbosely add labels on every fields. Very common need i believe.
Now the problem :
Now I need to add custom validation to my input models.
I did a naive approach which was to create a validation directive :
directive('myValidation', function (){
return {
require: 'ngModel',
link: function(scope, elem, attr, ngModel) {
ngModel.$parsers.unshift(function (value) {
// do some validation
return value;
});
}
};
});
and then to use it like this :
<text-field label="app.myLabel" model="myObj.myAttribute" myValidation="validationOptions"></text-field>
But of course this doesnt work, simple because the text-field directive which is replace=true "erases" the validation directive on it's element.
Can someone tell one what is the correct approach to do "custom input with presentation" directive, while allowing the validation part to be declared on the directive ( here text-field ) and used on the directive's input ?
Per example, is there a way to say "attributes on my element directive will be 'copied' to inside my directive ?"
aka :
<text-field label="app.myLabel" model="myObj.myAttribute" **myValidation="validationOptions"**></text-field>
would result in :
<div class="form-group">
<label for="{{fieldId}}" class="col-lg-2 control-label">{{label |translate}}</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="{{fieldId}}" ng-model="model" **myValidation="validationOptions"** placeholder="{{label|translate}}">
</div>
</div>
Or am I simply missing something ?
I would like to avoid using transclusion to resolve this issue, because this would oblige the form template to look like this :
<field label="myLabel">
<input type="text" class="form-control" id="{{fieldId}}" ng-model="model" placeholder= {{label|translate}}">
</field>
which is just uselessly verbose in my opinion. But i'm starting to ask myself if there really is another option ?
Maybe the trick can be done in the pre (or post ?) directve link function, where I would copy attributes/ directive from the text-field tag to it's child (input) tag ?
Could someone just light the way for me there ?
Could you try this:
Write a validate directive. This will have a controller that exposes an addValidationFunction(fn) and a getValidationFunction() methods.
Have the myValidation directive require the validate controller and call ctrl.addValidationFunction(myValidationImplementation) where myValidationImplementation is a function implementing the validation logic for this specific directive.
Write another directive, validateInner. This will require optionally the validate controller from its parent. This directive will also require the ngModel controller. If it finds the validate controller, it calls ctrl.getValidationFunction() and registers the function with the ngModel i.e.:
require: ["^?validate", "ngModel"],
link: function(scope,el,attrs,ctrls) {
if( ctrls[0] != null ) {
var validationFn = ctrls[0].getValidationFunction();
// register validationFn with ngModel = ctrls[1]
}
...
}
In the template of your textField:
<input validate-inner type="text" class="form-control" id="{{fieldId}}" ng-model="model" placeholder="{{label|translate}}">
Usage:
<text-field label="app.myLabel" model="myObj.myAttribute"
validate my-validation="validationOptions"></text-field>
NOTE 1: I am not sure if a replace:true directive wipes the other directives. If so, it is not consistent behaviour.
NOTE 2: The myValidation directive gets called as <xxx my-validation> (note camelCase → dash-case). If your code above is not a typo, then this is why <text-field> seems to wipe myValidation.

AngularJS does not send hidden field value

For a specific use case I have to submit a single form the "old way". Means, I use a form with action="". The response is streamed, so I am not reloading the page. I am completely aware that a typical AngularJS app would not submit a form that way, but so far I have no other choice.
That said, i tried to populate some hidden fields from Angular:
<input type="hidden" name="someData" ng-model="data" /> {{data}}
Please note, the correct value in data is shown.
The form looks like a standard form:
<form id="aaa" name="aaa" action="/reports/aaa.html" method="post">
...
<input type="submit" value="Export" />
</form>
If I hit submit, no value is sent to the server. If I change the input field to type "text" it works as expected. My assumption is the hidden field is not really populated, while the text field actually is shown due two-way-binding.
Any ideas how I can submit a hidden field populated by AngularJS?
You cannot use double binding with hidden field.
The solution is to use brackets :
<input type="hidden" name="someData" value="{{data}}" /> {{data}}
EDIT : See this thread on github : https://github.com/angular/angular.js/pull/2574
EDIT:
Since Angular 1.2, you can use 'ng-value' directive to bind an expression to the value attribute of input. This directive should be used with input radio or checkbox but works well with hidden input.
Here is the solution using ng-value:
<input type="hidden" name="someData" ng-value="data" />
Here is a fiddle using ng-value with an hidden input: http://jsfiddle.net/6SD9N
You can always use a type=text and display:none; since Angular ignores hidden elements. As OP says, normally you wouldn't do this, but this seems like a special case.
<input type="text" name="someData" ng-model="data" style="display: none;"/>
In the controller:
$scope.entityId = $routeParams.entityId;
In the view:
<input type="hidden" name="entityId" ng-model="entity.entityId" ng-init="entity.entityId = entityId" />
I've found a nice solution written by Mike on sapiensworks. It is as simple as using a directive that watches for changes on your model:
.directive('ngUpdateHidden',function() {
return function(scope, el, attr) {
var model = attr['ngModel'];
scope.$watch(model, function(nv) {
el.val(nv);
});
};
})
and then bind your input:
<input type="hidden" name="item.Name" ng-model="item.Name" ng-update-hidden />
But the solution provided by tymeJV could be better as input hidden doesn't fire change event in javascript as yycorman told on this post, so when changing the value through a jQuery plugin will still work.
Edit
I've changed the directive to apply the a new value back to the model when change event is triggered, so it will work as an input text.
.directive('ngUpdateHidden', function () {
return {
restrict: 'AE', //attribute or element
scope: {},
replace: true,
require: 'ngModel',
link: function ($scope, elem, attr, ngModel) {
$scope.$watch(ngModel, function (nv) {
elem.val(nv);
});
elem.change(function () { //bind the change event to hidden input
$scope.$apply(function () {
ngModel.$setViewValue( elem.val());
});
});
}
};
})
so when you trigger $("#yourInputHidden").trigger('change') event with jQuery, it will update the binded model as well.
Found a strange behaviour about this hidden value () and we can't make it to work.
After playing around we found the best way is just defined the value in controller itself after the form scope.
.controller('AddController', [$scope, $http, $state, $stateParams, function($scope, $http, $state, $stateParams) {
$scope.routineForm = {};
$scope.routineForm.hiddenfield1 = "whatever_value_you_pass_on";
$scope.sendData = function {
// JSON http post action to API
}
}])
I achieved this via -
<p style="display:none">{{user.role="store_user"}}</p>
update #tymeJV 's answer
eg:
<div style="display: none">
<input type="text" name='price' ng-model="price" ng-init="price = <%= #product.price.to_s %>" >
</div>
I had facing the same problem,
I really need to send a key from my jsp to java script,
It spend around 4h or more of my day to solve it.
I include this tag on my JavaScript/JSP:
$scope.sucessMessage = function (){
var message = ($scope.messages.sucess).format($scope.portfolio.name,$scope.portfolio.id);
$scope.inforMessage = message;
alert(message);
}
String.prototype.format = function() {
var formatted = this;
for( var arg in arguments ) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
<!-- Messages definition -->
<input type="hidden" name="sucess" ng-init="messages.sucess='<fmt:message key='portfolio.create.sucessMessage' />'" >
<!-- Message showed affter insert -->
<div class="alert alert-info" ng-show="(inforMessage.length > 0)">
{{inforMessage}}
</div>
<!-- properties
portfolio.create.sucessMessage=Portf\u00f3lio {0} criado com sucesso! ID={1}. -->
The result was:
Portfólio 1 criado com sucesso! ID=3.
Best Regards
Just in case someone still struggles with this, I had similar problem when trying to keep track of user session/userid on multipage form
Ive fixed that by adding
.when("/q2/:uid" in the routing:
.when("/q2/:uid", {
templateUrl: "partials/q2.html",
controller: 'formController',
paramExample: uid
})
And added this as a hidden field to pass params between webform pages
<< input type="hidden" required ng-model="formData.userid" ng-init="formData.userid=uid" />
Im new to Angular so not sure its the best possible solution but it seems to work ok for me now
Directly assign the value to model in data-ng-value attribute.
Since Angular interpreter doesn't recognize hidden fields as part of ngModel.
<input type="hidden" name="pfuserid" data-ng-value="newPortfolio.UserId = data.Id"/>
I use a classical javascript to set value to hidden input
$scope.SetPersonValue = function (PersonValue)
{
document.getElementById('TypeOfPerson').value = PersonValue;
if (PersonValue != 'person')
{
document.getElementById('Discount').checked = false;
$scope.isCollapsed = true;
}
else
{
$scope.isCollapsed = false;
}
}
Below Code will work for this IFF it in the same order as its mentionened
make sure you order is type then name, ng-model ng-init, value. thats It.
Here I would like to share my working code :
<input type="text" name="someData" ng-model="data" ng-init="data=2" style="display: none;"/>
OR
<input type="hidden" name="someData" ng-model="data" ng-init="data=2"/>
OR
<input type="hidden" name="someData" ng-init="data=2"/>

Categories