skip to Main Content

I’m working on a project and I need to be able to execute a function from my app’s navigation menu. As far as I understand, all functions are executable from a view using wire:click, and this triggers the function from the associated controller.

Is there any way to create a global function (or several) so that they can be called from the navigation menu (which is always loaded) regardless of the view I’m in?

I hope I’ve explained myself.

I’ve tried to use Ajax, Providers, and more, but I don’t know which is the correct way to do it.

2

Answers


  1. Providers
    Create a Service

    typescript
    import { Injectable } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class GlobalFunctionsService {
      myGlobalFunction() {
        // Logic for your global function
      }
    }

    Inject Service in Components

    typescript
    import { Component } from '@angular/core';
    import { GlobalFunctionsService } from './global-functions.service';
    
    @Component({
      // ...
    })
    export class NavigationMenuComponent {
      constructor(private globalFunctionsService: GlobalFunctionsService) {}
    
      callGlobalFunction() {
        this.globalFunctionsService.myGlobalFunction();
      }
    }

    Call from Navigation Menu

    <button (click)="callGlobalFunction()">Execute Global Function</button>

    BroadcastService:
    Create a BroadcastService

    typescript
    import { Injectable } from '@angular/core';
    import { EventEmitter } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class GlobalFunctionsBroadcastService {
      globalFunctionTriggered = new EventEmitter<any>();
    
      triggerGlobalFunction(data?: any) {
        this.globalFunctionTriggered.emit(data);
      }
    }

    Emit Event from Navigation Menu

    typescript
    import { GlobalFunctionsBroadcastService } from './global-functions-broadcast.service';
    
    @Component({
      // ...
    })
    export class NavigationMenuComponent {
      constructor(private broadcastService: GlobalFunctionsBroadcastService) {}
    
      callGlobalFunction() {
        this.broadcastService.triggerGlobalFunction();
      }
    }

    Listen for Event in Relevant Components

    typescript
    import { GlobalFunctionsBroadcastService } from './global-functions-broadcast.service';
    
    @Component({
      // ...
    })
    export class SomeComponent {
      constructor(private broadcastService: GlobalFunctionsBroadcastService) {
        this.broadcastService.globalFunctionTriggered.subscribe(() => {
          // Execute logic when function is triggered
        });
      }
    }
    Login or Signup to reply.
  2. Here is the way I’ve done this in my laravel project (I’m not using livewire though, but I don’t see why this won’t work for you).

    Create a service provider if you don’t have one for your site/app

    php artisan make:provider SiteServiceProvider
    

    Register the service provider in config/app.php

    'providers' => ServiceProvider::defaultProviders()->merge([
            // other service providers
            AppProvidersSiteServiceProvider::class,
        ])->toArray(),
    

    And in the boot method of your SiteServiceProvider you can make global functions (available within all of your views)

    View::share('formatPhoneNumber', function ($phoneNumber) {
        // Ensure $phoneNumber is a 10-digit number
        $phoneNumber = preg_replace('/[^0-9]/', '', $phoneNumber);
    
        // Format the phone number
        return sprintf("(%s) %s - %s",
            substr($phoneNumber, 0, 3),
            substr($phoneNumber, 3, 3),
            substr($phoneNumber, 6)
        );
    });
    

    And in your view you can use that function like so

    <a class="stretched-link" href="tel:{{ $phoneNumber }}">&#x260E; {{ $formatPhoneNumber($phoneNumber) }}</a>
    

    You could also make global variables.

    In the boot method of that SiteServiceProvider you would have something like the following

    View::composer('*', function ($view) use ($config) {
        $view->with('phoneNumber', $config['phoneNumber']);
        $view->with('emailAddress', $config['emailAddress']);
        // Add more variables as needed
    });
    

    And then you can use it in the view like

    <a class="stretched-link" href="tel:{{ $phoneNumber }}">&#x260E; {{ $formatPhoneNumber($phoneNumber) }}</a>
    

    Having written most of this answer I now realize that this is not what you meant, you want to invoke a function by using a menu from anywhere in the site regardless of the view being served, but since I’ve already written this answer, maybe it’ll be useful to others…

    One way you probably might be able to do this is putting the functions you want to be global into a trait, and then using that trait in all your view component classes.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search