Conditionally toggle class in angular 2 - html

I need to toggle a class "active" on in app-component whenever a button in "app-header" component is clicked.
Here is my app-component.html,
<div class="off-canvas">
<app-header><app-header>
<app-home></app-home>
<app-footer></app-footer>
</div>
app-header.html
<div>
<!--Some code-->
<button></button>
</div>
How can I do this using only angular since the div and button are in 2 different components????please help I am new to angular!!!

You can bind your object to the [ngClass] directive:
<div [ngClass]="{'active': isActive, 'disabled': isDisabled}">
To share data between components, see this answer: https://stackoverflow.com/a/45371025/1791913

You can use EventEmitter.
app-header.html
<div>
<!--Some code-->
<button (click)="emitClick()"></button>
</div>
app-header.ts
#Output() _clickEvent:EventEmitter<any>=new EventEmitter();
constructor(){
}
ngOnInit(){
}
emitClick($event){
this.clickEvent.emit()
}
app-component.html
<div class="off-canvas" [ngClass]="{'someClassName':active}">
<app-header (_clickEvent)="toggleActive($event)"><app-header>
<app-home></app-home>
<app-footer></app-footer>
</div>
app-component.ts
active:boolean=false;
constructor(){
}
ngOnInit(){
}
toggleActive($event){
// Insert click event handling here
}
You should declare active variable in your app-component.ts and initialized it to Boolean. Every click will cause the active to toggle between true and false.
A class named 'someClassName' will be added by the ngClass whenever the 'active' variable it true.

You can create a common service and store a variable as public, example:
#Injectable()
export class DataService{
foo:string;
}
Then use variable in the both components as a shared variable, example:
#Component({...})
export class FooComponent{
constructor(private dataService:DataService){}
foo():void{
console.log(this.dataService.foo);
}
}

Related

Get value of a variable in one component to another component using ngmodel

I have two components first and second. From the second component, I am calling the first component. In the first component, I have a matslider module and I want to get that slider on/off status to my second component ts file. So I am getting that value in first, but don't know how to pass that to the second component.
first.component.html
<div>
<mat-slide-toggle class="toggles"
(change)="OnToggle($event)
[(ngModel)]="selected">Toggle</mat-slide-toggle>
</div>
first.component.ts
#Input() selected=false;
public OnToggle(event)
{
this.selected = event.selected;
}
second.component.html
<div class="container">
<app-first> </app-first>
</div>
I think you can use an output event in the first component and bind to it in the second component.
here it is example:
First Component:
#Output() selectedChange = new EventEmitter<boolean>();
public OnToggle(event) {
this.selected = event.selected;
this.selectedChange.emit(this.selected);
}
SecondComponent:
<app-first (selectedChange)="onSelectedChange($event)"></app-first>
public onSelectedChange(selected: boolean) {
console.log(selected);
}

Angular 10 scrollTo from parent component to an element in child component html

parent html:
<div>
<button type="button" (click)="scroll(childelementTwo)">TO CHILD</button>
</div>
<div>
<app-child>
</div>
child html:
<div>
<div #childelementOne>
lot of stuff
</div>
<div #childelementTwo>
another lot of stuff
</div>
</div>
if all this html code were in the "same" component.html I would use this function, but not:
scroll(el: HTMLElement) {
el.scrollIntoView();
}
So: How can I scroll to an html element in child component ?
You can use #ViewChildren for this.
List-Item:
#Component({
selector: 'app-list-item',
templateUrl: './list-item.component.html',
styleUrls: ['./list-item.component.css']
})
export class ListItemComponent implements OnInit {
#Input() list;
constructor(private elRef: ElementRef) { }
ngOnInit() {
}
scrollIntoView() {
this.elRef.nativeElement.scrollIntoView();
}
}
List-Component:
#ViewChildren(ListItemComponent) viewChildren!: QueryList<ListItemComponent>;
list = new Array(1000).fill(true)
scrollTo() {
this.viewChildren.toArray()[100].scrollIntoView()
}
HTML:
<button (click)="scrollTo()">scroll to 100</button>
<app-list-item *ngFor="let item of list">
list works!
</app-list-item>
stackblitz: https://stackblitz.com/edit/angular-ivy-6ccaav?file=src%2Fapp%2Fapp.component.html
Mat, your "elements" are in child and you want control in parent. So, first make access to the elements in child using ViewChild
//in your child.component
#ViewChild("childelementOne") childelementOne;
#ViewChild("childelementTwo") childelementTwo;
Then in parent you can do
<div>
<button type="button" (click)="scroll(childComponent.childelementTwo)">
TO CHILD
</button>
</div>
<div>
<!--see that use a template reference variable to the childComponent-->
<app-child #childComponent></app-child>
</div>
scroll(el: ElementRef) {
el.nativeElement.scrollIntoView();
}
See how, in the .html we are using childComponent.childelementTwo. childComponentis the own component app-child, childComponent.childelementTwo is the "variable" that we get in the #ViewChild. By defect is an ElementRef. You get to the HTMLElement using el.nativeElement. Yes, using a template reference we can access to all the public variables and public function of your child.component
I create a stackblitz that is looks like the stackblitz in enno's answer, but see that is complety different
NOTE. You can also use the same referenceVariable in the child.component and use ViewChildren, so you can pass to the function the QueryList and the index

Property 'authenticationService' is private and only accessible within class 'AdminComponent'

I am trying to deploy am angular project but I keep on getting this error from this class.
<div class="page-content">
<app-breadcrumb [breadcrumbs]="breadcrumbs"></app-breadcrumb>
<mat-toolbar class="toolbar-header">
<mat-toolbar-row>
<span class="font-larger">Welcome {{authenticationService.getName()}}!</span>
<span class="mat-toolbar-spacer"></span>
</mat-toolbar-row>
</mat-toolbar>
<mat-grid-list cols="3" rowHeight="240px" class="app-admin-tiles">
<mat-grid-tile *ngFor="let element of tools"
[colspan]="element.cols"
[rowspan]="element.rows"
>
<app-admin-tile
[color]="element.color"
[text]="element.text"
[icon]="element.icon"
[url]="element.url"
style="width: 100%;"
></app-admin-tile>
</mat-grid-tile>
</mat-grid-list>
</div>
enter image description here
please assign authenticationService.getName() to a variable and use it in template..
in ts eg:
ngOnInit() {
this.name = authenticationService.getName();
}
in template use like <span class="font-larger">Welcome {{name }}!</span>
Expanding from my comment here, it's isn't a good idea to bind a function in template expression or data-binding with default change detection strategy. Instead call the function in the component controller and bind the result from it in the template.
Try the following
Controller
export class AppComponent implements OnInit {
name: string;
constructor(private authenticationService: AuthenticationService) { }
ngOnInit() {
this.name = this.authenticationService.getName(); // <-- get name here
}
}
Template
<!-- Show only if the `name` is initialized with a valid value -->
<span *ngIf="name" class="font-larger">Welcome {{ name }}!</span>
...

How to close modal in angular 6

I am trying to close modal from home component.my close button is in home component.If i click close button i want to close modal.If i click close button from home component how to set visible value is false from home component. How can i use service for that? or any other way is there? How do it?
dialog.component.html
<div [#dialog] *ngIf="visible" class="dialog">
<ng-content></ng-content>
<button *ngIf="closable" (click)="close()" aria-label="Close" class="dialog__close-btn">X</button>
<app-home></app-home>
</div>
<div *ngIf="visible" class="overlay" (click)="close()"></div>
home.component.ts:
<button (click)="showDialog = !showDialog" class="btn">Close</button>
Demo: https://stackblitz.com/edit/angular-7zdnwy?file=src%2Fapp%2Fdialog%2Fdialog.component.html
I followed this approach from Angular Documentation and it works ok.
You Parent is Dialog and child is app-home. So emitter is defined in child class like this
export class HomeComponent implements OnInit {
#Output() close = new EventEmitter<boolean>();
...
// <button (click)="onClose()" in html
onClose() {
this.close.emit(true)
}
}
and listen for the event in parent dialog class like this
// html
<app-home (close)="onCloseClick($event)"></app-home>
// Class code
export class DialogComponent implements OnInit {
...
onCloseClick(close: Boolean) {
if(close){
this.close()
}
}
...
}
Hope it helps.

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".