简体   繁体   中英

Proper way to call a function of one component from another component

I have two components.

Component 1 is a little FAB menu icon thing that CALLS the function

@Component({
selector: 'app-contextualmenu',
templateUrl: './contextualmenu.component.html',
styleUrls: ['./contextualmenu.component.scss']
})
export class ContextualMenuComponent implements OnInit {
context: string;    

constructor(private ctxMenu: ContextualMenuSyncService, ) {
    ctxMenu.context$.subscribe(v => { this.context = v; });
}

ngOnInit() {}

add() {
    this.ctxMenu.add();
}
}

Component 2 is a component that has the function being CALLED

@Component({
selector: 'app-sites',
templateUrl: './sites.component.html',
styleUrls: ['./sites.component.scss']
})
export class SitesComponent implements OnInit {
list: Site[];

constructor(private ctxMenu: ContextualMenuSyncService) {
    this.ctxMenu.sync("sites");
    this.ctxMenu.add = this.add;
}

ngOnInit() {   }

add() {       
    this.router.navigateByUrl("/newsite");
}
}

Lastly there is a ContextualMenuSyncService that acts a conduit between two components.

@Injectable()
export class ContextualMenuSyncService {
private context = new Subject<string>();
context$ = this.context.asObservable();

add: Function;

constructor() { }

sync(value: string) {
    this.context.next(value);
}
}

So in a nutshell I am trying to call add() of Component 2 from add() of Component 1

According to what I have read on this topic a shared service as above is an appropriate way to accomplish inter-component communication.

My problem however is that when I call add() it is being executed out of ContextualMenuSyncService context. Meaning the this is ContextualMenuSyncService and not SitesComponent ( Component 2 ) which means I have no access to SitesComponent ( Component 2 ) members, injects, info, etc.

How do you call a member function of a component from another component within first component's context?

You'd do it more like this:

Component where function is running:

@Component({
selector: 'app-sites',
templateUrl: './sites.component.html',
styleUrls: ['./sites.component.scss']
})
export class SitesComponent implements OnInit, OnDestroy {
list: Site[];
private addSub;

constructor(private ctxMenu: ContextualMenuSyncService) {
    this.ctxMenu.sync("sites");
    this.addSub = this.ctxMenu.add$.subscribe(() => this.add());
}

ngOnInit() {   }

ngOnDestroy() { this.addSub.unsubscribe(); } // always unsubscribe

add() {       
    this.router.navigateByUrl("/newsite");
}
}

Service:

@Injectable()
export class ContextualMenuSyncService {
private context = new Subject<string>();
context$ = this.context.asObservable();

private addSource: Subject<any> = new Subject();
add$: Observable<any> = this.addSource.asObservable();
add() {
    this.addSource.next();
}

constructor() { }

sync(value: string) {
    this.context.next(value);
}
}

the function calling the service is fine.

You need to explicitly bind the this value of add to get Component 2's this value. There's several ways of doing this, but among the easiest and most popular is to use an arrow function like so when adding add to ctxMenu :

this.ctxMenu.add = () => this.add(); // maintains Component2's this 

Alternatively, you could use bind like so:

this.ctxMenu.add = this.add.bind(this); // maintains Component2's this 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM