Automatically injecting dependencies in Aurelia using Typescript

Recently, I started working with Typescript and Aurelia framework. Currently, I am facing an issue while trying to implement the @autoinject decorator in a VS2015 ASP.NET MVC 6 project.

Below is the code snippet I am using:

import {autoinject} from "aurelia-framework";
import {HttpClient} from "aurelia-http-client";

@autoinject()
export class App {
       http: HttpClient;
       constructor(httpClient: HttpClient) {
          this.http = httpClient;
       }

       activate() {
          this.http.get("/api/test/")...
       }
}

Upon running this code, I encounter an error stating that 'this.http' is undefined.

I suspect that enabling TypeScript's emitDecoratorMetadata flag could resolve this issue, but I am unsure on how to do so.

I attempted adding a tsconfig.json file to the project and setting the flag in compiler options, however, it resulted in multiple errors (duplicate identifier). How can I address these errors? Is there something specific I need to include under "files"?

Additionally, here is my config.js file for reference:

System.config({
  baseURL: "/",
  defaultJSExtensions: true,
  transpiler: "typescript",
  paths: {
    "npm:*": "jspm_packages/npm/*",
    "github:*": "jspm_packages/github/*"
  },

  map: {
    "aurelia-bootstrapper": "npm:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e584909780898c84c8878a8a919691978495958097a5d4cbd5cbd5c887809184cbd4">[email protected]</a>",
    "aurelia-framework": "npm:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1574606770797c74387367747870627a677e55243b253b2538777061743b243b253b22">[email protected]</a>",
    "aurelia-http-client": "npm:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ee8f9b9c8b82878fc3869a9a9ec38d82878b809aaedfc0dec0dec38c8b9a8fc0df">[email protected]</a>",
    "typescript": "npm:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="84f0fdf4e1f7e7f6edf4f0c4b5aab3aab1">[email protected]</a>",
     ....
  }
});

Answer №1

Understanding the Functionality of @autoInject()

Prior to utilizing TypeScript's emitDecoratorMetadata flag, it is important to note that this setting enables the TypeScript compiler to introduce the Metadata Reflection API and incorporate a unique decorator definition into the transpiled TypeScript code.

With Aurelia's @autoInject() decorator, it leverages the type metadata generated by TypeScript's decorator mechanism and applies it to the respective class similar to how the @inject(...) decorator functions.

To implement this feature, ensure to activate the new option within the compilerOptions section of your Type Script configuration.

TypeScript Configuration Sample:

{
    "version": "1.5.1",
    "compilerOptions": {
        "target": "es5",
        "module": "amd",
        "declaration": false,
        "noImplicitAny": false,
        "removeComments": false,
        "noLib": true,
        "emitDecoratorMetadata": true
    },
    "filesGlob": [
        "./**/*.ts",
        "!./node_modules/**/*.ts"
    ],
    "files": [
        // ...
    ]
}

Snippet Screenshot from Related Article:

https://i.sstatic.net/AvFbM.jpg

Further Reading on emitDecoratorMetadata:

Explore Available Type Script Options:
https://github.com/Microsoft/TypeScript/wiki/Compiler-Options

If desired, Gulp-Typescript offers a viable solution along with relevant Gulp settings

Gulp Supported Options: https://github.com/ivogabe/gulp-typescript#options
GitHub Discussion Thread: https://github.com/ivogabe/gulp-typescript/issues/100

Sample Gulp Code Snippet: gulp.task('build-ts', [], function() {

  return gulp.src(paths.typescript)
    .pipe(plumber())
    .pipe(changed(paths.output, {extension: '.js'}))
    .pipe(sourcemaps.init())
    .pipe(ts({
      declarationFiles: false,
      noExternalResolve: true,
      target: 'es5',
      module: 'commonjs',
      emitDecoratorMetadata: true,
      typescript: typescript
    }))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(paths.output));
});

Answer №2

Exploring the @autoinject & @inject Decorators

If you're curious about what exactly the @autoinject and @inject decorators contain, look no further than the dependency-injection Library within the popular aurelia Framework.

    /**
    * Dive into the TypeScript transpiler behavior with this decorator
    */
    export function autoinject(potentialTarget?: any): any {
      let deco = function(target) {
        target.inject = metadata.getOwn(metadata.paramTypes, target) || _emptyParameters;
      };

      return potentialTarget ? deco(potentialTarget) : deco;
    }

    /**
    * Define the dependencies to be injected by the DI Container
    */
    export function inject(...rest: any[]): any {
      return function(target, key, descriptor) {
        // Check if we are injecting into a method or constructor
        if (descriptor) {
          const fn = descriptor.value;
          fn.inject = rest;
        } else {
          target.inject = rest;
        }
      };
    }

For more information, check out the Source URL: https://github.com/aurelia/dependency-injection/blob/master/src/injection.js

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 expected result is not obtained when making an Ajax request to a PHP variable

I recently encountered an issue with my AJAX GET request. The response I received was unexpected as the PHP variable appeared to be empty. Here is the snippet of jQuery code that I used: jQuery(document).ready(function($) { $.ajax({ url: '/wp ...

Error: Attempting to access an undefined property

I have a quite extensive Vue/Vuitify project that is not functioning correctly. I have simplified the project down to a small program to highlight the issue. Despite trying everything that comes to mind, and even some things that don't, I am unable to ...

Direct users from one path to another in Express framework

I have two main routes set up in nodejs. First is the users.js route: router.post('/users/login', function(request, response) { // Logic for user login // Redirect to dashboard in dashboard.js file after login response.redirect(&ap ...

What is a way to ensure that an event is constantly activated when hovering over a specific element?

Currently, I am facing a scenario where I have a button and I need an event to continuously trigger while the button is being hovered. Unfortunately, using the mouseover method only causes the event to fire once when the cursor initially moves over the but ...

Tips for validating multiple inputs of the same type with identical names in JavaScript

I have limited experience with Javascript and am facing an issue with a HTML form that contains multiple input types with the same names occurring more than once. My goal is to validate the form before inserting the data into the database. I have managed t ...

The JavaScript-rendered HTML button is unresponsive

I have a JavaScript function that controls the display of a popup window based on its visibility. The function used to work perfectly, with the close button effectively hiding the window when clicked. However, after making some changes to the code, the clo ...

Understanding the Document.ready function?

Recently, I came across some websites that follow this specific pattern: <html> <head> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script> $(function (){...do some stuff with p ...

Unable to trigger an event from an asynchronous method in TypeScript

In my scenario, I have a child component that needs to emit an event. However, I require the parent handler method to be async. The issue arises when the parent does not receive the emitted object in this particular configuration: Parent Component <co ...

Should case sensitivity be disregarded in an array's input?

I need to search for a value in an array, but the search should be case-insensitive. How can I achieve this? This is the code snippet I am using: $.ajax({ type: "GET", url: "ajax.php", dataType: "json", data: { pageType: pageType, input: request.term, da ...

Is there a workaround in TypeScript to add extra details to a route?

Typically, I include some settings in my route. For instance: .when('Products', { templateUrl: 'App/Products.html', settings: { showbuy: true, showex ...

The onChange function in Material UI Text Field is preventing users from inputting additional values

My application contains a custom TextField component. I am facing an issue where I cannot increase the value of the first TextField due to the presence of the onChange method. However, the second TextField does not have the onChange method, and I can succe ...

Creating a realistic typewriter effect by incorporating Code Block as the input

I am looking to add a special touch to my website by showcasing a code segment with the Typewriter effect. I want this code block not only displayed but also "typed" out when the page loads. Unfortunately, I have been unable to find a suitable solution s ...

Stripping away AM | PM from date variables

Is there a way to accurately calculate the difference between two datetime values in minutes without including AM|PM? When attempting to trim out the AM | PM from my code, I encounter errors (specifically NaN minutes). How can I safely remove this element ...

Rendering JSON Data in JavaScript using Table Pagination

Currently, I am working on rendering JSON data from a URL onto a table. My challenge is to display only 10 rows per page and I'm seeking guidance on how to achieve this. Below is the code snippet that I am using for rendering the data: const url = " ...

Utilizing AJAX for seamless communication between JavaScript and PHP within a modal dialogue box

I'm struggling with learning how to effectively use ajax. In the project I'm currently working on, I have a chart where I can select different people. Once I click on a person's button, their information gets updated in the database. However ...

An error occured: Unable to access undefined properties (specifically 'hasOwnProperty')

I encountered an issue and managed to solve it. I am currently working on creating an update profile page for my Express app using Mongoose, but I keep getting the error "TypeError: Cannot read properties of undefined (reading 'hasOwnProperty')". ...

CSS Testimonial Slider - Customer Feedback Display

I'm having some issues with the code below: <div id="box"> <div class="wrapper"> <div class="testimonial-container" id="testimonial-container"> <div id="testimon ...

Multiple instances of Ajax drop-down effects are now available

On my website's staff page, I have implemented a dropdown menu using AJAX to display information about each member of the staff. The issue arises when attempting to open multiple dropdown menus on the same page - the second dropdown that is opened ten ...

Create a Buffer that includes all the characters of the alphabet when converted to

My current project involves using Node.js to generate secure, random tokens. Here is a snippet of the code I'm using: crypto.randomBytes(32).toString("hex"); // dd89d6ab1a7196e8797c2da0da0208a5d171465a9d8e918d3b138f08af3e1852 Although this method wo ...

How to Utilize JQuery for Sticky Elements

I am experimenting with a unique twist on the classic Sticky Element concept. Check out for a typical sticky element example. Instead of the traditional sticky behavior, I am looking to have an element initially anchored to the bottom of the user's ...