Detect if a boolean changes Angular 8 - html

I have this ngbCollapse in my html:
<div style="margin: 1.5em 1.5em;" [ngbCollapse]="isCollapsed">
//things
</div>
In my component, I would call a method everytime isCollapsed changes:
export class Component implements OnInit {
public isCollapsed = true;
constructor(private Serv: _service) {}
ngOnInit() {}
//Everytime isCollapsed changes I would call this method
isCollapsedInService () {
this._service.set(isCollapsed);
}

I would suggest you use Event Binding in Angular
In Angular 8, event binding is used to handle the events raised from the DOM like button click, mouse movement etc. When the DOM event happens (eg. click, change), it calls the specified method in the component.
https://www.javatpoint.com/event-binding-in-angular-8#:~:text=In%20Angular%208%2C%20event%20binding,specified%20method%20in%20the%20component.

In html file
<button (click)="isCollapsedInService($event)">Btn</button> <!--Event Binding-->
In .ts file
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
isCollapsedInService($event){
console.log("Button is clicked!", $event);
}
}

Related

I need to have a 'container' template that has to show MyComponent upon certain condition 'externalCondition' MyComponent uses Form and formValidation

container.html
<div ngIf="externalCondition"> <!--Initially this is false. Later became true --!>
<my-component #MyComponentElem > </my-component>
<button [disabled]= "!myComponentElemRef.myDetailsForm.valid" (click)="myComponentElemRef.AFunctionInsideComponent()"> </button>
</div>
container.ts
#Component({
selector: 'my-component',
templateUrl: './comm-roleplay-end2end.html',
styleUrls: ['./comm-roleplay-end2end.scss']
})
export class Container {
#ViewChild('MyComponentElem', { static: true }) private myComponentElemRef: MyComponent;
}
mycomponent.ts
#Component({
selector: 'my-component',
templateUrl: './my-component.html',
styleUrls: ['./my-component.scss']
})
export class MyComponent {
public externalCondition:Boolean = false;
public myDetailsForm: FormGroup;
constructor()
{
//my form builder
}
//
public AFunctionInsideComponent()
{
}
}
Based on myDetailsForm.valid, I need to turn on something in my container.
Issue is that myComponentElemRef is 'undefined' because the element is not created initially. It is visible only after 'externalCondition' becomes true. Upon button click, I need the FormGroup of MyContent to be visible.
But it gets stuck in script error due to
TypeError: reading undefined (myComponentElemRef)
Please suggest the best mechanism to handle the situation
try using [hidden] instead of ngIf, that way the component is created but not visible

Angular: How to send string values to another component using EventEmitter?

I have a parent component and a child component, I want to send 2 values from the child component via EventEmitter to the parent component as I want to use the printMessages() function there.
I have a click event on the child component which emits 2 string values, but I'm unsure how to connect the emit event to the parent component and for the printMessages() function to run. How can the parent component read these values into the "printMessages()" function and for that function to run after the values have reached it? As you can see, I currently have no HTML in the parent component, perhaps I need to do something there?
Parent Component:
import { Component } from '#angular/core';
#Component({
selector: 'parent-component',
template: ``,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
// Function in which I want to send values from the child component.
printMessages(string1: string, string2: string) {
console.log(string1, string2);
}
Child Component:
import { Component, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'child-component',
template: `
<button (click)="sendStrings()">Send Strings</button>
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
#Output() message = new EventEmitter();
constructor() { }
sendStrings(){
this.message.emit({string1:"Hello", string2:"World!"});
}
}
You need to react on the child components event within the template and call the method.
import { Component } from '#angular/core';
#Component({
selector: 'parent-component',
template: `<child-component (onMessage)="printMessages(e)"></child-component>`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
printMessages(event) {
// strings are included in event object
}
}

Angular: sanitizer.bypassSecurityTrustHtml does not render attribute (click)

I try to render a button and it works fine, but when I click the button it doesn't execute alertWindow function, help!:
app.component.ts:
import {
Component,
ElementRef,
OnInit,
ViewEncapsulation } from '#angular/core';
import { DomSanitizer, SafeHtml } from "#angular/platform-browser";
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
encapsulation: ViewEncapsulation.ShadowDom,
})
export class AppComponent implements OnInit {
public content: SafeHtml;
constructor(private sanitizer: DomSanitizer) {}
async ngOnInit() { this.renderButton(); }
alertWindow() { alert("don't work"); }
renderButton() {
this.content =
this.sanitizer.bypassSecurityTrustHtml(`
<button (click)='connectWallet()' class="button">
Connect your wallet
</button>`);
}
app.component.ts;
<div [innerHTML]="content"></div>
Solution
Based on what I understand you wanted to display HTML dynamically at runtime? then solution is to use
ComponentFactoryResolver
and ViewContainerRef
It will be better if you can provide more details, what you are trying to achieve, so that people can guide you
Why it didn't work?
It doesn't work because it is outside of angular, when you use innerHTML then whatever you passed to it is pure vanilla HTML and JavaScript
Try this example
(window as any).alertWindow = function () {
alert("don't works");
};
#Component({...})
export class AppComponent {
...
renderButton() {
this.content = this.sanitizer.bypassSecurityTrustHtml(`
<button onclick='alertWindow()' class="button">Connect your wallet</button>
`);
}
}
It works right?
As you can see I have moved alrertWindow function outside of component's class and added to window variable and also changed (click) to onclick

How to call a component from other component in angular 7

I have a checkbox,if that checkbox is checked, I need to show alert message on load the application.But problem is that checkbox is in header component and it is linked with home component.So when I will be in home page and if that checkbox is checked, I need to show alert message on load the application. Here is the code below,
header.component.html
<div><input checked type="checkbox">Other-component</div>
header.component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router";
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
constructor(public router: Router){}
ngOnInit() {}
}
home.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import Speech from 'speak-tts';
import { RxSpeechRecognitionService, resultList, } from '#kamiazya/ngx-speech-recognition';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css'],
providers: [ RxSpeechRecognitionService ]
})
export class HomeComponent implements OnInit {
showit:any;
nestedjson:any;
constructor(private formBuilder: FormBuilder,public service: RxSpeechRecognitionService) {
}
ngOnInit() {
}
}
1) To the question in your headline: How to call a component from other component
You can give the header component a reference id inside the home template.
<app-header #header></app-header>
Then you can access the header component through a ViewChild in your home component.
#ViewChild('header') headerComponent: HeaderComponent;
But this does not seem to be very good practice for your needs. Consider using a service and subscribe to a Subject by using RxJs Observables. Or much simpler in your case: just use two-way-data-binding.
2) The way you should actually communicate between components: two way data binding
header.component.ts
export class HeaderComponent implements OnInit {
#Input() isChecked: boolean;
#Output() isCheckedChanged = new EventEmitter<boolean>();
constructor(public router: Router){}
ngOnInit() {
}
}
header.component.html
<input [(ngModel)]="isChecked" type="checkbox">
home.component.ts
export class HomeComponent implements OnInit {
isChecked: boolean;
constructor() {}
ngOnInit() {
}
}
home.component.html
<app-header [(isChecked)]="isChecked"></app-header>
Edit: in your case you also don't need two way binding since you don't need any feedback from the HeaderComponent. One way data binding will be fine. Then you can remove the line
#Output() isCheckedChanged = new EventEmitter<boolean>();
And in Home template don't use banana in the box syntax [()], instead just use []:
<app-header [isChecked]="isChecked"></app-header>
You can make use of a service which is defined at the root level.And then with the help of a service you can either emit or use Subjects to capture in your home component.

Component Interaction #Input

I would like a component to send input to another component. Below is the code .ts and .html. of the two components.
Now the problem is that the html page of the parent component also shows the html part of the child component ... I want the component to pass only one string to the child component
Parent.ts
import ...
#Component({
selector: 'app-parent',
templateUrl: './parent.html',
styleUrls: ['./parent.css']
})
export class ParentComponent implements OnInit {
sostegno : string;
constructor() { }
ngOnInit() { }
avvia1() {
this.sostegno = "xxx";
this.router.navigate(['./xxx'], { relativeTo: this.route });
}
avvia2()
this.sostegno = "yyy";
this.router.navigate(['./yyy'], { relativeTo: this.route });
}
}
Parent.html
<div>
...
</div>
<app-child [sostegno]="sostegno"></app-child>
Child.ts
import ...
#Component({
selector: 'app-child',
templateUrl: './child.html',
styleUrls: ['./child.css']
})
export class ChildComponent implements OnInit {
#Input() sostegno : string;
constructor() { }
ngOnInit() {
console.log(this.sostegno);
}
}
There are some changes which you need to make because looking at the code which your currently have it seems incomplete.
You are using this.router without injecting the Router class in your constructor.
You are using this.route without injecting the ActivatedRoute class in your constructor.
To test that your parent > child interaction is working you can remove your param and instead place a test for the html
<app-child [sostegno]="'Test'"></app-child>
This should work for your ngOnInit function which is inside of your child component. If this works all you need to do now is either initialize sostegno in your parent component else your console log inside your child component will not reflect the changes when you call avvia1 or avvia2 inside of your parent class.
Hope this helps!