How to call other component function from different component? - javascript

I've html structure like this :
Parent Component where both Comp1 and Comp2 resides :
now in comp1 I've some elements if that changes then I've to reflect values in comp2 but there's no connection between them.
Comp1 :
import { Component } from '#angular/core';
import { Comp2Component } from 'comp2.component';
#Component({
selector: 'comp1',
templateUrl: './comp1.html'
})
export class Comp1Component {
sortBy(value)
{
this.FeedSortBy = value;
this.SortByLabel = this.SortByLabelList[value];
Comp2Component.filterActivities();
}
}
Comp2
import { Component } from '#angular/core';
#Component({
selector: 'comp2',
templateUrl: './comp2.html'
})
export class Comp2Component {
filterActivities()
{
//call this function on comp1 sort function call so it will update value of comp2
}
}
As per Rahul and Sajit's answer I try using with EventEmitter and change my structure to parent child :
In my parent component I use :
import { Component,EventEmitter, Input, Output, OnInit } from '#angular/core';
import { FeedsComponent } from '../feeds/feeds.component';
#Component({
selector: 'my-desk',
styleUrls: ['../../assets/css/style.min.css'],
templateUrl: './my-desk.component.html'
})
export class MyDeskComponent {
#Output() FeedSortBy = new EventEmitter<string>();
sortBy(value)
{
this.FeedSortBy.emit(value);
}
}
and in my child component I use :
import { Component, OnInit, Input, Output } from '#angular/core';
import { DataService } from '../data.service';
declare var $: any;
#Component({
selector: 'feeds',
styleUrls: ['../../assets/css/style.min.css'],
templateUrl: './feeds.component.html'
})
export class FeedsComponent {
constructor(private dataService:DataService)
{
}
#Input() FeedSortBy:number = 2;
}
Child component HTML :
{{FeedSortBy}}
But it always output 2 it doesn't change can I get any trigger as well to know if value is change so I call function there

You cannot do that, There are two possible ways you could achieve this,
use angular service to pass the data between two components
use Event Emitters to pass the value among the components.

You can call method of another component from a different component but it will not update the value of the calling component without some tweaking like
Event Emitters if they have a parent child relationship or Shared Services or using ngrx redux pattern
How to Call a different component method be like
Component1
test(){
console.log("Test");
}
Component 2
working(){
let component = new Component1();
component.test();
}
Now to update the value in component 2 you might have to use any of the above.
For Event Emitters follow this link
For Shared services follow this link
For ngrx follow this link

Related

Reloading multiple child component from parent in Angular 14

I have a problem with reloading my child component from parent component in Angular.
Here is an example of what I want to do.
This is my child component
import { Component } from "#angular/core";
#Component({
selector: "app-child",
template: `<p> {{ticks}} </p>`,
styleUrls: ["./child.component.css"]
})
export class ChildComponent {
ticks = Date.now().valueOf();
constructor() {}
update(): void {
this.ticks = Date.now().valueOf();
}
}
And here is my parent component:
import { Component, OnInit, ViewChild } from '#angular/core';
import { ChildComponent } from './../child/child.component';
#Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
#ViewChild(ChildComponent, { static: false }) childC: ChildComponent;
showChild: boolean = true;
constructor() {}
ngOnInit() {}
onUpdateChild() {
this.childC.update();
}
}
Parent Component HTML :
<p>
parent works!
<button (click)="onUpdateChild()">update</button>
<app-child *ngIf="showChild"></app-child>
<app-child *ngIf="showChild"></app-child>
</p>
The main problem is that if I use my child component multiple time, and trying to click on “update” button, it just updates one of my child component that is used in parent component, but I want to update all same child component in parent component, here is what happens when you click on “update” button, only first value will change, not both.
How can I fix it ?!?
You can use #ViewChildren and QueryList to do what you are looking for.
#ViewChildren(ChildComponent) childrenC!: QueryList<ChildComponent>;
And your function would look like:
onUpdateChild() { //I would rename it to onUpdateChildren
if(this.childrenC) {
this.childrenC.forEach((childC: ChildComponent) => {
this.childC.update();
});
}
}
If you wanted your child component to update on it's own - as stated by a comment to your original post - this is an example of what you could do so you wouldn't even need the update button:
import { Component, OnInit } from "#angular/core";
#Component({
selector: "app-child",
template: `<p> {{ticks}} </p>`,
styleUrls: ["./child.component.css"]
})
export class ChildComponent implements OnInit {
ticks = Date.now().valueOf();
constructor() {}
ngOnInit(): void {
setInterval(() => {
this.ticks = Date.now().valueOf();
}, 1000); //updates every 1 second
}
}
Another option you can do without using a button is to use #Input with the ticks property that updates the value from the parent through an input.

Angular - How can I toggle the visibility of an element in a component from another component?

I have the following scenario in my Angular app:
A component MainDashboardComponent that is visible when I have the route /. Obviously I have the <router-outlet> tag in my app.component.html file, which looks like this:
<app-side-menu></app-side-menu>
<div class="main-container">
<div class="content">
<router-outlet></router-outlet>
</div>
</div>
As you can see I have a SideMenuComponent I use to have a side menu on all my routes. In MainDashboardComponent I have a method that for some reason needs to toggle a chat element that is situated on the side menu.
Inside the SideMenuComponent I have a method that handles the visibility toggle for the chat element and it works as expected. How can I call this method from my MainDashboardComponent and toggle the chat element from there?
What I tried with no success
I tried to inject the SideMenuComponent inside my MainDashboardComponent but, though the method toggleChat() is called, the element doesn't change it's visibility. Looks like I have a kind of multiple instance of the same component I guess...
Can you please help me with this? Thank you!
MainDashboardComponent
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-main-dashboard',
templateUrl: './main-dashboard.component.html',
styleUrls: ['./main-dashboard.component.scss']
})
export class MainDashboardComponent implements OnInit {
constructor() { }
ngOnInit() {}
setFocus(id) {
// here I'd like to call SideMenuComponent togglechat() ...
}
}
SideMenuComponent
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-side-menu',
templateUrl: './side-menu.component.html',
styleUrls: ['./side-menu.component.scss']
})
export class SideMenuComponent implements OnInit {
showChat: boolean;
constructor() {
this.showChat = false;
}
ngOnInit() {
}
toggleChat() {
this.showChat = !this.showChat;
}
}
To communicate between different components, there are different ways.
If you want to communicate between parent and child component, you can use EventEmitter to emit event from child component and handle the event in your parent component
If you want to communicate between any components, you can use Service and implement communication with the help of EventEmitter or Subject/BehaviorSubject
In your case, we can create a service, myService.ts and declare and eventEmitter
.service.ts
#Injectable()
export class AppCommonService {
toggle : EventEmitter<boolean> = new EventEmitter<boolean>()
}
mainDashboard.component.ts
constructor(private myService : myService){}
chatStatus : boolean = false;
ngOnInit(){
this.myService.toggle.subscribe(status=>this.chatStatus = status);
}
toggleChat(){
this.myService.toggle.emit(!this.chatStatus);
}
sideMenu.component.ts
constructor(private myService : myService){}
chatStatus : boolean = false;
ngOnInit(){
this.myService.toggle.subscribe(status=>this.chatStatus = status);
}
Generally this is the domain of a service!
Just create a service and add the "showCat" property.
Inject the service into both components
Alter SideMenuComponent to:
toggleChat() {
this.myService.showChat = !this.myService.showChat;
}
Alter MainDashboardComponent, also use this.myService.showChat to show / hide your chat window
Service TS
#Injectable()
export class MyService{
showCat:boolean = true
}
MainDashboardComponent
toggleChat() {
this.myService.showChat = !this.myService.showChat;
}
SideMenuComponent
chatVisiblity = this.myService.showCat //<-- bind this to the element attribute
You could efficiently use child to parent communication in this scenario. You'll need to create a custom event using angular's EventEmitter in your SideMenuComponent and use it in your MainDashboardComponent.
So, here is some code that may help you -
// SideMenuComponent
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-side-menu',
templateUrl: './side-menu.component.html',
styleUrls: ['./side-menu.component.scss']
})
export class SideMenuComponent implements OnInit {
#Output() valueChange = new EventEmitter();
showChat: boolean;
constructor() {
this.showChat = false;
}
ngOnInit() {
}
toggleChat() {
this.showChat = !this.showChat;
this.valueChange.emit(this.showChat);
}
}
// MainDashboardComponent
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-main-dashboard',
template: `<app-side-menu (valueChange)='setFocus($event)'></app-side-menu>`
styleUrls: ['./main-dashboard.component.scss']
})
export class MainDashboardComponent implements OnInit {
constructor() { }
ngOnInit() { }
setFocus(event) {
// check for required input value
console.log(event);
}
}
Refer these tutorials if required -
https://dzone.com/articles/understanding-output-and-eventemitter-in-angular,
https://angular-2-training-book.rangle.io/handout/components/app_structure/responding_to_component_events.html

Pass changing array to child component #Input field

I am trying to pass an array to a child component. The array is being defined in the subscribe method of a parent component's onInit lifecycle hook.
Parent component:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'selector-parent',
templateUrl: 'parent.component.html'
})
export class ParentComponent implements OnInit {
array: [];
constructor() { }
ngOnInit() {
this.appDataService.getValues()
.subscribe(
value => {
value.item
.filter(loaded => !this.array.some(existing => existing.key === loaded.key))
.forEach(loaded => { this.array.push(loaded) })
}
)
}
}
Child component:
import { Component, OnInit } from '#angular/core';
#Component({
selector: '[selector-child]',
templateUrl: 'child.component.html'
})
export class ChildComponent implements OnInit {
#Input() inputArray: [];
constructor() { }
ngOnInit() {
console.log(this.inputArray)
}
}
Binding is: <tr selector-child [inputArray]="array"></tr>
Unfortunately, the console log on the inputArray is turning up undefined. I've tried using ngOnChanges in the child component but for some reason, it won't recognize the change in the parent. Thinking of using a service to pass the data if there isn't a simpler way to solve the problem.
You have to initialize the array in your parent component:
array: [] = [];
I don't see ngOnChanges in your child component. Also, make sure you do it as how it specified in the angular docs. https://angular.io/guide/component-interaction#intercept-input-property-changes-with-ngonchanges

cannot display array sent from one component to other in angular2

SERVICE--
import {Injectable} from '#angular/core';
import {UserData} from '../user-data/user-data.component';
#Injectable()
export class UserDataService {
constructor(){}
userdata:UserData[];
getData(){
console.log('service',this.userdata);
return this.userdata;
}
setData(user:any){
this.userdata=user;
console.log(this.userdata);
}
}
USER-DATA-class ---
export class UserData {
firstname: string;
middlename: string;
lastname: string;
email: string;
contact: number;
}
Component1 --
import { Component,OnInit,OnDestroy } from '#angular/core';
import { UserData } from '../../user-data/user-data.component';
import { ViewEditUser } from '../../view-edit-user/view-edit-user.component';
import {UserDataService} from '../../user-data-service/user-data-service.service';
#Component({
selector: 'form-page',
templateUrl: `app/add-user-sidebar/user-form/form.component.html`,
providers:[UserDataService]
})
export class Form implements OnInit,OnDestroy {
userdetail:UserData;
constructor(private service:UserDataService){
}
addUser(first:string,middle:string,last:string,emailid:string,contactno:number){
this.userdetail=({firstname:first,middlename:middle,lastname:last,email:emailid,contact:contactno})
console.log(this.userdetail);
this.service.setData(this.userdetail);
}
ngOnInit(){
}
ngOnDestroy(){
}
}
Component2--
import { Component,Input, OnInit } from '#angular/core';
import { Form } from '../add-user-sidebar/user-form/form.component';
import {UserData} from '../user-data/user-data.component';
import { WelcomePage } from '../welcome-page/welcome-page.component';
import {UserDataService} from '../user-data-service/user-data-service.service';
#Component({
selector:'view-edit',
templateUrl: 'app/view-edit-user/view-edit-user.component.html',
providers: [UserDataService]
})
export class ViewEditUser implements OnInit {
arraydata:any;
constructor(private service:UserDataService){}
// arraydata:any;
printarray(){
console.log(this.arraydata);
}
ngOnInit()
{
this.arraydata=this.service.getData();
console.log("hhghdfghdf",this.arraydata);
}
}
I am new to angular2, I have two components in my module, one component is a form where user inputs data, that data is then sent to a service, when I console.log it then I can see the data in service. but when I try to access that array from the second component then I can't access the data what to do?
If you provide the service on each component, you can't use it for communication, because each component will get a different service instance.
If one component is a parent (ancestor) of the other component, only provide it on the parent component.
Otherwise provide it on a component that is a parent (anjestor) of both or provide it only in #NgModule() to make the service global.
You also need to be aware that it's possible that one component reads, before the other set the value, depending on where you set the value and in what order the components are created.
Using a BehaviorSubject usually avoids this pitfall, because this way it doesn't matter which component is created first or if one component tries to read, while the other hasn't set the value yet.
For shareing between to Angular instances see also How to share service between two modules - #NgModule in angular2?
You nee to use observables to pass data between components.
In your service create a Subject type variable and in the your first component do a .next to pass data to the service and in your 2nd component, subscribe to the service veriable and it will get you the data.
You are not getting the data because of the async behavior of JavaScript which will be handled by observables

Angular 2 - Get passed object to component via inputs

On my parent page I have a link here:
<a (click)="showPermissionsRates(5757);">Link</a>
The function sets it:
showPermissionsRates(item) {
this.currentEventPoolId = item;
}
With a child component on the parent page here:
<app-event-pools-permissions-rates [eventPoolId]="currentEventPoolId "></app-event-pools-permissions-rates>
And then in my child component TS file I use:
inputs: ['eventPoolId']
But how do I get that value of '5757' in the child component? Such as using alert?
You should be able to just use #Input() on the child property.
I've put this together showing a VERY basic example, but without more to go on regarding your issues, it's hard to know what you need:
https://plnkr.co/edit/y9clOla1WrPFmhMJoz7o?p=preview
The gist is to use #Input() to mark your inputs in the child component, and map those in the template of the parent.
import {Component} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import { ChildComponent } from 'child.component.ts';
#Component({
selector: 'my-app',
template: `
<div>
<button (click)="changeProperty('ABC 123')">Click Me!</button>
<child-component [childProperty]="parentProperty"></child-component>
</div>
`,
})
export class App {
public parentProperty: string = "parentProp";
public changeProperty(newProperty: string) : void {
this.parentProperty = newProperty;
}
}
Then, in the child:
import {Component, Input} from '#angular/core'
#Component({
selector: 'child-component',
template: `
<div>Hello World: {{ childProperty }}</div>
`,
})
export class ChildComponent {
#Input()
childProperty:string;
constructor() {
this.childProperty = 'childProp'
}
}
I think you are setting value to at input variable in a click event, then you have to listen for it in the child component constructor using ngonchanges
ngOnChanges(changes: SimpleChanges) {
if(changes['eventpoolid'] && changes['eventpoolid'].currentValue) {
// you get updated value here
}
}

Categories