Angular. Change type of input - html

I have div, that, when pressed, triggers a function that change type of input.
There are two inputs, they have 'password' type, function, changes it to 'text'
Problem
Error 1: 'password' is possibly 'null'.
If i put <!> to the password field, there is new error: Property 'type' does not exist on type 'Element'.
Html:
<div class="eyes" (click)="togglePasswords()">
<i *ngIf="show_password" class="fa fa-eye" aria-hidden="true"></i>
<i *ngIf="!show_password" class="fa fa-eye-slash" aria-hidden="true"></i>
</div>
TypeScript:
public togglePasswords(): void {
let password = document.querySelector(".password");
let repeat_password = document.querySelector(".repeat-password");
this.show_password = !this.show_password;
if (this.show_password) {
password.type = "text";
repeat_password.type = "text";
} else {
password.type = "password"
repeat_password.type = "password";
}
}
I repeated it with a simple site (made index.html, put there script tag, in script.js repeated this), and it worked.
I inserted js code to tag inside html component in angular, but it didn't help.
I solved it!
I should have used password.setAttribute("type", "text") instead of password.type = "text"
Guy who helped me, why did you delete your answer?

You can use input element like below in angular.
<input [type]="show_password ? 'text' : 'password'">
And on click you just need to toggle show_password value.

Related

How to read if a checkbox is checked in typescript?

This must be something basic which I can't figure out how to do it. I want to display in console if a check box is checked. My html and typescript code are:
<div class="my-form-field" style="display: block;margin-bottom: 10px;">
<mat-checkbox id="is3dCheckBox" (ngModel)="handleInputChange()">Split tag in bits</mat-checkbox>
</div>
And .ts file has the function handleInputChange()
handleInputChange() {
var element = <HTMLInputElement>document.getElementById("is3dCheckBox");
var isChecked = element.checked;
if (isChecked == true)
console.log("Checked");
if (isChecked == false)
console.log("Not Checked");
}
My console has no error, but it's not displaying the text when checkbox is checked. What am I doing wrong?
You just need to use a type assertion to tell TypeScript it is an HTMLInputElement: var element = document. getElementById("is3dCheckBox"); var isChecked = element.
You can bind to the change event of mat-checkbox.
Template
<mat-checkbox (change)="onChange($event.checked)"></mat-checkbox>
Component Class
onChange(checked) {
console.log(checked);
}
Also just as a side note, in Angular you should generally not feel the need to directly reference the document object to access DOM elements. For this Angular has ElementRef.

ERROR: Property 'value' does not exist on type 'HTMLDivElement' ? Typescript can't find my div?

Learning Typescript and trying to build a simple textbox that displays the text once submitted.
Am able to capture the input great and and now trying to report it back to the user.
The problem is on compilation typescript gives this error message:
Property 'value' does not exist on type 'HTMLDivElement'.
Am simply trying to assign the value of the div messageList to print the array (don't care about formatting yet).
I have been searching the web and most I can find says it must be naming error, i tried changing the name to 1 and still no joy.
Have attempted to use general HTML element in the cast but no joy.
The TS code:
let messages = [];
class Message {
content: string;
constructor(
public message: string
){
this.message = message
}
}
function post(message: string){
var text = (<HTMLInputElement>document.getElementById("messageInput")).value;
const newPost = new Message(text)
messages.push(newPost.message)
console.log(messages)
this.report(newPost)
}
function report(message: Message){
(<HTMLDivElement>document.getElementById("messageList")).value = messages
}
the HTML:
<!DOCTYPE html>
<html>
<head>
<title>Typescript Messages</title>
</head>
<body>
<textarea id="messageInput" type="text" name="message" rows="15" cols="40"></textarea>
<button id="submitButton" type="submit" value="submit" onclick="post()">Post</button>
<div id="messageList" value="">Hello rubhy</div>
<script src="message.js"></script>
</body>
</html>
Any help would be appreciated, thank you
function report(message: Message){
(<HTMLDivElement>document.getElementById("messageList")).value = messages
}
You need to cast it as HTMLInputElement as you done with text in post function:
function report(message: Message){
(<HTMLInputElement>document.getElementById("messageList")).value = messages
}
The HTMLDivElement type doesn't have the value property, so that's why you get that error.
EDIT: I just saw that messageList is a <div>. Div cannot contain a value property. For custom properties, use data-*
https://www.w3schools.com/tags/att_data-.asp

How do I perform field validation within the Angular typescript and not in the form?

Due to specific requirements, I need to validate the presence of my delivery.address field within the typescript code, so I am calling a function, addressIsValid(), to do this as shown in the code below.
<div class="col col-md-6 col-lg-12">
<input class="form-control" type="text" name="address" id="address"
[(ngModel)]="delivery.address" #address="ngModel">
<ng-container *ngIf="delivery.method=='Delivery'">
<div *ngIf="!addressIsValid()" class="primary-color">
<!-- <div *ngIf="address.invalid && (address.dirty
|| address.touched)" class="primary-color"> -->
Address is required
<!-- </div> -->
</div>
</ng-container>
</div>
Typescript function:
public addressIsValid() {
return !this.delivery.address == undefined
&& !this.delivery.address == null;
}
The problem is after valid value is entered into the field, the error message: "Address is required." does not go away. How do I fix this?
I think the problem is in your addressIsValid function.
Take this 2 objects for example:
const o = { name: 'john' };
const o2 = { name: undefined };
!o.name --> false;
!o2.name --> true;
Neither of the above fulfills the condition == undefined or == null.
Thus, you will always get a falsy value.
You could modify your function like this:
public addressIsValid() {
return this.delivery.address !== undefined
&& this.delivery.address !== null;
}
You probably wanted to check this:
public addressIsValid() {
return !!this.delivery.address;
}
example
If that is not the case you need to debug what this.delivery actually contains after your method call.
console.log(this.delivery)
And tell us what that contains.
I would suggest reading about Angular Reactive Forms. You can easily define validation rules in TypeScript and drive the display of error messages in your view.
this.heroForm = new FormGroup({
'name': new FormControl(this.hero.name, [
Validators.required,
Validators.minLength(4),
forbiddenNameValidator(/bob/i) // <-- Here's how you pass in the custom validator.
]),
'alterEgo': new FormControl(this.hero.alterEgo),
'power': new FormControl(this.hero.power, Validators.required)
});
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="name.errors.forbiddenName">
Name cannot be Bob.
</div>
Also take a look at the FormBuilder service, which will help condense the form creating syntax.

How do I reset a form including removing all validation errors?

I have an Angular form. The fields are validated using the ng-pattern attribute. I also have a reset button. I'm using the Ui.Utils Event Binder to handle the reset event like so:
<form name="searchForm" id="searchForm" ui-event="{reset: 'reset(searchForm)'}" ng-submit="search()">
<div>
<label>
Area Code
<input type="tel" name="areaCode" ng-model="areaCode" ng-pattern="/^([0-9]{3})?$/">
</label>
<div ng-messages="searchForm.areaCode.$error">
<div class="error" ng-message="pattern">The area code must be three digits</div>
</div>
</div>
<div>
<label>
Phone Number
<input type="tel" name="phoneNumber" ng-model="phoneNumber" ng-pattern="/^([0-9]{7})?$/">
</label>
<div ng-messages="searchForm.phoneNumber.$error">
<div class="error" ng-message="pattern">The phone number must be seven digits</div>
</div>
</div>
<br>
<div>
<button type="reset">Reset</button>
<button type="submit" ng-disabled="searchForm.$invalid">Search</button>
</div>
</form>
As you can see, when the form is reset it calls the reset method on the $scope. Here's what the entire controller looks like:
angular.module('app').controller('mainController', function($scope) {
$scope.resetCount = 0;
$scope.reset = function(form) {
form.$setPristine();
form.$setUntouched();
$scope.resetCount++;
};
$scope.search = function() {
alert('Searching');
};
});
I'm calling form.$setPristine() and form.$setUntouched, following the advice from another question here on Stack Overflow. The only reason I added the counter was to prove that the code is being called (which it is).
The problem is that even after reseting the form, the validation messages don't go away. You can see the full code on Plunker. Here's a screenshot showing that the errors don't go away:
I started with the comment from #Brett and built upon it. I actually have multiple forms and each form has many fields (more than just the two shown). So I wanted a general solution.
I noticed that the Angular form object has a property for each control (input, select, textarea, etc) as well as some other Angular properties. Each of the Angular properties, though, begins with a dollar sign ($). So I ended up doing this (including the comment for the benefit of other programmers):
$scope.reset = function(form) {
// Each control (input, select, textarea, etc) gets added as a property of the form.
// The form has other built-in properties as well. However it's easy to filter those out,
// because the Angular team has chosen to prefix each one with a dollar sign.
// So, we just avoid those properties that begin with a dollar sign.
let controlNames = Object.keys(form).filter(key => key.indexOf('$') !== 0);
// Set each control back to undefined. This is the only way to clear validation messages.
// Calling `form.$setPristine()` won't do it (even though you wish it would).
for (let name of controlNames) {
let control = form[name];
control.$setViewValue(undefined);
}
form.$setPristine();
form.$setUntouched();
};
$scope.search = {areaCode: xxxx, phoneNumber: yyyy}
Structure all models in your form in one place like above, so you can clear it like this:
$scope.search = angular.copy({});
After that you can just call this for reset the validation:
$scope.search_form.$setPristine();
$scope.search_form.$setUntouched();
$scope.search_form.$rollbackViewValue();
There doesn't seem to be an easy way to reset the $errors in angular. The best way would probably be to reload the current page to start with a new form. Alternatively you have to remove all $error manually with this script:
form.$setPristine(true);
form.$setUntouched(true);
// iterate over all from properties
angular.forEach(form, function(ctrl, name) {
// ignore angular fields and functions
if (name.indexOf('$') != 0) {
// iterate over all $errors for each field
angular.forEach(ctrl.$error, function(value, name) {
// reset validity
ctrl.$setValidity(name, null);
});
}
});
$scope.resetCount++;
You can add a validation flag and show or hide errors according to its value with ng-if or ng-show in your HTML. The form has a $valid flag you can send to your controller.
ng-if will remove or recreate the element to the DOM, while ng-show will add it but won't show it (depending on the flag value).
EDIT: As pointed by Michael, if form is disabled, the way I pointed won't work because the form is never submitted. Updated the code accordingly.
HTML
<form name="searchForm" id="searchForm" ui-event="{reset: 'reset(searchForm)'}" ng-submit="search()">
<div>
<label>
Area Code
<input type="tel" name="areaCode" ng-model="areaCode" ng-pattern="/^([0-9]{3})?$/">
</label>
<div ng-messages="searchForm.areaCode.$error">
<div class="error" ng-message="pattern" ng-if="searchForm.areaCode.$dirty">The area code must be three digits</div>
</div>
</div>
<div>
<label>
Phone Number
<input type="tel" name="phoneNumber" ng-model="phoneNumber" ng-pattern="/^([0-9]{7})?$/">
</label>
<div ng-messages="searchForm.phoneNumber.$error">
<div class="error" ng-message="pattern" ng-if="searchForm.phoneNumber.$dirty">The phone number must be seven digits</div>
</div>
</div>
<br>
<div>
<button type="reset">Reset</button>
<button type="submit" ng-disabled="searchForm.$invalid">Search</button>
</div>
</form>
JS
$scope.search = function() {
alert('Searching');
};
$scope.reset = function(form) {
form.$setPristine();
form.$setUntouched();
$scope.resetCount++;
};
Codepen with working solution: http://codepen.io/anon/pen/zGPZoB
It looks like I got to do the right behavior at reset. Unfortunately, using the standard reset failed. I also do not include the library ui-event. So my code is a little different from yours, but it does what you need.
<form name="searchForm" id="searchForm" ng-submit="search()">
pristine = {{searchForm.$pristine}} valid ={{searchForm.$valid}}
<div>
<label>
Area Code
<input type="tel" required name="areaCode" ng-model="obj.areaCode" ng-pattern="/^([0-9]{3})?$/" ng-model-options="{ allowInvalid: true }">
</label>
<div ng-messages="searchForm.areaCode.$error">
<div class="error" ng-message="pattern">The area code must be three digits</div>
<div class="error" ng-message="required">The area code is required</div>
</div>
</div>
<div>
<label>
Phone Number
<input type="tel" required name="phoneNumber" ng-model="obj.phoneNumber" ng-pattern="/^([0-9]{7})?$/" ng-model-options="{ allowInvalid: true }">
</label>
<div ng-messages="searchForm.phoneNumber.$error">
<div class="error" ng-message="pattern">The phone number must be seven digits</div>
<div class="error" ng-message="required">The phone number is required</div>
</div>
</div>
<br>
<div>
<button ng-click="reset(searchForm)" type="reset">Reset</button>
<button type="submit" ng-disabled="searchForm.$invalid">Search</button>
</div>
</form>
And JS:
$scope.resetCount = 0;
$scope.obj = {};
$scope.reset = function(form_) {
$scope.resetCount++;
$scope.obj = {};
form_.$setPristine();
form_.$setUntouched();
console.log($scope.resetCount);
};
$scope.search = function() {
alert('Searching');
};
Live example on jsfiddle.
Note the directive ng-model-options="{allowinvalid: true}". Use it necessarily, or until the entry field will not be valid, the model value is not recorded. Therefore, the reset will not operate.
P.S. Put value (areaCode, phoneNumber) on the object simplifies purification.
Following worked for me
let form = this.$scope.myForm;
let controlNames = Object.keys(form).filter(key => key.indexOf('$') !== 0);
for (let name of controlNames) {
let control = form [name];
control.$error = {};
}
In Short: to get rid of ng-messages errors you need to clear out the $error object for each form item.
further to #battmanz 's answer, but without using any ES6 syntax to support older browsers.
$scope.resetForm = function (form) {
try {
var controlNames = Object.keys(form).filter(function (key) { return key.indexOf('$') !== 0 });
console.log(controlNames);
for (var x = 0; x < controlNames.length; x++) {
form[controlNames[x]].$setViewValue(undefined);
}
form.$setPristine();
form.$setUntouched();
} catch (e) {
console.log('Error in Reset');
console.log(e);
}
};
I had the same problem and tried to do battmanz solution (accepted answer).
I'm pretty sure his answer is really good, but however for me it wasn't working.
I am using ng-model to bind data, and angular material library for the inputs and ng-message directives for error message , so maybe what I will say will be useful only for people using the same configuration.
I took a lot of look at the formController object in javascript, in fact there is a lot of $ angular function as battmanz noted, and there is in addition, your fields names, which are object with some functions in its fields.
So what is clearing your form ?
Usually I see a form as a json object, and all the fields are binded to a key of this json object.
//lets call here this json vm.form
vm.form = {};
//you should have something as ng-model = "vm.form.name" in your view
So at first to clear the form I just did callback of submiting form :
vm.form = {};
And as explained in this question, ng-messages won't disappear with that, that's really bad.
When I used battmanz solution as he wrote it, the messages didn't appear anymore, but the fields were not empty anymore after submiting, even if I wrote
vm.form = {};
And I found out it was normal, because using his solution actually remove the model binding from the form, because it sets all the fields to undefined.
So the text was still in the view because somehow there wan't any binding anymore and it decided to stay in the HTML.
So what did I do ?
Actually I just clear the field (setting the binding to {}), and used just
form.$setPristine();
form.$setUntouched();
Actually it seems logical, since the binding is still here, the values in the form are now empty, and angular ng-messages directive is triggering only if the form is not untouched, so I think it's normal after all.
Final (very simple) code is that :
function reset(form) {
form.$setPristine();
form.$setUntouched();
};
A big problem I encountered with that :
Only once, the callback seems to have fucked up somewhere, and somehow the fields weren't empty (it was like I didn't click on the submit button).
When I clicked again, the date sent was empty. That even more weird because my submit button is supposed to be disabled when a required field is not filled with the good pattern, and empty is certainly not a good one.
I don't know if my way of doing is the best or even correct, if you have any critic/suggestion or any though about the problem I encountered, please let me know, I always love to step up in angularJS.
Hope this will help someone and sorry for the bad english.
You can pass your loginForm object into the function ng-click="userCtrl.login(loginForm)
and in the function call
this.login = function (loginForm){
loginForm.$setPristine();
loginForm.$setUntouched();
}
So none of the answers were completely working for me. Esp, clearing the view value, so I combined all the answers clearing view value, clearing errors and clearing the selection with j query(provided the fields are input and name same as model name)
var modelNames = Object.keys($scope.form).filter(key => key.indexOf('$') !== 0);
modelNames.forEach(function(name){
var model = $scope.form[name];
model.$setViewValue(undefined);
jq('input[name='+name+']').val('');
angular.forEach(model.$error, function(value, name) {
// reset validity
model.$setValidity(name, null);
});
});
$scope.form.$setPristine();
$scope.form.$setUntouched();

Disable HTML5 form validation in Grails Project

I've started to design and implement a blog-homepage in Grails to get practice with Grails development and HTML. I'm not that experienced with HTML4/5 yet.
My problem is that i want to disable HTML5's form validation which standard message is:"Please fill in this field" if the field is required and not filled, and instead use my own custom error-text that can be typed into the file i18n/messages.properties.
I have read these two question on how to disable form validation in plain HTML5 with either novalidate="" or autocomplete="off"
I have generated the scaffolded templates in my Grails project, by typing: install-templates.
My plan was to change the _form.gsp to include either autocomplete="off" or novalidate="" in the method renderFieldForProperty(), but neither are working.
Hope somebody have solved this problem and want to share knowledge ;)
Edit: Code from scaffolded renderFieldForProperty():
private renderFieldForProperty(p, owningClass, prefix = "") {
boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate')
boolean display = true
boolean required = false
if (hasHibernate) {
cp = owningClass.constrainedProperties[p.name]
display = (cp ? cp.display : true)
required = (cp ? !(cp.propertyType in [boolean, Boolean]) && !cp.nullable && (cp.propertyType != String || !cp.blank) : false)
}
if (display) { %>
<div class="fieldcontain \${hasErrors(bean: ${propertyName}, field: '${prefix}${p.name}', 'error')} ${required ? 'required' : ''}"> <-- At the end of this line i have tried the to attributes mentioned above
<label for="${prefix}${p.name}">
<g:message code="${domainClass.propertyName}.${prefix}${p.name}.label" default="${p.naturalName}" />
<% if (required) { %><span class="required-indicator">*</span><% } %>
</label>
${renderEditor(p)}
</div>
<% } } %>
Above if you scroll right i have written where i have tried the 2 attributes i mentioned in my post.
You need to customize renderEditor.template this file is responsible for render the form fields according to the Domain Class. As example I changed the isRequired() method:
private boolean isRequired() {
//!isOptional()
return false //always return false, not including the required='' in the field.
}