one-time occurrence of $mdToast injection within a parent class

Seeking advice on how to efficiently place a single instance of $mdToast (from Angular Material) into a base class (Typescript). In my UI, I have five tabs with separate controller instances and it seemed logical to centralize the $mdToast declaration in a base class rather than repeating it. However, despite having its own "$inject" property, it seems to be overridden by the one in the derived class. Any suggestions on the best approach for moving $mdToast to a common base class? Here is a snippet of my current code:

Note that the original $mdToast lines are currently commented out:

export class MainController extends BaseController {
static $inject = [
  'tableService',
  '$mdSidenav', 
  //'$mdToast', 
  '$mdDialog', 
  '$mdMedia',
  '$mdBottomSheet'];

constructor(
  private tableService: ITableService,
  private $mdSidenav: angular.material.ISidenavService,
  //private $mdToast: angular.material.IToastService,
  private $mdDialog: angular.material.IDialogService,
  private $mdMedia: angular.material.IMedia,
  private $mdBottomSheet: angular.material.IBottomSheetService) {
  super();
  var self = this;
}}

The following is the base class. Take note of the injection of $mdToast and the declaration of $mdToast outside of the constructor:

export class BaseController {
static $inject = [
  '$mdToast'];

constructor() {
  var self = this;
}

private $mdToast: angular.material.IToastService;

openToast(message: string): void {
  this.$mdToast.show(
    this.$mdToast.simple()
      .textContent(message)
      .position('top right')
      .hideDelay(3000)
  );
}}

I tried using $injector as suggested elsewhere on SO, but it didn't work for me. Appreciate any helpful responses!

Answer №1

There is a common pattern in the code snippet provided:

export class BaseController {
    static $inject = [...];
    ...
}

export class MainController extends BaseController {
    static $inject = [...BaseController.$inject,
      ...
    ];

    constructor(...deps) {
        const superDeps = BaseController.$inject.map((dep, i) => deps[i]);

        super(...superDeps);

        const thisDeps = deps.slice(superDeps.length);
        const thisDepNames = this.constructor.$inject.slice(superDeps.length);
        ...


    }

    ...
}

This pattern can be encapsulated in a base class or decorator for ease of use if it is repeated frequently. It essentially involves parsing two arrays, $inject and deps, to assign dependencies to this.

However, it's worth noting that this method is not type-safe.

In TypeScript, it's recommended to keep things DRY while maintaining type safety. For consistency, we should prioritize listing the dependencies of the parent class first:

export class BaseController {
    static $inject = ['$mdToast'];

    constructor(protected $mdToast: angular.material.IToastService) { ... }
}

export class MainController extends BaseController {
    static $inject = [
      '$mdToast'

      'tableService',
      ...  
    ];

    constructor(
        $mdToast: angular.material.IToastService,

        private tableService: ITableService,
        ...
    ) {
        super($mdToast);
    }}
    ...
}

Answer №2

Although considered a bit of a hack, this method will effectively complete the task in a straightforward manner. Utilize ES6's import/export statements to ensure that this service is accessible wherever it is needed.

export let $injector;

class injectorConfig {
    static $inject = ['$injector'];
    constructor (private $originalInjector) {
        $injector = $originalInjector;
    }
}

app.config(injectorConfig);

Your BaseController.ts file should resemble the following structure:

import {$injector} from '../yourfilename';

export class BaseController {
    private $mdToast = $injector.get('$mdToast');
    constructor( ) {
        var self = this;
    }
}

It is important to note that just because this method works does not mean it should be heavily relied upon. However, in certain scenarios like these, this technique can be fairly reasonable. Keep in mind that the $injector will not be accessible until Angular executes this config block, therefore it cannot be used in providers or any other code that executes prior to the config block.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The art of transforming properties into boolean values (in-depth)

I need to convert all types to either boolean or object type CastDeep<T, K = boolean> = { [P in keyof T]: K extends K[] ? K[] : T[P] extends ReadonlyArray<K> ? ReadonlyArray<CastDeep<K>> : CastDeep<T[P]> ...

How can you establish the default value for a form from an Observable?

Check out my TypeScript component below export interface Product{ id?:string, name:string, price:string; quantity:string; tags:Tags[]; description:string; files: File[]; } product$:Observable<Product | undefined>; ngOnIn ...

Typescript's spellbinding courses

I'm encountering some issues with Typescript and the "@botstan/Magic" library in nodejs. Before we proceed, please take a look at the "Magic" documentation. Follow these lines: import Magic from "@botstan/magic"; import * as _ from "lodash"; @ ...

Issue in TypeScript: Property '0' is not found in the type

I have the following interface set up: export interface Details { Name: [{ First: string; Last: string; }]; } Within my code, I am using an observable configuration variable: Configuration: KnockoutObservable<Details> = ko.observable& ...

Create an Angular-UI function that appends a modal inside a <div> element with the class

We are facing an issue with conflicting rule names between our legacy .css and Twitter Bootstrap on our large website. To resolve this conflict, we have implemented a .sass version of Bootstrap and structured everything as follows: .bootstrap-enabled { / ...

Utilizing the 'as' prop for polymorphism in styled-components with TypeScript

Attempting to create a Typography react component. Using the variant input prop as an index in the VariantsMap object to retrieve the corresponding HTML tag name. Utilizing the styled-components 'as' polymorphic prop to display it as the select ...

Unable to retrieve the updated array value in NodeJs when accessed outside the function scope

I recently started working with node and I'm attempting to retrieve the Twitter id of a group of users. The module takes an array of screen names, iterates over them to obtain the userId, and then adds them to an array. However, I'm facing an iss ...

Is AngularJS primarily a client-side or server-side framework, or does it have elements

Is it possible to connect to the database on the server side? I have experience using it on the client side, but can the same method be used on the server side? If it's not suitable for server-side use, should I go with PHP or Node.js for designing ...

AngularJS retrieves empty array from OData request

After studying the technique demonstrated in this live example here: http://jsfiddle.net/h22f7596/, my goal is to exhibit the content of a JSON file from my personal OData Service using AngularJS. Here is the HTML snippet I have: <div ng-repeat=" ...

utilizing protractor for end-to-end testing: utilizing Promises in utility functions

I'm relatively new to working with protractor and promises in general. Despite the plethora of information available on returning promises or handling queued actions, I find it difficult to grasp. Therefore, I am seeking a clear and straightforward an ...

Looking for a shortcut in VSCode to quickly insert imports into existing import statements or easily add imports as needed on the go?

It seems that the current extensions available on the VSCode marketplace struggle to properly add Angular imports. For example, when I try to import OnInit using the Path IntelliSense extension: export class AppComponent implements OnInit It ends up impo ...

Vue: rendering props cannot be utilized with TSX

After switching my setup from JSX in a Vue component to TS with vue-class-component, I found that only the code snippet below works for me (as shown in the example on repo): import Vue from 'vue' import { Component } from 'vue-property-dec ...

Encountering a problem with AngularJS when trying to pass a controller through ng-include in HTML

I'm currently developing a portal-style application that will dynamically inject HTML from other URLs (within the domain) into different sections of the page, which I like to refer to as widgets. Each widget needs to be loaded with an ng-include and h ...

What is the best way to send data to a different screen in Ionic 1 and Angular 1?

I have designed a screen with multiple buttons similar to this: Currently, I am able to pass the id of a button when clicked on its route. However, I am facing difficulty in passing parameters for several buttons. My query is how can I pass the id of a b ...

Looking to have two separate modules on a single page in AngularJS, each with its own unique view

<!DOCTYPE html> <html> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js" ...

Is there a way to set a default value for an Angular service provider?

Imagine an Angular Service that encapsulates the HTTP Client Module. export class HttpWrapperService { private apiKey: string; } Of course, it offers additional features that are not relevant here. Now I'm faced with the task of supplying HttpWr ...

javascript identify dissimilarities within arrays

Working on an Angular 2 application and attempting to identify the difference between two arrays (last seven days and missing dates within the last seven days). Everything works fine when initializing the array through a string, like in example code 1. How ...

Pausing in a NodeJS HTTP request listener until receiving another response before proceeding

Essentially, this is a web proxy. Within a request listener, I am creating another http request, reading its response, and passing it to the main response. But I have the challenge of needing to wait for the secondary request to complete before continuing. ...

Is it possible to retrieve a union type property as an array of values in order to conduct a flexible type validation process?

Currently, my code looks something like this: interface Apple { type: 'Apple' } interface Banana { type: 'Banana' } interface Coconut { type: 'Coconut' } type Fruit = Apple | Banana | Coconut type AppleOrBanana = App ...

Utilize the key-value pair from ng-repeat to expand the scope of the expression

In an attempt to utilize the key value from ng-repeat as an extension of another scope.arrayResult, I aim to achieve arrayResult.q1/q2/q3 etc... <ul ng-repeat="(key,x) in data"> <li><h4>Question: {{x}}</h4> <p>{{ ar ...