Using Angular 8 to change the attribute value of a div - html

In Angular 8, I'm trying to change the value of an element so that I can mask and unmask a text field at the click of a button. The way it is now, the UI has admin controls that when turned on (the showOTP input), it allows a user to have an 'eye' icon to mask and unmask the text. The HTML for this div is here:
OTP HTML
<div class="toggle-otp">
<toggle-otp [showOTP]="toggleOTPEnabled">
<mat-form-field>
<input matInput type="text" fontName="passwordFont">
</mat-form-field>
</toggle-otp>
</div>
The CSS is configured to have the font be a masked version of the text, or be normal text depending if the user hit the button to mask/unmask the field
OTP CSS
toggle-otp input[fontName=passwordFont] {
font-family: passwordFont;
}
toggle-otp input[fontName=unmask] {
font-family: plaintext;
}
Where I'm getting tripped up with this is the OTP TypeScript isn't what is handling the fontName being changed, it's being exported to a separate input component called toggle-otp that holds the button that is displayed for when the admin controls have password masking/unmasking enabled.
OTP TS
export * from ./lib/toggle-otp
TOGGLE-OTP HTML
<div class="toggle-otp-button *ngIf="showOTP">
<button id="toggle-otp" type="button" (click)=otpField.fontName = togglePasswordFont(passwordField.fontName)
</button>
</div>
TOGGLE-OTP TS
#Component({
selector: 'toggle-otp'
})
export class ToggleOTPComponent {
#ContentChild(MatInput) otpField;
togglePasswordFont(font) {
let togglePasswordFont;
font === 'unmask' ? (togglePasswordFont = 'passwordFont') : (togglePasswordFont = 'unmask')
return togglePasswordFont;
}
}
Every thing is working as expected except that the fontName of the OTP HTML is not being updated with the value of 'unmask' to change the font styling, and I'm not sure how I can accomplish this when using an input component.
I have tried using [attr.fontName] in the OTP HTML, but I don't think it's actually binding to the input component TOGGLE-OTP, and thus I can't get the fontName to change it's value.

Related

Why property binding to the color of a text element is not reactive in angular?

Below is my .ts file,
import { Component } from '#angular/core';
#Component({
selector: 'app-event-binding',
templateUrl: './event-binding.component.html',
styleUrls: ['./event-binding.component.css']
})
export class EventBindingComponent {
textColor = '';
onInput = (ev: any) => {
this.textColor = ev.target.value;
}
}
Below is my HTML template ,
<div>
<h3 [style.color]="textColor">EVENT BINDING</h3>
<input type="text" (input)="onInput($event)">
</div>
Here when I completely type "blue" in the input box my text color of h3 changes to blue.
But I noticed when i press backspace and now the value of textColor is "blu" , the text still remains in Blue color. I was expecting return to black.
It changes to black only when I clear the entire input.
So is there some kind of history retaining in the color in html? What does this?
The same happens when maninpulating the DOM with plain JavaScript, I have prepared an example for you:
document.querySelector('input').addEventListener('input', event => {
document.querySelector('h3').style.color = event.target.value;
})
<h3>EVENT BINDING</h3>
<input type="text">
When trying to set a value which the browser considers as invalid, the operation is not performed. You can see in the DOM that the value of the inline style is not updated. In this case, the last valid value will be used. Angular works the same than plain JavaScript here.
As a workaround, you can check whether the entered value is valid with CSS.supports(), and fall back to black:
onInput = (ev: any) => {
const value = ev.target.value;
this.textColor = CSS.supports('color', value) ? value : 'black';
}

ngClass-Angular with input and css

when the input variable is touched I would like it to change the css, but I'm having difficulties, when I click on the input it doesn't change the css, can anyone help me?
The idea would be that when the input was changed, the card would turn upside down with the css "hover"
enter image description here
enter image description here
enter image description here
One way to detect if input has been touched would be to use event callbacks (such as click listener on the form).
#Component({
selector: 'input-clearable-example',
templateUrl: './input-clearable-example.html',
styleUrls: ['./input-clearable-example.css'],
})
export class InputClearableExample {
value = 'Clear me';
isTouched: boolean = false;
onTouch(event: any) {
console.log(event)
this.isTouched = true;
}
}
<mat-form-field class="example-form-field" appearance="fill"
(click)="onTouch($event)" [ngClass]="{'background-red' : isTouched}">
<mat-label>Touch me!</mat-label>
<input matInput type="text" [(ngModel)]="value"/>
</mat-form-field>
.background-red {
background: red;
}
Working example: https://stackblitz.com/edit/angular-by3kvr-5wv7oo?file=src%2Fapp%2F.%2Finput-clearable-example.html
An even more correct way would be to actually check if the form has been touched https://www.geeksforgeeks.org/how-to-check-whether-a-form-or-a-control-is-touched-or-not-in-angular-10/

Accessibility with complex custom components

Accessibility guidelines were invented before components were released, so they always say that a label is used to identify a form control like <input> or <textarea>, etc. What happens when I have a complex Angular / React / ... component that acts like a form control?
Imagine a <custom-select> that renders an input and adds items to a list. The resulting html looks like:
<custom-select ....>
<input ...>
</custom-select>
When I type something in the input and I press enter, it adds that entry to the list and renders the input again, something like:
<custom-select ....>
<span>What I typed</span>
<input ...>
</custom-select>
Of course, if I type something else in the input and I press enter, it gets added to the list:
<custom-select ....>
<span>What I typed</span>
<span>Something else</span>
<input ...>
</custom-select>
If we want to use this custom component in a form, we would like to put a label to it like any other form item, p.e:
<label for="foo">Foo</label>
<input id="foo" type="text">
<label for="select">Select a country</label>
<custom-select id="select"></custom-select>
Is this even valid a11y? Wave tool will complain of an orphan label while axe says nothing. So, can we use a plain old label to tag a custom component for accessibility purposes? We need a label to be put there for consistency but needs to be accessible.
In case I can do this, that custom-select is also rendering an input. That input needs its own label or aria-label, right?
Yes the input will need to be labeled.
Is there any reason for the component to not manage this? Accept the labeling text and then render the correct accessible HTML for the label and input pair?
So in React:
<CustomSelect labelText="Enter your destination" />
with the component doing:
const id = generatedUniqueId() // This will need to be memoized in the real implementation to avoid creating new id's with every render.
...
<>
<label for={id}>{labelText}</label>
<input id={id} />
</>
Atleast in angular: You can preserve a11y like the following:
// Custom Input HTML (Using Angular Material for eg);
// You can import the label inside the custom component and bind it to the
input field so that you can always have a new ID to every custom input
<mat-form-field [attr.aria-labelledby]="customAriaLabelledByIDs">
<mat-label *ngIf="label" [for]="customId">{{ label }}</mat-label>
<input matInput [id]="customId" />
</mat-form-field>
// In your component.ts file,
#Input() customId: string;
#Input() customAriaLabelledByIDs: string[];
combinedAriaLabelledByIDs: string;
ngOnInit() {
if (this.customAriaLabelledByIDs) {
this.combinedAriaLabelledByIDs =
this.customAriaLabelledByIDs.length === 1
? this.customAriaLabelledByIDs[0]
: this.customAriaLabelledByIDs.join(' ');
}
}
/// Wherever you use, now you will have something like this:
<your-custom-selector
[customAriaLabelledByIDs]="['id-1', 'id-2', 'id-3']"
[customId]="first-name-ID"
></your-custom-selector>
<your-custom-selector
[customAriaLabelledByIDs]="['id-4', 'id-5', 'id-6']"
[customId]="second-name-ID"
></your-custom-selector>
etc.,
You can add multiple aria-attributes to the #Input() and use it from the custom component like, aria-label, role, aria-expanded, etc...
Let me know if you need any more explanation on any of the things i mentioned above. Will be happy to help!!

How to set value to SCSS variables from HTML?

I have gone through this link and it doesn't answer my questions.
Passing values from HTML to SCSS
I am building a web application wherein an admin can go and set custom properties such as
1) changing global font size
2) changing the panel background colors
3) changing button color
4) changing button dimensions etc.
I have looked at PrimeNg designer API and I see that they have a list of about 500 variables in their scss file.
What I would like to do is create a form so that user can set the values on the UI.
Scenario 1-->
Example -->
<p-fieldset legend="Global Font Size">
<input type="text" pInputText placeholder="Enter the global font size">
</p-fieldset>
once the user enters a value here, I want the value of the following variable that's contained inside of scss file to be updated with what the user entered above.
$fontSize:14px;
Scenario 2 -->
Example -->
<p-fieldset legend="Global Font Size">
<input type="text" pInputText placeholder="Enter the global font size">
<button (onClick)="saveGlobalFontSize(fontSize)"> OK </button>
</p-fieldset>
1) How can I accept a value on the UI and update the value of scss variable as asked in scenario 1?
2) How can I accept a value on the UI, pass it to a typescript function and then update the value of scss variable as asked in scenario 2?
Here is the documentation that I am referring -->
https://www.primefaces.org/designer-ng/#/documentation
I really appreciate the folks who took time to answer my question but unfortunately that wasn't what I was looking for.
The simplest answer is -->
1. Create css variables in your styles.css file.
Example :
:root {
--body-color: yellow;
--text-color: red;
--font-size: 50px;
}
Then assign those variables to the properties such as -->
input {
color: var(--text-color);
}
Then in your HTML -->
<div class="ui-fluid">
<div class="ui-g">
<div class="ui-g-12">
<div class="ui-g-3">
<p-fieldset legend="Global Font Size">
<input type="text" placeholder="Enter the global font size">
<button pButton label="Save"></button>
</p-fieldset>
</div>
</div>
</div>
</div>
In your TS file -->
import { Component, Input, OnInit } from '#angular/core';
import { TableBody } from 'primeng/table';
#Component({
templateUrl: './miscdemo.component.html'
})
export class MiscDemoComponent implements OnInit {
input = document.querySelector('input');
body = document.querySelector('body');
fontSize = document.querySelector('input');
button = document.querySelector('button');
constructor() {
}
ngOnInit() {
if (this.input) {
this.input.addEventListener('change', () => {
this.body.style.setProperty('--body-color', this.input.value);
this.fontSize.style.setProperty('--body-color', this.input.value);
} );
}
this.input = document.querySelector('input');
this.button = document.querySelector('button');
if (this.input) {
this.button.addEventListener('click', () => {
this.body.style.setProperty('--body-color', this.input.value);
this.body.style.setProperty('--font-size', this.input.value + 'px');
} );
}
}
}
A great working example is here -->
https://jsfiddle.net/btg5679/9e22zasm/5/
For changing font size, you can use relative font sizes and just set the main font size when you want to change the font size scale. You can see how to do it here.
For changing colors and other values, you can use CSS values as described here.
SCSS is compiled down to CSS so by the time the browser is running it you cannot change the values assigned to SCSS variables.
However using CSS custom properties, also called CSS variables you can. https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties

Angular 2 html form validation

I've created a form using html validations with Angular 2.
I want to to check the sate of the inputs (no empty, correct format, etc) when the user click to a certain button. At the moment I'm doing it as following:
<form id="memberForm" #memberForm="ngForm" >
<input
type="text"
id="MemberName"
required
name="MemberName"
[(ngModel)]="newMember.name">
</form>
<div
[ngClass]="{'button_disabledButton' : !memberForm?.valid}"
(click)="onSubmit(memberForm?.valid, memberForm);">
<span>Next</span>
</div>
With this, I'm only evaluating the input once clicked and focus out. How can I make it hapens when the user click in the "Next" element?
You should make getter/setter solution for your ngModel input.
In the .ts file in the appropriate class put this:
savedVar:string = '';
get variable(): string {
return this.savedVar;
}
set variable(str: string) {
this.savedVar = str;
// do your validation
}
In template use ngModel=variable like this:
<input [(ngModel)]="variable">