skip to Main Content

(The following code extract illustrates a problem in more complex code where a public method is reported as "not defined")

I have defined a class Organisation with a field/variable organisationName and a public property get OrganisationName()

export class Organisation {
  organisationName = '';

  public get OrganisationName(): string {
    return this.organisationName;
  }
}

I can instantiate this, set the organisationName and access the property OrganisationName

let x = new Organisation();
x.organisationName = 'New Org';
console.log('X Field', x.organisationName);
console.log('X Property', x.OrganisationName);

However if I pass an instance of an Organisation to an Angular component, the property is returning undefined

export class OrganisationEditComponent implements OnInit, OnDestroy {
  @Input() organisation = new Organisation();

In ngOnInit because the property is undefined I’ve also tried creating another instance based on the Input and accessing OrganisationName(). That too gives undefined

let y = this.organisation as Organisation;
console.log('y Field', y.organisationName);
console.log('y Property', y.OrganisationName);

enter image description here

What do I need to do to be able to access the property of the Organisation instance passed into the Angular component as an Input()?

I’ve also tried defining the organisation Input as follows:

@Input() organisation!: Organisation;

This makes no difference.


UPDATE

The issue arises from the fact that I’m populating the data from an API. If the property doesn’t exist in the data returned then the method is not accessible in the Angular application even though it is defined there. If I add the property to the API data, then this is what is displayed, not whatever is returned from the class defined in Angular.

Stackblitz simulation here: https://stackblitz.com/edit/stackblitz-starters-jqzlfj?file=src%2Fmain.ts

2

Answers


  1. Chosen as BEST ANSWER

    Answering my own question, but not accepting it as I don't fully understand the javascript (coming from a strongly typed world)

    Comment from @Silvermind: This line: let y = this.organisation as Organisation;, does not magically convert that object to an Organisation type

    The answer is to use Object.assign

    I've updated the Stackblitz example - https://stackblitz.com/edit/stackblitz-starters-jqzlfj?file=src%2Fmain.ts

    main.ts line 40

    // this.organisation = this.organisations[2]; // displayName is not accessible
    Object.assign(this.organisation, this.organisations[2]); // displayName is accessible
    

    Simple assignment does not give me an instance of the type expected. Is this by design or a limitation of javascript?


  2. The problem may be that you are setting a default value to the input property…

    export class OrganisationEditComponent implements OnInit, OnDestroy {
      @Input() organisation = new Organisation();
    

    Setting a default value might cause unexpected behavior if you are really expecting the value to be set from outside the component. When the OnInit fires, it’s possible you might not have the value from the outside and you still have the default value. That really depends on the parent components, which you didn’t include in the question.

    I would recommend that you do something like this…

    export class OrganisationEditComponent implements OnInit, OnDestroy {
      @Input() organisation: Organisation | undefined;
    

    Then later in your code, you will be forced to make sure the the organisation input has been set before you try accessing it or it’s members.

    Doing this is typically a bad idea…

    @Input() organisation!: Organisation;
    

    Because, the ! only tells the Typescript compiler to "pretend" that the property will never be null or undefined. It doesn’t actually do anything at runtime. This can cause bugs if the value is ever null or undefined at runtime. Use ! with extreme caution.

    Side note:

    I wouldn’t create classes the way you show. There are a few issues with the way you have your Organisation class. I recommend the following…

    • Always use camel casing
    • Make backing properties private and use a setter of the properties have the same name and meaning.
    • OR change the name of the getter to represent the meaning better (for example if you need to transform the value)
    export class Organisation {
      private _organisationName = '';
    
      public get organisationName(): string {
        return this._organisationName;
      }
    
      public set organisationName(value: string) {
        this._organisationName = value;
      }
    
      // Example to illustrate a single getter and changing the name
      public get displayName(): string {
        return `Your organisation: ${this._organisationName}`;
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search