How to change the background color of input field when a button is clicked? - html

I would like to change my input field to change color when I click on a button. For extra information: the button's value itself changes when it is clicked.
This is the HTML I have right now:
<h2 class="label-custom">Tag</h2>
<input class="input" [readonly]="isReadOnly" formControlName="tag" [placeholder]="'Enter your tags' | transloco">
<button type="alter-button" class="alter-button" (click)="alter()">{{btnVal}}</button>
All the alter() function does is make the field readonly and change the button name. I can also change the color of the input field depending on what value the btnVal currently holds since the alter() function is called with each click. Is there a way I can change the background of the input field within the typescript file containing the alter() function?

You can modify the alter() function to something like this
import { Component, ElementRef } from '#angular/core';
#Component({
selector: 'app-root',
template: `
<h2 class="label-custom">Tag</h2>
<input class="input" [readonly]="isReadOnly" formControlName="tag" [placeholder]="'Enter your tags' | transloco">
<button type="alter-button" class="alter-button" (click)="alter()">{{btnVal}}</button>
`
})
export class AppComponent {
isReadOnly = false;
btnVal = 'Alter';
constructor(private elementRef: ElementRef) {}
alter() {
this.isReadOnly = !this.isReadOnly;
this.btnVal = this.isReadOnly ? 'Revert' : 'Alter';
const inputElement = this.elementRef.nativeElement.querySelector('.input');
inputElement.style.backgroundColor = this.isReadOnly ? 'lightgray' : 'white';
}
}

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';
}

Angular add dom element after current input in directive

I have two inputs:
<label for="date-string">String value</label>
<input [formControl]="dateString" type="date" id="date-string"/>
<br>
<label for="date-object">Date object with directive help</label>
<input [formControl]="dateObject" type="date" id="date-object"/>
I want to add a div straight after an input using a directive for all inputs type 'date' and have 'formControl' directive.
The only problème is how to add a dom element after current html element (using elementRef).
I've seen ppl talking about parent node, but i don't want to appendChild to the parent node (the new element will be at the very end of the node list but i need it to be straight after current input element).
Any idea?
You can break this down into two questions:
Q1: How to apply a directive to all input elements with type="date" and with the attribute formControl?
A1: When declaring a directive you can use any CSS selector to choose which elements the directive is applied to: https://angular.io/api/core/Directive#options
Q2: How to insert a div immediately after another element?
A2: Use insertBefore applied to the element's next sibling: https://stackoverflow.com/a/4793630/12914833
So the directive looks like this:
#Directive({
selector: 'input[type="date"][formControl]',
})
export class DateInputDirective {
constructor(private elRef: ElementRef) {
const el = elRef.nativeElement as HTMLElement;
const div = document.createElement('div');
div.textContent = 'Inserted Div';
div.style.backgroundColor = 'red';
// any other styling
el.parentNode.insertBefore(div, el.nextSibling);
}
}
Stackblitz: https://stackblitz.com/edit/angular-ivy-n4ault?file=src/app/date-input.directive.ts
<div *mydirective>
<label for="date-string">String value</label>
<input [formControl]="dateString" type="date" id="date-string"/>
</div>
<br>
<label for="date-object">Date object with directive help</label>
<input [formControl]="dateObject" type="date" id="date-object"/>
import { DOCUMENT } from '#angular/common';
#Directive({
selector: '[mydirective']
})
export class MyDirective implements OnInit {
constructor(
private elementRef: ElementRef,
private renderer: Renderer2,
#Inject(DOCUMENT) private document: Document) { }
ngOnInit() {
const child = this.document.createElement('div');
this.renderer.appendChild(this.elementRef.nativeElement, child);
}
}
So with css/sass techniques to can set the appropriate position for your new element

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/

angular : passing the input value to the component

I want to affect the value of this input to a variable 'numToAdd' which is in my component and then add 1 to the variable 'numToAdd', but I can't pass the value of the html input to my component variable 'numToAdd'. How to bind my html input to a variable in the component ?
my html code
<input type="number" id=num class=num>
my component
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-afficher-projets',
templateUrl: './afficher-projets.component.html',
styleUrls: ['./afficher-projets.component.css']
})
export class AfficherProjetsComponent implements OnInit {
ngOnInit(): void {}
numToAdd: number;
constructor() { }
add: void {
this.numToAdd++;
}
}
Two-way binding a primary functionality of angular. Use the ngModel directive to bind input to variables.
<input type="number" id="num" class="num" [(ngModel)]="numToAdd">
The above code binds the variable numToAdd with the input. Find more details here

Angular 7 components: how to detect a change by user interaction?

I have a component with several checkboxes, drop-downs, and a save button.
Here is a simplified example component template:
<aside class="container">
<div class="row">
<input
type="checkbox"
id="all-users"
[(ngModel)]="showAllUsers"
(ngModelChange)="onChange($event)"
/>
<label for="all-users">Show all users</label>
</div>
<div class="row">
<ng-select
[(ngModel)]="selectedUser"
[clearable]="false"
appendTo="body"
(change)="onChange($event)"
>
<ng-option *ngFor="let user of activeUsers" [value]="user">{{ user }}</ng-option>
</ng-select>
</div>
<div class="row">
<button type="button" class="btn btn-primary" [disabled]="!dirty" (click)="onSave()">
Save Changes
</button>
</div>
</aside>
I want to enable the Save Changes button only when the user made a change, either by unchecking the check-box or changing a selection in drop-down box.
Right now I have an event handler registered at each and every control in the component (the onChange function in the example above), and use a dirty flag to disable or enable the Save Changes button.
Here is the component.ts for the above template:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-filter',
templateUrl: './filter.component.html',
styleUrls: ['./filter.component.css']
})
export class FilterComponent implements OnInit {
dirty: boolean;
showAllUsers: boolean;
selectedUser: string;
activeUsers: string[];
ngOnInit() {
this.dirty = false;
this.showAllUsers = true;
this.activeUsers = ['Thanos', 'Thor', 'Starlord'];
this.selectedUser = 'Thor';
}
onChange(event) {
console.log('Event is ' + event);
this.dirty = true;
}
onSave() {
console.log('Gonna save changes...');
this.dirty = false;
}
}
Registering the event handler to every control does not seem intuitive to me.
Is this the correct approach to figure out a change made by user or does angular provide a different way to achieve this?
I would highly recommand using both FormGroup and FormControl to achieve this behavior.
Both exposes the dirty property, a read-only boolean.
The dirty property is set to true when the user changes the value of the FormControl from the UI. In the case of the FormGroup, the dirty property is set to true as long as at least 1 of the FormControl in that group is dirty.
As a side note, the property pristine is the opposite property. So you can use one or the other if it simplifies the condition.
[disabled]="myFormGroup.pristine" might be easier to read than [disabled]="!myFormGroup.dirty".