-1

I have several classes that I would like to include in a module, so I can then just import the module, as it was a different package, and use those classes from it. Here's a small example:

human.ts (my class file)

export class Human {

  private numOfLegs: Number;

  constructor() {
    this.numOfLegs = 2;
  }
}

test.module.ts (my module file)

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { Human } from './human';

@NgModule({
  imports: [CommonModule],
  declarations: [
    Human
  ],
  providers: [],
  exports: [Human]
})
export class TestModule {}

How do I instantiate the Human class in a component? I've tried both:

import { TestModule } from './test.module';

and

import { Human } from './test.module';

But if I do new Human() I still get cannot find name Human

bruno.bologna
  • 475
  • 4
  • 14
leota
  • 1,636
  • 2
  • 13
  • 33
  • I think you will still have to import Human in your components to use it, just as if you were to use Http or any other object. – hayhorse Sep 08 '17 at 14:41
  • In the thread I used to vote for a duplicate, the answer is stated. By the way, if you import a service into an NgModule, you will still have to import the class into your component where you will use it. The javascript import and the NgModule import are 2 completely different things which can be a bit confusing. – Deblaton Jean-Philippe Sep 08 '17 at 14:43
  • So what I'm trying to do is wrong? – leota Sep 08 '17 at 14:46
  • Classes cannot be wrapped into a module? – leota Sep 08 '17 at 14:46
  • 1
    you can read [Avoiding common confusions with modules in Angular](https://blog.angularindepth.com/avoiding-common-confusions-with-modules-in-angular-ada070e6891f) – Max Koretskyi Sep 08 '17 at 15:19
  • *But if I do new Human() I still get cannot find name Human* - where exactly do you do that? The code in the question is incomplete and lacks http://stackoverflow.com/help/mcve – Estus Flask Sep 08 '17 at 16:36
  • @estus `How do I instantiate the Human class in a component?` – leota Sep 08 '17 at 16:38
  • Do you need to have one instance per each component instance or should they share a common instance? The question should cover this, it's not clear what is exact desirable behaviour. – Estus Flask Sep 08 '17 at 16:40
  • I mean an instance for component, not a gobal one – leota Sep 08 '17 at 16:47

3 Answers3

3

Angular modules and ES6 / TypeScript / Node modules are different. Angular modules are a collection of Components, Services and Directives; whereas the ES6 modules comprise of classes in most cases.

If you want to reuse your NgModule which is dependent on other non-Angular classes you can export them as ES6 modules and use them elsewhere. Have a file like export.ts or index.ts and place the following export statements there -

export { TestModule } from './test.module';
export { Human } from './human';

Now, when you want to use the NgModule somewhere, you import it with a command like the following -

import { TestModule } from '../lib/export'; 
jaibatrik
  • 6,770
  • 9
  • 33
  • 62
  • But this would just be an ES6 module, not an NgModule – leota Sep 08 '17 at 15:11
  • As long as the node dependencies are satisfied, the NgModule should work anywhere in Angular environment. After all, modules are classes. – jaibatrik Sep 08 '17 at 15:17
  • BTW, this is what I was looking for. Just a way to wrap multiple classes in a module. Thanks – leota Sep 08 '17 at 17:38
1

A class shouldn't be provided in declarations or exports, these ones are for components directives and pipes, providing Human there is a mistake.

The first option is that Human is provided as value provider (not as class provider) in the module, so it should be instantiated manually. This option is preferred when a class accepts non-DI arguments.

@NgModule({
  providers: [{ provide: Human, useValue: Human }]
})
export class TestModule {}

...

import { Human } from '...';

@Component(...)
class SomeComponent {
  constructor(@Inject(Human) Human: typeof Human) {
    this.human = new Human();
  }
}

The second option is to make Human a component provider. It is instantiated for each component instance. In this case TestModule is redundant. This option is generally preferred:

import { Human } from '...';

@Component({ providers: [Human], ... })
class SomeComponent {
  constructor(public human: Human) {}
}

In both cases Human DI token should be imported in component file where it's used.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
0

Make the Human class injectable and declare it in the providers section of your test module.

If you app module (the root one) loads the test module eagerly, the providers declared in the test module will be available in the app module and you'll be able to inject Human in your components from the root module.

The situation is different if you load your test module lazily - these have their own injectors and don't share providers with other modules.

@NgModule({
  imports: [CommonModule],
  providers: [Human]
})
export class TestModule {}

I assume that you're loading the TestModule using the router configuration:

@NgModule({
  imports: [ BrowserModule, TestModule,
    RouterModule.forRoot([
      {path: 'test', loadChildren: TestModule},
      )
  ],
    bootstrap:    [ AppComponent ]
})

In AppComponent you can inject Human:

export class AppComponent {

  constructor(human: Human) {
    console.log(human.numOfLegs);
  }
}

Make sure that numOfLegs is public.

Yakov Fain
  • 11,972
  • 5
  • 33
  • 38
  • I made it injectable and declared it as provider of my module. But how do I access it?? tried TestModule.Human after import, but it doesn't work. Could you please provide a little example? – leota Sep 08 '17 at 15:01
  • Added some code to my answer. – Yakov Fain Sep 08 '17 at 17:12