I have a form which gets generated at runtime. I'm trying to update the class of the input box if validation fails. I'm performing validation on ng-blur = "chaeckValidation()" Now if I'm using ng-class = "active" and set the variable in controller for $scope.active = "has-error-class".
What this is doing is updating class of all the elements in form to error-class css but I want to attach error-class css only to the element which failed validation.
I tried but couldn't find any success. I can't hardcode anything in form as the form is completely dynamic and moreover I'm performing validation through regular expression in function and want to display error message based on which regular expression failed.
Code:
prop.json
[
{ label : Application Name
cid : uniqueId
typeApex : CURRENCY
fieldPath : application_Name__c
type : NUMBER
value : ''
dbRequired : true
isRequired : false
},
{...similar array of JSON object ...},
{}
]
view.html
<div ng-if="prop.type != 'picklist' && prop.type != 'reference'">
<label for="{{prop.label}}">{{prop.label}}</label>
<input type="{{prop.type}}" id="inputFields{{prop.fieldPath}}" ng-blur="fieldValidation(prop.fieldPath, prop.typeApex, $event)" ng-model-options="{updateOn: 'blur'}"
class="form-control" name="{{prop.fieldPath}}" ng-model="fieldPathValue[prop.fieldPath]"
ng-required="isRequired({{prop.dbRequired}}, {{prop.required}})" ng-class ="active"/>
</div>
Controller
$scope.fieldValidation = function(fieldPath, type, $event) {
console.log('fieldPath in fieldValidation ',fieldPath);
var myMap = new Map();
myMap.set("Term__c","^[0-9]+$");
myMap.set("Loan_Amount__c","[0-9]+(\.[0-9][0-9]?)?");
//console.log("fieldPathValue ",$.parseJSON(JSON.stringify($scope.fieldPathValue)));
//console.log("fieldPathValue ",$scope.fieldPathValue);
var value = $event.target.value;
console.log("value ",value);
var reg = new RegExp(myMap.get(fieldPath));
console.log("regex test result ",reg.test(value));
console.log("event ",$event);
if(!reg.test(value)) {
//add error message classs to selected field
//display error message on top of field
$timeout(function(){
$scope.$apply(function () {
$scope.active = "has-error";
});
}, 0);
}
Result Image:
I have made an error in first input field which accepts float numbers and I have provided alphabets, so it throws error but that error is propogated to entire form and not only to the element which triggers it.
How can I make sure only element that fails validation on ng-blur gets the error-class-css attached.
I have tried doing this using getElementById but no success. Added the questions link below.
I have described more on my questions form element in one of my questions. DOM elements not getting updated from angular controller
Related
I have an input:
In the controller I want to obtain the value of the text input by setting available. For example:
vm.inputValue = document.getElementById('link').value;
It breaks my code as I get a console error of:
TypeError: Cannot read property 'value' of null
What am I doing wrong?
AngularJS have a directive that does it to you, the ng-model. It binds in a variable the input you enter in the HTML and it reflect the changes you make in the variable inside your controller in JavaScript.
In your HTML
<input type="text" ng-model="vm.myText">
{{ vm.myText }} <!-- This is output the value of vm.myText in the HTML -->
<button ng-click="vm.logData()"></button>
In your JavaScript
function MyController(){
var vm = this;
vm.myText = '';
vm.logData = logData;
function logData(){
console.log('Your data is ', vm.myText);
// This easy, you can access your value in the JavaScript
}
}
Probably you forget to set the id (id = "link")of the input field in HTML:
<input id = "link" type = "text">
Also, you can do the same thing using ng-model
<input ng-model = "vm.inputValue" type = "text">
And from controller, you can get the correct value if you define a scope variable:
$scope.vm = {};
$scope.vm.inputValue = "";
I have the following TextBoxFor on an MVC form:
<div class="col-xs-3">
#Html.TextBoxFor(m => m.SalesSubTotal, null, new { #class = "form-control", title = "", #tabindex = "-1", #readonly = "readonly", #style = "text-align:right", Value = String.Format("{0:C2}", Model.SalesSubTotal) })
</div>
The user will never actually enter a value in this field. The field is always updated via a line in a JavaScript function that looks as follows:
$("#SalesSubTotal").val(salesSubTotal.toFixed(2));
When the page first displays the input displays $0.00 as I would expect. However, when the field is updated, the currency symbol is never displayed. So, instead of displaying something like $90.15, it displays 90.15.
Can someone see what I'm doing wrong?
Your number format {0:C2} isn't active anymore when javascript is invoked:
$("#SalesSubTotal").val(salesSubTotal.toFixed(2));
will actually just set the field to the value with two decimals just like you have experienced it. You have to add the dollar sign there aswell to get the correct result:
$("#SalesSubTotal").val("$" + salesSubTotal.toFixed(2));
The string format is being applied when the element is rendered for the first time with Value = String.Format("{0:C2}", Model.SalesSubTotal), but then you change the value without that format in JS.
You can create a helper function that formats the value and use it like so:
(function() {
function currencyFormat(val) {
return `$${val.toFixed(2)}`;
}
let salesSubTotal = 90.1525346252;
$("#SalesSubTotal").val(currencyFormat(salesSubTotal));
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="SalesSubTotal">
Alternatively, you can extend the jQuery prototype with jQuery.fn.extend().
(function() {
$.fn.extend({
currencyVal: function(val) {
this.val(`$${val.toFixed(2)}`);
}
});
let salesSubTotal = 90.1525346252;
$("#SalesSubTotal").currencyVal(salesSubTotal);
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="SalesSubTotal">
I am trying to change the value of a hidden field on submission by JavaScript. In my page there are two buttons, one for going back to homepage (index.php) and another for returning to the first page for data entry (addData.php). I am trying to use a hidden field with id "goHome" to control the routeing. My codes are like this:
HTML (Form only)
<form name = "addDataReal" id = "addDataReal" method = "POST" action = "addDataProc.php" onsubmit="return checkNSub()">
<!-- Other items -->
<input type = "submit" name = "submitBtnF" id = "submitBtnF" class="shortText" style = "width: 120px;" value = "Submit + Home" onclick = "return getGoValue(true)"/>
<input type = "submit" name = "submitBtnR" id = "submitBtnT" class="shortText" style = "width: 120px;" value = "Submit + Next" onclick = "return getGoValue(false)"/>
<input type = "hidden" name = "goHome" id = "goHome" value = "" />
</div>
</form>
Javascript
function checkNSub() {
//form validation functions
//OK then return true
//Not then return false
}
function getGoValue(goHome) {
if (goHome) {
document.getElementById("goHome").value = "true";
} else {
document.getElementById("goHome").value = "false";
}
return true;
}
Before this I have tried many other versions and I refered to these few questions:
Set form hidden value on submit
Setting a form variable value before submitting
How to change the value of hidden input field before submitting
But none of the methods were working for me.
For practical purposes there is a workaround for this, but I want to know if I would like to keep these two buttons, how should my code be modified so that the value of "goHome" can be changed before the form is submitted? After many attempts I am still getting $_POST["goHome"] = "".
Also, why is the form submitted before the value is actually changed when the code is placed before that?
Thanks!
It's old question But I thought If any one still looking for the answer , here it is
You can try jquery $('input[name="goHome"]').val('true');
or JS - document.getElementByName("goHome").value = "true";
This will work for sure.
While updating any value at the time of submitting for use name selector instead of ID, that will save you some time :)
When we try to change value of Hidden field at the time of submitting form it didn't update value because DOM has already detached the ID from the input parameter but name is still there because name is going to be passed in form.
If anyone find this useful and they do not have to work for lot hours for a simple solution :)
Happy Coding :)
Various ways to achieve this. Firstly though keep in mind that you are using type="submit" <input> inside a <form> , and that means that they will automatically submit the form regardless of an onclick event or not.
One as much as less intrusive (to your code) way is the following:
Take out the submit inputs from your form like this:
Example :
<form name = "addDataReal" id = "addDataReal" method = "POST" action = "whatever.php">
<!-- Other items -->
<input type = "hidden" name = "goHome" id = "goHome" value = "" />
</div>
</form>
<input type = "submit" name = "submitBtnF" id = "submitBtnF" class="shortText" style = "width: 120px;" value = "Submit + Home" onclick = "return getGoValue(true)"/>
<input type = "submit" name = "submitBtnR" id = "submitBtnT" class="shortText" style = "width: 120px;" value = "Submit + Next" onclick = "return getGoValue(false)"/>
Change your getGoValue() and checkNSub() functions like this :
function checkNSub() {
//form validation functions
//OK then return true
//Not then return false
var myForm = document.getElementById('addDataReal');
myForm.submit();
}
function getGoValue(goHome) {
if (goHome) {
document.getElementById("goHome").value = "true";
console.log(document.getElementById("goHome").value);
checkNSub();
} else {
document.getElementById("goHome").value = "false";
console.log(document.getElementById("goHome").value);
checkNSub();
}
return true;
}
Try it out.
P.S : A couple of console.logs so you can check out the value changing. Comment out checkNSub(); to see them in your console. Nevertheless keep in mind that you are posting a Form which means you are going to load a new page from the server , this new page will be agnostic regarding your "goHome" value. The "goHome" value exists only while you are on the same page. The moment your DOM is "recreated" you will lose it.
P.S.2 :
Your return true; inside the getGoValue(); is not needed in my
example. You can remove it.
the return in your onclick = "return getGoValue(true)" is also
not needed and you can remove it
P.S.3 :
This reply is focused on keeping most of your code intact. In reality now that you have your inputs outside the form there is no need for them to be of type="submit" you should change them to <button> with onClick events (or Listeners).
I'm creating inputs inside a form dynamically. I created this directive for the purpose:
// Generate inputs on the fly using BE data.
.directive('inputGenerator', ['$compile', function ($compile) {
return {
restrict: 'E',
scope: {
id: '#',
type: '#',
name: '#',
attributes: '=',
ngModel: '=',
ngDisabled: '='
},
link: function (scope, iElement, iAttrs) {
// Get attributes
var id = iAttrs.id,
type = iAttrs.type,
name = iAttrs.name;
scope.ngModel[name] = {};
var extended_attributes = {
"type": type,
"id": id,
"data-ng-model": 'ngModel.' + name + '[\'value\']',
"name": name,
"data-ng-disabled": "ngDisabled"
};
if ( ! scope.attributes) {
scope.attributes = {};
}
// Append extra attributes to the object
angular.extend(scope.attributes, extended_attributes);
// Generate input
var input = '<input ';
angular.forEach(scope.attributes, function (value, key) {
input += key + '="' + value + '" ';
});
input += '/>';
// Compile input element using current scope (directive) variables
var compiledElement = $compile(input)(scope);
// Set the file selected name as the model value
compiledElement.on('change', function () {
if (this.files && this.files[0].name) {
var that = this;
scope.$apply(function () {
scope.ngModel[name] = {};
scope.ngModel[name]['value'] = that.files[0].name;
});
}
});
// Replace directive element with generated input
iElement.replaceWith(compiledElement);
}
};
}]);
This html line will trigger the directive:
<input-generator data-name="{{ item.name }}" data-ng-model="inputs.sources" data-attributes="item.attrs" data-type="{{ item.type }}" data-id="inputFile_{{ $index }}" data-ng-disabled="inputs.sources[item.name].selected" />
I'm running on Angular 1.4.3.
Problem
The model and pretty much everything works fine in the directive, but for some reason the form remains valid when the input added is invalid as you can see in this image.
I already tried:
Any of the Angular features of form validation works
I debugged Angular and seems to be that the input attached to the form is different from the input compiled inside the directive.
I already called formName.$setPristine() after each input was created, but it didn't work.
I couldn't access the form from the directive, but I think is not a good idea either.
I already wrapped the input with a ng-form tag, but nothing useful comes out of that.
I tried to use the directive compile method, but this is just triggered once when the app loads and I've a select input that loads different inputs on change.
Any help on this is much appreciated! :)
Thank you to everyone for contribute anyways!!
You should definitely take a look at my Angular-Validation Directive/Service. It as a ton of features and I also support dynamic inputs validation, you can also pass an isolated scope which helps if you want to not only have dynamic inputs but also have dynamic forms, also good to use inside a modal window.
For example, let's take this example being a dynamic form and inputs defined in the Controller:
$scope.items.item1.fields = [
{
name: 'firstName',
label:'Enter First Name',
validation:"required"
},
{
name: 'lastName',
label: 'Enter Last Name',
validation:"required"
}
];
$scope.items.item2 = {
heading:"Item2",
formName:"Form2"
};
$scope.items.item2.fields = [
{
name: 'email',
label:'Enter Email Id',
validation:"required"
},
{
name: 'phoneNo',
label: 'Enter Phone Number',
validation:"required"
}
];
It will bind the validation to the elements and if you want to easily check for the form validity directly from the Controller, simply use this
var myValidation = new validationService({ isolatedScope: $scope });
function saveData() {
if(myValidation.checkFormValidity($scope.Form1)) {
alert('all good');
}
}
You can also use interpolation like so
<input class="form-control" type="text" name="if1"
ng-model="vm.model.if1"
validation="{{vm.isRequired}}" />
Or using a radio/checkbox to enable/disable a field that you still want to validate when it becomes enable:
ON <input type="radio" ng-model="vm.disableInput4" value="on" ng-init="vm.disableInput4 = 'on'">
OFF <input type="radio" ng-model="vm.disableInput4" value="off">
<input type="text" name="input4"
ng-model="vm.input4"
validation="alpha_dash|min_len:2|required"
ng-disabled="vm.disableInput4 == 'on'" />
It really as a lot of features, and is available on both Bower and NuGet (under the tag name of angular-validation-ghiscoding). So please take a look at my library Angular-Validation and a live demo on PLUNKER.
It's loaded with features (custom Regex validators, AJAX remote validation, validation summary, alternate text errors, validation on the fly with the Service, etc...). So make sure to check the Wiki Documentation as well... and finally, it's fully tested with Protractor (over 1500 assertions), so don't be afraid of using in production.
Please note that I am the author of this library
I ran into this issue as well with Angular v1.5.9. The main issue here is that you are compiling the HTML template before it is in the DOM, so Angular doesn't know it's part of the form. If you add the HTML first, then compile, Angular will see your input as a form child, and it will be used in the form validation.
See similar answer to Form Validation and fields added with $compile
Don't do:
var myCompiledString = $compile(myHtmlString)(scope);
// ...
element.replaceWith(myCompiledString);
Do this instead:
var myElement = angular.element(myHtmlString)
element.replaceWith(myElement) // put in DOM
$compile(myElement)(scope) // $compile after myElement in DOM
Note: I swapped the more conventional element for OP's iElement, which is a jQLite reference of the directive's HTML element
you need to use ng-form directive as a wrapper for your input.
you can see an example of this here
but it works for me. You can pass the form reference to the directive and use it directly.
in the code below, the scope.form is used to know the general state of the form, and the scope.name to access the input field state.
< ng-form name="{{name}}" ng-class="{error: this[name][name].$invalid && form.$submitted}" >
i hope it helps
you need to set name of control dynamic and use this dynamic name for form validation. in the following e.g. you see the dynamic name and id of control and used for the validation of angular (using ng-massages)
more details see http://www.advancesharp.com/blog/1208/dynamic-angular-forms-validation-in-ngrepeat-with-ngmessage-and-live-demo
Field Num Is Required.
I've got a fairly simple angular controller method :
$scope.addComment = function () {
if ($scope.newComment.message) {
$scope.can_add_comments = false;
new Comments({ comment: $scope.newComment }).$save(function (comment) {
$scope.comments.unshift(comment);
return $scope.can_add_comments = true;
});
return $scope.newComment = {};
}
};
And in my form I have a textarea that holds the value of comment :
<textarea class="required" cols="40" id="new_comment_message" maxlength="2500" ng-disabled="!can_add_comments" ng-model="newComment.message" required="required" rows="20"></textarea>
Works great so far, however I do want to send some data, hidden data with the comment as well. So I added something to hold that value :
<input id="hash_id" name="hash_id" ng-init="__1515604539_122642" ng-model="newComment.hash_id" type="hidden" value="__1515604539_122642">
However when I inspect the $scope.newComment it always comes back as an object with only message as it's property, which is the value from the text area, and I don't get the property on the object hash_id.
When I make this input non hidden and I manually type in the value into the input field and submit a form, I do get a object with hash_id property. What am I doing wrong here, not setting it right?
As far as I know, ng-model doesn't use the value property as a "default" (i.e. it won't copy it back into your model). If you want a default, it should be placed wherever the model is defined:
$scope.newComment = { hash_id: "__1515604539_122642", /* Other params */ };
Alternatively, changing the ng-init to an assignment should work (though I would recommend the above solution instead):
<input id="hash_id" name="hash_id" ng-init="newComment.hash_id = '__1515604539_122642'" ng-model="newComment.hash_id" type="hidden">