0

I'm trying to execute a Component method from a Service method. I saw these other 2 threads:

Link1 - How to call component method from service?

Link2 - Angular2 call a Component from a Service

But they show a method executed from the constructor.

I'm using on an Ionic app, the Ion-Select component(lot of selects) And for it I'm using a feature call Action Sheet which has a callback handler for every option chosen from the select.

The Action is on the service, and so the Handler call. But each select has an own method that need to be called from the ActionSheet. Thats my code now:

SELECT EXAMPLE

import { Component, EventEmitter, Input, Output } from '@angular/core';
import { ActionSheetService } from '../../services/action-sheet.service';

import { Type } from '../../models/general/type.model';

@Component({
    selector: 'type-select-component',
    templateUrl: 'type-select.component.html',
    providers: [ ActionSheetService ]
})
export class TypeSelectComponent {

    @Input() public types: Object[];
    @Output() public typeId: EventEmitter<number> = new EventEmitter<number>();

    public updatedItem: Type = new Type();
    private actionTitle: string = "What's Type"

    constructor( private actionSheetService: ActionSheetService ) { }

    //The Service should execute this method
    public updateSelectItem(id:number, type: Type): void{
        this.updatedItem = type;
        this.typeId.emit(id);
    }

    public presentActionSheet(): void {
//calling the service method passing options for the action sheet 
this.actionSheetService.presentActionSheet(this.actionTitle,this.types as Type[]);
        }
    }

ACTION-SHEET SERVICE

import { Injectable } from '@angular/core';
import { ActionSheetController } from 'ionic-angular'

@Injectable()
export class ActionSheetService {

constructor(private actionSheetCtrl: ActionSheetController) { }

public presentActionSheet(
    actionTitle: string, 
    items: any[]): void {

    let actionSheet = this.actionSheetCtrl.create({
        title: actionTitle
    });
    for (let i = 0; i < items.length; i++) {
        actionSheet.addButton({
            text: items[i].name,
            cssClass: items[i].css,
            icon: items[i].selectIcon,
            handler: () => {
//Here I should execute the method updateSelectItem from the component
                updateSelectItem(i, items[i]);
                console.log('Service ActionHandler');
            }
        });
    }
    actionSheet.addButton({ text: 'Cancel', 'role': 'cancel' });
    actionSheet.present();
    }
}

Why am I doing this way??? Well I could put an action sheet in each select...But then it'll break DRY

Any help guys?

Rafael de Castro
  • 888
  • 4
  • 16
  • 37

1 Answers1

3

You can pass a callback to your service and set it as handler for your action sheets.

public presentActionSheet(
    actionTitle: string, 
    items: any[],
    callbackHandler:any): void {

    let actionSheet = this.actionSheetCtrl.create({
        title: actionTitle
    });
    for (let i = 0; i < items.length; i++) {
        actionSheet.addButton({
            text: items[i].name,
            cssClass: items[i].css,
            icon: items[i].selectIcon,
            handler: () => {
                callbackHandler(i, items[i]);//call the handler passed
                console.log('Service ActionHandler');
            }
        });
    }
    actionSheet.addButton({ text: 'Cancel', 'role': 'cancel' });
    actionSheet.present();
    }

In your component

public presentActionSheet(): void {
//calling the service method passing options for the action sheet 
this.actionSheetService.presentActionSheet(this.actionTitle,this.types as Type[],this.updateSelectItem.bind(this) );//send your component function. Do not forget to bind the context
        }
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • man :D It worked! But I didn't "bind the context" didn't understand this part... The app its working with your modification. But can I elucidate me on this xD XD – Rafael de Castro Jan 08 '18 at 12:23
  • 1
    well.. `this.updateSelectItem.bind(this)` [Bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind) function sets the context to the current `this` i.e the component. Otherwise when it is called `this` will point to a different context and `this.updatedItem` will error – Suraj Rao Jan 08 '18 at 12:27