Search code examples
arraysangularionic-frameworkngforfunction-call

Ionic & Angular: Inserting Function Names with ngFor


How can I insert a function call via *ngFor, while this call comes as an inserted String from the Array I'm iterating over?

My array contains a list of user actions that are described by their function names (among others). The template has a part that shall list these actions for each user entry, using Ionic's ion-fab directive. Instead of writing down each action I want to iterate over the list using *ngFor and insert each function name into a (click) attribute.
My current solution doesn't work, though.

Here's my code:

Class

constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    private usersProv: Users
) {
    this.userActions = [
        {
            'label'     : 'Edit',
            'function'  : 'editUser',
            'icon'      : 'ios-create-outline',
            'color'     : 'primary'
        },
        {
            'label'     : 'Remove',
            'function'  : 'removeUser',
            'icon'      : 'ios-trash-outline',
            'color'     : 'yellow'
        },
        {
            'label'     : 'Send message',
            'function'  : 'sendMessageToUser',
            'icon'      : 'ios-send-outline',
            'color'     : 'secondary'
        }
    ];
    console.info('userActions', this.userActions);
}

Template

<ion-fab right>
    <button ion-fab mini color="light">
        <ion-icon name="ios-arrow-dropleft"></ion-icon>
    </button>
    <ion-fab-list side="left">
        <div *ngFor="let action of userActions">
            <button ion-fab mini color="{{action.color}}" title="{{action.label}}" (click)="action.function(user)">
                <ion-icon name="{{action.icon}}"></ion-icon>
            </button>
        </div>
    </ion-fab-list>
</ion-fab>

And this is the error I get:

ERROR TypeError: "_v.context.$implicit.function is not a function"

Inserting with curly brackets ((click)="{{action.function}}(user)") doesn't help, either. The error then is:

`ERROR Error: "Uncaught (in promise): Error: Template parse errors: Parser Error: Got interpolation ({{}}) where expression was expected at column 0 in [{{action.function}}(user)]`

Is this possible at all?
And is it recommendable to approach it the way I'm doing?

Thanks in advance!


Solution

  • Instead of using a string, you should hold a reference to the function, like so

    userActions = [
        {
            'label'     : 'Edit',
            'function'  : this.editUser.bind(this),
            'icon'      : 'ios-create-outline',
            'color'     : 'primary'
        },
        {
            'label'     : 'Remove',
            'function'  : this.removeUser.bind(this),
            'icon'      : 'ios-trash-outline',
            'color'     : 'yellow'
        },
        {
            'label'     : 'Send message',
            'function'  : this.sendMessageToUser.bind(this),
            'icon'      : 'ios-send-outline',
            'color'     : 'secondary'
        }
    ];
    

    Here I'm using bind, so we don't lose the context of this when we invoke the function.

    Then, in your HTML, you can call it like so:

    <button (click)="a.function(user)">{{a.label}}</button>
    

    Here is a StackBlitz demo