update ng-invalid when editing double entry fields - css

i have a password and password confirm field, which is connected using a directive. beside that i have css that set border color when ng-invalid. the issue is that when i for instance enter the confirm_password first and then same in password it does not remove the 'ng-invalid'. is there a way to tell angular to update other fields classes when editing password?
html
<div class="form-group">
<label>Adgangskode</label>
<input type="password" class="form-control" name="password"
ng-model="vm.password" ng-minlength="6" ng-maxlength="24"
placeholder="Din adgangskode"
equals="vm.confirm_password" required>
<p ng-show="SignUp.password.$invalid
&& (SignUp.password.$dirty || vm.submitted)"
class="help-block ng-binding" style="">Adgangskode er invalid.</p>
</div>
<div class="form-group">
<label>Adgangskode bekræftelse</label>
<input type="password" class="form-control" name="confirm_password"
ng-model="vm.confirm_password"
ng-minlength="6" ng-maxlength="24"
ng-model="vm.confirm_password"
placeholder="Bekræft din adgangskode"
required nx-equal="vm.password">
<p ng-show="SignUp.confirm_password.$error.nxEqual
&& (SignUp.confirm_password.$dirty || vm.submitted)"
class="help-block ng-binding">Adgangskoderne er ikke ens.</p>
</div>
css
input.ng-dirty.ng-invalid {
border-color: #a94442;
}
.ng-submitted input.ng-invalid {
border-color: #a94442;
}
directive funciton
function ComparePassword() {
return {
require: 'ngModel',
link: function (scope, elem, attrs, model) {
if (!attrs.nxEqual) {
console.error('nxEqual expects a model as an argument!');
return;
}
scope.$watch(attrs.nxEqual, function (value) {
model.$setValidity('nxEqual', value === model.$viewValue);
});
model.$parsers.push(function (value) {
var isValid = value === scope.$eval(attrs.nxEqual);
model.$setValidity('nxEqual', isValid);
return isValid ? value : undefined;
});
}
}
}

Have the compare directive watch the other field:
app.directve("compareTo", compareTo);
function compareTo() {
return {
require: "ngModel",
link: function(scope, elem, attrs, ngModel) {
ngModel.$validators.compareTo = function(modelValue) {
return modelValue == scope.$eval(attrs.compareTo);
};
scope.$watch(attrs.compareTo, function() {
ngModel.$validate();
});
}
};
}
Usage:
<form name="form1">
<input type="password" name="password" required
ng-model="user.password" />
<input type="password" name="confirmPassword" required
ng-model="user.confirmPassword" compare-to="user.password" />
</form>
<div ng-show="form1.comfirmPassword.$error.compareTo">
Error: Password entries must match
</div>
Think carefully about double entry
Double entry:
increases the workload for every single user;
can be bypassed by copying and pasting, or automatic form-filling tools;
only ensures the two fields match, not that they contain the valid information;
and
may be seen as belittling the user;
Alternatives to double entry are worth serious consideration. These alternatives include authentication and/or simple methods of reset or recovery.
— Formulate Information Design Blog - Double entry of form fields

Related

KnockoutJS Required (ifonly) not being honored when observable changes

I have 2 fields that I need to required based on another field in my model. The first field is functioning as desired, however the second field (similar logic) doesn't honor the required attribute. I have verified that the onlyif code is firing when the observable is changed. However the form allows submission if the required fields are not filled in.
JS Code
//Works As Expected
self.model.RecentLocations.LastDayOnSite.extend({
required: {
onlyIf: function () {
return ((!self.model.RecentLocations.IsLastDayOnSiteNA()) && (self.model.CaseType() != 'Quarantine'));
}
}
});
//Not Requiring Field as expected.
self.model.ContactTracingStartDate.extend = ko.observable().extend({
required: {
onlyIf: function () {
return (self.model.IsContactTracingRequired() == "Y");
}
}
});
HTML Code
//Works As Expected
<div class="col-md-2 form-group">
<i id="lastDayOnSite-asterisk" class="fas fa-asterisk fa-fw" style="font-size: 7px; color:red; vertical-align:super" data-bind="hidden: (model.RecentLocations.IsLastDayOnSiteNA() || model.CaseType() === 'Quarantine')"></i>
<label for="lastDayOnSite-datepicker_nfd">Last Day on Site</label>
<input type="text" class="form-control datepicker_nfd" id="lastDayOnSite-datepicker_nfd" data-bind="value: model.RecentLocations.LastDayOnSite, preventFutureDate: model.RecentLocations.LastDayOnSite, disable: model.RecentLocations.IsLastDayOnSiteNA()" data-emessage="Last Day on Site" placeholder="Date">
</div>
//Not Requiring Field as expected.
<div class="col-md-2 form-group">
<i id="contactTracingStartDate-asterisk" class="fas fa-asterisk fa-fw" style="font-size: 7px; color:red; vertical-align:super" data-bind="visible: (model.IsContactTracingRequired() === 'Y')"></i>
<label for="contactTracingStartDate-datepicker_nfd">Contact Tracing Start Date</label>
<input type="text" class="form-control datepicker_nfd" id="contactTracingStartDate-datepicker_nfd"
data-bind="value: model.ContactTracingStartDate,
preventFutureDate: model.ContactTracingStartDate, enable: (model.IsContactTracingRequired() === 'Y')" data-emessage="Contract Tracing Start Date" placeholder="Date">
</div>
Not Sure what I am missing here but I am fairly new to KnockoutJS but I can't see where the disconnect is. Any Help or suggestions would be appreciated.
The answer is change the line of code
self.model.ContactTracingStartDate.extend = ko.observable().extend({
TO:
self.model.ContactTracingStartDate.extend({
The problem was the observerable was reset by the ko.observable().extend instead of just extending the existing observable.

How to dynamically set 'was-validated' class on form to show validation feedback messages with angular 5 after submit

I am using a template based form in angular. I also use bootstrap (v4) and I wish to show some validation messages when the form was submitted.
This is my form:
<form [ngClass]="{'was-validated': wasValidated}">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" class="form-control" [(ngModel)]="category.name" #name="ngModel" required maxlength="100"/>
<div *ngIf="name.invalid" class="invalid-feedback">
<div *ngIf="name.errors.required">
Name is required.
</div>
</div>
</div>
<button type="submit" class="btn btn-success" (click)="save()">Save</button>
</form>
My component looks as follows:
category: Category;
wasValidated: boolean = false;
ngOnInit() {
this.reset();
}
save() {
this.wasValidated = true;
this.categoriesService.createCategory(this.category).subscribe(
() => {
this.notificationService.add(notifications.category_saved, {name: this.category.name});
this.reset();
},
() => this.notificationService.add(notifications.save_category_failed)
);
}
reset() {
this.wasValidated = false;
this.category = {} as Category;
}
This works, but I have a feeling it's overly complex and more like a workaround rather than the right way. What is the best way to accomplish this?
Note: the class was-validated must be present on the form element in order to show the div with class invalid-feedback. I'm using this: https://getbootstrap.com/docs/4.0/components/forms/#validation
Note 2: I have currently no mechanism yet to prevent form submission on error. I'd like to know a good solution for that as well!
With the answer from #Chellappan V I was able to construct the solution I wanted.
I have applied to following changes:
First added #form="ngForm" to the form tag in the template. Secondly I changed the ngClass expression to reference the submitted state of the form, rather than referring to a boolean which was set to true manually when form was submitted. Last but not least I pass the form in the submit method on the save button.
<form novalidate #form="ngForm" [ngClass]="{'was-validated': form.submitted}">
<!-- form controls -->
<button type="submit" class="btn btn-success" (click)="submit(form)">Save</button>
</form>
In the component I injected the template variable in the component with #ViewChild.
#ViewChild("form")
private form: NgForm;
The submit method now takes a form parameter of type NgForm which is used to check if the form was valid before sending a request to the backend:
submit(form: NgForm) {
if (form.valid) {
this.categoriesService.createCategory(this.category).subscribe(
() => {
this.notificationService.add(notifications.category_saved, {name: this.category.name});
this.reset();
},
() => this.notificationService.add(notifications.save_category_failed)
);
} else {
this.notificationService.add(notifications.validation_errors);
}
}
Finally the reset method resets the form and the model so it can be re-entered to submit a next instance:
reset() {
this.form.resetForm();
this.category = {} as NewCategoryDto;
}

semantic form validation - Validation for either one of the fields as non-empty

I have a form in which I have 2 fields, ssn and phone. I would like the user to enter anyone of the field. I'm using semantic validation, here is my code, can you please let me know how to validate the form using Semantic?
<form class="ui error form basic segment" role="form" method="POST" action="{{ url('/username/email') }}">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<input type="hidden" name="_method" value="patch">
<div class="ui info message">
Please enter either SSN or phone to email you the username.
</div>
<div class="field">
<label for="ssn">SSN</label>
<div class="ui icon input">
<input type="text" class="form-control" name="ssn" value="{{ old('ssn') }}">
</div>
</div>
<div class="field">
<label for="phone">Phone</label>
<div class="ui icon input">
<input type="text" class="form-control" name="phone" value="{{ old('phone') }}">
</div>
</div>
<input type="submit" value="Email Username" class="ui primary button">
</form>
<script type="text/javascript">
$('.ui.form')
.form({
inline : true,
on: 'blur',
fields: {
username: {
identifier : 'ssn',
rules: [
{
type : 'empty',
prompt : 'Please enter a SSN'
}
]
},
}
})
;
</script>
`
Here's a little bit more elegant solution that follows Semantic UI fields identification standard.
Field could be identified not only via input[name="…"] CSS selector offered in Oniisaki's accepted answer, but also by DOM element id or data-validation attribute:
/**
* Checks whether current field value or at least one of additionally
* given fields values is not empty, neither blank string.
* #param {string} value Current field value.
* #param {string} fieldIdentifiers Comma separated field identifiers.
* #return {boolean}
*/
$.fn.form.settings.rules.allEmpty = function(value, fieldIdentifiers) {
var $form = $(this);
return !!value || fieldIdentifiers.split(',').some(function(fieldIdentifier) {
return $form.find('#' + fieldIdentifier).val() ||
$form.find('[name="' + fieldIdentifier +'"]').val() ||
$form.find('[data-validate="'+ fieldIdentifier +'"]').val();
});
};
// Using newly created custom validation rule.
// Notice how multiple fields are defined, if required.
$('.ui.form').form({
ssn: {
identifier: 'ssn',
rules: [{
// Multiple field identifiers could be defined,
// like `allEmpty[phone,email,skype]`.
type: 'allEmpty[phone]',
prompt: 'SSN or Phone (at least one field) must be filled.'
}]
}
});
I would create a Semantic UI custom validation function that accepts parameters for your purpose.
Here's the link: http://jsfiddle.net/owcfuhtq/
The code:
$(document).ready(function(){
// function to check if at least one text is not empty for a collection of elements
// text is the value of the input device
// csv is the argument as string. It's the string inside "[" and "]"
$.fn.form.settings.rules.isAllEmpty = function(text,csv){
//If the text of the field itself isn't empty, then it is valid
if (text)
return true;
var array = csv.split(','); // you're separating the string by commas
var isValid = false; // return value
$.each(array,function(index,elem){
// for each item in array, get an input element with the specified name, and check if it has any values
var element = $("input[name='"+elem+"']");
//If element is found, and it's value is not empty, then it is valid
if (element && element.val())
isValid = true;
});
return isValid;
};
var formValidationRules =
{
ssn: {
identifier: 'ssn',
rules: [{
type: "isAllEmpty[phone]",
//If you got additional fields to compare, append it inside the [] with a "," separator
//E.g. isAllEmpty[field1, field2]
prompt: 'An error occurred'
}]
}
}
$('.ui.form').form(formValidationRules);
});
If you want to include select box you can use it sth like this :
$.fn.form.settings.rules.isAllEmpty = function (text, csv) {
if (text) {
return true;
}
var array = csv.split(',');
var isValid = false;
$.each(array, function (index, elem) {
var element = $("input[name='" + elem + "']");
if (element.length == 0) {
element = $("select[name='" + elem + "']")
}
if (element && element.val()) {
isValid = true;
}
});
return isValid;
};

HOW TO CONVERT TRIPLE TAG IN METEOR 0.7.0.1 ACCORDING TO VERSION 0.8.0

I have updated meteor application to version 0.8.0 from 0.7.0.1. Every changes tried to do but not able to figure out, how to change triple tag according to new version. Referred the following link and tried to do so but still getting error.
The link following is: https://github.com/meteor/meteor/wiki/Using-Blaze
The code of .html file is: Basically this {{{done }}} part. I tried to change according to the above link as {{> done}}. But then getting error as ""Reactive HTML attributes must either have a constant name or consist of a single {{helper}} providing a dictionary of names and values. A template tag of type INCLUSION is not allowed here.
""
<template name="subscribedKeyword">
<div class="issue" >
<div class="issue-content">
<h3>
{{category}}
<input id='check' class="checktype" name="mark" type="checkbox" value="1" {{{ done}}} />Get Notifications
<input type="hidden" name="mark" value="0" />
</h3>
</div>
</div>
</template>
The corresponding .js file code is: I think that there is no need to change anything in this file. As according to the above link, changes need to be done in the html file only.
Template.subscribedKeyword.done = function () {
// alert('inside done function');
var subscribedUsersOfThisDomain= Subscribed.findOne(this._id);
var subscribedPersons = subscribedUsersOfThisDomain.categorySubscribedUsers;
// alert('before if block in done function');
if(subscribedPersons && subscribedPersons.length)
{
var j;
var ch='';
// alert('before loop in done function');
for(j= 0;j< subscribedPersons.length;j++)
{
//alert('j '+j);
//alert('person '+person[j].username);
if(subscribedPersons[j].username === Meteor.user().username)
{
ch ="checked";
// alert('value of ch that is set'+ch);
break;
}
}
if(ch=== 'checked')
{
// alert('while returning value in if block');
return 'checked="checked"';
}
else
{
// alert('while returning value in else block');
return '';
}
}
else
return '';
};
Do let me know what changed need to be done. Thanks in advance
The simplest way I can see is:
<template name="subscribedKeyword">
<div class="issue" >
<div class="issue-content">
<h3>
{{category}}
<input id='check' class="checktype" name="mark" type="checkbox" value="1" checked={{done}} />Get Notifications
<input type="hidden" name="mark" value="0" />
</h3>
</div>
</div>
</template>
Template.subscribedKeyword.done = function () {
// alert('inside done function');
var subscribedUsersOfThisDomain= Subscribed.findOne(this._id);
var subscribedPersons = subscribedUsersOfThisDomain.categorySubscribedUsers;
// alert('before if block in done function');
if(subscribedPersons && subscribedPersons.length)
{
var j;
var ch='';
// alert('before loop in done function');
for(j= 0;j< subscribedPersons.length;j++)
{
//alert('j '+j);
//alert('person '+person[j].username);
if(subscribedPersons[j].username === Meteor.user().username)
{
ch ="checked";
// alert('value of ch that is set'+ch);
break;
}
}
if(ch=== 'checked')
{
// alert('while returning value in if block');
return "checked";
}
else
{
// alert('while returning value in else block');
return null;
}
}
else
return null;
};
According to https://github.com/meteor/meteor/wiki/Using-Blaze#conditional-attributes-with-no-value-eg-checked-selected

learning AngularJs : ng-model does not binding into View

I am very new to angularJS and you can say that this is my first day using angularJS.
it seems silly BUt i am trying to do some basic stuff which is not working somehow.
I have a text box in which if you enter 1234, Count should be 555 OR if you enter any number it should be 550 and i am putting 1234 on page load so it is showing me 555 BUT when i change value in textbox, Count is not changing.
<div ng-app>
<div ng-controller="prCtrl">
Enter Product ID to get the reviews details
<input type="number" ng-model="productId" required />
<br />
Total Review Count = {{ Count }}
</div>
</div>
function prCtrl($scope,$http) {
$scope.productId = 1234;
if ($scope.productId === 1234) {
$scope.Count = 555;
} else {
$scope.Count = 550;
}
}
how can i change {{ Count }} depending on the value entered in textbox.
thanks
An option would be to subscribe to the model change and carry out your logic there:
Controller:
function prCtrl($scope,$http) {
$scope.productId = 1234;
$scope.$watch('productId', function(newValue, oldValue){
if (newValue === 1234) {
$scope.Count = 555;
} else {
$scope.Count = 550;
}
});
}
View:
<div ng-app>
<div ng-controller="prCtrl">
Enter Product ID to get the reviews details
<input type="number" ng-model="productId" required />
<br />
Total Review Count = {{ Count }}
</div>
</div>
I have tested that, and it appears to do what you want.
And a final note - you mention you are new to angular - I would highly recommend egghead.io 's sessions on AngularJS ( https://egghead.io/lessons ). They are good at getting you up to speed with AngularJS :)
Alternatively you can use a function, without watching the value using $watch
function prCtrl($scope,$http) {
$scope.productId = 1234;
$scope.getCount = function() {
if ($scope.productId === 1234) {
return 555;
} else {
return 550;
}
}
}
view:
<div ng-app>
<div ng-controller="prCtrl">
Enter Product ID to get the reviews details
<input type="number" ng-model="productId" required />
<br />
Total Review Count = {{ getCount() }} // replaced with function call
</div>
</div>
This function gets called when ever a model is changed in the scope, so it will always update your value

Resources