Method with undefined constructor parameter in Typescript

Understanding how to effectively use Typescript and Angularjs in conjunction has been a challenge for me. Despite reading numerous blog posts and consulting the official documentation for both projects, the concepts just haven't fully clicked.

My Angular controller requires two dependencies: $scope and a custom service named greetingService. I have set up a main app Angular module where I have connected the controller and service. By including log statements in my Typescript constructors, I can verify that the dependencies are being injected correctly. However, when attempting to utilize a dependency within the controller, it appears as undefined. The code snippet below showcases this issue more clearly:

declare var angular;

module App.Services {
    export class GreetingService {

        constructor(private $http) {
            console.log("In greeting service constructor");
            console.log($http);
        }

        getGreetingsPromise() {
            return this.$http.get('/greetings.json');
        }
    }
}

module App.Controllers {
    export class GreetingController {

        static $inject = ['$scope', 'greetingService'];
        constructor(public $scope, public greetingService: App.Services.GreetingService) {
            this.$scope.greeting = "This will be a greeting.";
            this.$scope.greet = this.greet;

            console.log(greetingService); // this is defined and looks right
        }

        greet(language: string) {
            console.log("Greeting...");
            console.log(this.$scope); // this is undefined
            console.log(this.greetingService); // this is undefined
            var greetingPromise = this.greetingService.getGreetingsPromise();
            greetingPromise.then(data => this.$scope.greeting = data[language]);
        }
    }
}


var mainApp = angular.module('mainApp', []);
mainApp.controller('greetingController', ['$scope', 'greetingService', App.Controllers.GreetingController]);
mainApp.service('greetingService', App.Services.GreetingService);

Below is the Angular template (which displays "This will be a greeting" as intended from the constructor initialization):

<div class="jumbotron">
    <div ng-controller="greetingController">
        <p class="lead">{{greeting}}</p>
        <button ng-click="greet('english')">Greet me</button>
    </div>
</div>

Answer №1

Here is a crucial line to pay attention to:

this.$scope.greet = this.greet

This specific line is causing the issue. By simply copying the function reference to a scope property, you are risking the scenario where it is called with scope this not being the controller instance. It gets determined by the caller (in this case, this should actually be the scope itself inside the greet function when called from the template) apart from the bound functions. A quick fix would involve using function.bind. For example:

this.$scope.greet = this.greet.bind(this)
, in which you generate a bound function – a function reference tied to the controller instance. Alternatively, you can utilize an arrow function and assign it as a reference, resulting in TypeScript converting any this instances to a cached variable like _this:

   greet = (language: string) => {
        console.log("Greeting...");
        console.log(this.$scope); // this will be undefined
        console.log(this.greetingService); // this will be undefined
        var greetingPromise = this.greetingService.getGreetingsPromise();
        greetingPromise.then(data => this.$scope.greeting = data[language]);
    }

If possible, consider using the controller As syntax (provided your Angular version supports it, or upgrade if not) instead of directly interfacing with the scope to avoid having to perform all these modifications.

For instance:

export class GreetingController {
    greeting :string;

    static $inject = ['greetingService'];

    constructor(public greetingService: App.Services.GreetingService) {
        this.greeting = "A greeting message.";
    }

    greet(language: string) {
        var greetingPromise = this.greetingService.getGreetingsPromise();
        greetingPromise.then(data => this.greeting = data[language]);
    }
}

and

<div class="jumbotron">
    <div ng-controller="greetingController as vm">
        <p class="lead">{{vm.greeting}}</p>
        <button ng-click="vm.greet('english')">Say Hello</button>
    </div>
</div>

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

Localization & Internationalization in Angular 6 CLI for enhancing multi-language functionality

Our Application is built on Angular 6 and we are looking to incorporate multilingual support. Please advise on how we can enable localization and internationalization in Angular 6. This pertains specifically to the Angular 6 version. ...

Enforcement of Typescript Field Type Lax During Assignment

My current issue involves a constructor that is supposed to set the value of _device. The field is specifically designed to be of type number, and the constructor parameter is also expected to be of type number. However, when a parameter of type string is ...

Encountering issues with UI router functionality

Issue with UI router functionality. Here is the code I have: angular.module('bApp', ['ui.router']); angular.module('bApp').config(function($stateProvider, $urlRouterProvider) { $urlRouterProvider.otherwise('/& ...

Encountering numerous issues during my attempt to perform an npm install command

After cloning a git repository, I encountered an issue when trying to run the app in the browser. Despite running "npm install," some dependencies were not fully installed. Upon attempting to run "npm install" again, the following errors were displayed: np ...

The syntax for an Angular controller

During my research on angular interview questions and answers, I came across a discussion about different syntax styles for controllers. The author presented their code in the following format: function Customer($scope) { $scope.CustomerName = "Sh ...

Struggling to troubleshoot an error - Invalid key Token '{' found at column 2

I am encountering a debugging issue that I can't seem to resolve. form-field.html <div class='row form-group' ng-form="{{field}}" ng-class="{ 'has-error': {{field}}.$dirty && {{field}}.$invalid }"> <label cla ...

Properly storing information in the mongoDB

Having trouble saving data in my Angular application correctly. Here is a snippet of my API code: .post('/type/add', function(req, res){ var type = new NewType({ type: req.body.type, subtype: req.body.subtype, }); type.save ...

Simplify typing in TypeScript using default generic parameters

Imagine I came across the following object: const inquiries = { whoCreatesIssues: { options: { sameTeam: { id: 'SAME_TEAM' }, management: { id: 'MANAGEMENT' ...

Encountering incorrect month while utilizing the new Date() object

My Objective: I am looking to instantiate a new Date object. Snippet of My Code: checkDates (currentRecSec: RecommendedSection){ var currActiveFrom = new Date(currentRecSec.activeFrom.year,currentRecSec.activeFrom.month,currentRecSec.activeFrom.day ...

Guide to Rolling a Set of 5 Dice

I am looking to develop a game involving 5 dice. I have already created a function to roll one die using a random method, but I am unsure how to extend this functionality to the remaining four dice without having to create a separate method for each one. ...

Tips for uploading images, like photos, to an iOS application using Appium

I am a beginner in the world of appium automation. Currently, I am attempting to automate an iOS native app using the following stack: appium-webdriverio-javascript-jasmine. Here is some information about my environment: Appium Desktop APP version (or ...

The compilation of the module has encountered an error with the PostCSS loader. There is a SyntaxError at line 2, character 14 indicating an unknown

I am developing an Angular 8 application. Currently, I am incorporating AlertifyJs into my project. In the styles.css file of Angular, I have imported these libraries: @import '../node_modules/alertifyjs/build/alertify.min.js'; @import '. ...

Adjust the date format within AngularJs

I am currently using the ui mask for formatting dates. However, I am facing an issue where I need to input the year first. Check out my demo here: http://jsfiddle.net/XS4R6/85/ <div ng-controller="myController"> <input type="text" ng ...

Transforming this JavaScript function using Template Strings into TypeScript

Is there anyone out there who can assist with the following query? I have a functional .js file that I need to integrate into a TypeScript program. import React from "react"; import styled, { css } from "styled-components"; const style = ({ theme, ...res ...

Encountering an issue post-upgrade with Angular 7 project

Currently, I am facing an issue with upgrading a project from Angular 6 to version 7. Despite following multiple online tutorials and successfully completing the upgrade process, I encountered an error when running the 'ng serve' command: ERROR ...

I encountered a 404 error while trying to implement an IIS 8 Rewrite rule

After implementing the Rewrite rule on IIS 8 for my asp.net application, I encountered a 404 error when trying to access www.mysiteurl.com/?_escaped_fragment_. Interestingly, changing the actionType to Redirect allowed successful redirection. <rule nam ...

$watch will not be activated unless a full refresh is completed

I am using a $watch function to keep an eye on an array called menuItems within the MenuFilter service. $scope.filterMenuItems = MenuFilter.menuItems; $scope.$watch(function () { return MenuFilter.menuItems; }, function (newVal, oldVa ...

Retrieving data from both a Firestore collection and its nested sub-collection simultaneously

In my Ionic 5 app, I have organized my Firestore database structure as follows. Book (collection) {bookID} (document with book fields) Like (sub-collection) {userID} (document named after user ID with respective fields) The collection Book consists of ...

A different approach to handling multiple constructors in Angular 4

Angular 4 does not support having multiple constructors, so I need to find a cleaner way to instantiate my object. This is what my model looks like: export class SrcFilter { constructor(public firstList?: Array<String>, public secondList?: Arra ...

The Next.js template generated using "npx create-react-app ..." is unable to start on Netlify

My project consists solely of the "npx create-react-app ..." output. To recreate it, simply run "npx create-react-app [project name]" in your terminal, replacing [project name] with your desired project name. Attempting to deploy it on Netlify Sites like ...