1

I am trying to learn Angular and have run into what is probably a very simple problem.

I have written a child component for doing grid paging called "PageSelectorComponent". This component just takes a total record count and calculates and displays page links (no providers are used in this component). I have embedded this component inside another component called "TestComponent".

PageSelectorComponent and Test Component are included in the delarations portion of my app.module.ts file.

My issue is that I get the following error:

ERROR Error: Uncaught (in promise): Error: No provider for PageSelectorComponent!

If I add PageSelectorComponent to the providers section of the app.module.ts everything works fine except now I get two instances of the component. This causes my subscribe not to work.

I have looked over how PageSelectorComponent and TestComponent are declared but don't see a difference.

Why does the app complain about not listing PageSelectorComponent as a provider?

Here is the NgMoudle section of my app.modules.ts:

@NgModule({
  declarations: [
    AppComponent,
    NavigationComponent,
    HomeComponent,
    PageSelectorComponent,
    TestComponent,
  ],
  imports: [
    BrowserModule,
    RoutingModule,
  ],
  providers: [
    PageSelectorComponent // App complains if I leave this out but now I get 2 instances of the component.
  ],
  bootstrap: [AppComponent]
})

Here is the definition for PageSelectorComponent:

@Component({
    moduleId: module.id,
    selector: 'app-page-selector',
    templateUrl: './page-selector.component.html',
    styleUrls: ['./page-selector.component.css'],
})

export class PageSelectorComponent {
  // member variables declared here
     .
     .
  private static instanceNum: number = 0; // TOOD: debugging

  constructor() {
    PageSelectorComponent.instanceNum += 1;
    console.log(`page-selector instance number ${PageSelectorComponent.instanceNum}`)
    this.subject = new Subject();
  }

Like I said, I think there is some really basic Angular thing I missed here. Any suggestions on where to look?

Thanks in advance!

David Chu
  • 11
  • 2
  • You don't need to put it to `providers`, `PageSelectorComponent.instanceNum += 1;` thing here causes the trouble tried `this.instanceNum?` also if there is something like `PageSelectorComponent.instanceNum += 1;` in other components better stop doing it – masterpreenz Aug 31 '17 at 21:37
  • Thanks for the quick reply.I know I _shouldn't_ need to list PageSelectorComponent in the providers section. Just tried taking it out again but I get the same error as above. Also took out the `static instanceNum`. I am still getting two instances. My thinking is that this is because it is listed in declarations **and** providers. – David Chu Aug 31 '17 at 21:47
  • If `No provider for PageSelectorComponent` appears means `PageSelectorComponent` was used like a service / provider would behave somewhere in the other components – masterpreenz Aug 31 '17 at 21:53
  • Ok I stripped this down to the bare bones. Just app.component.ts and PageSelectorComponent. Still the same issue with needing to put it in the providers section. Maybe it is how I use the component? ` export class AppComponent { title = 'app'; constructor(private pager: PageSelectorComponent) {} } ` – David Chu Aug 31 '17 at 22:21
  • This `private pager: PageSelectorComponent` is causing you the issue since if you call it this way app will look for a Provider named `PageSelectorComponent` – masterpreenz Aug 31 '17 at 22:23
  • Ah ok. Makes sense (newb error). If don't declare it in the constructor then how to I access the PageSelectorComponent instance so I can subscribe to it? I did just try taking out the "private" key word but still the same issue. – David Chu Aug 31 '17 at 22:30
  • No, create a `service` or more like an `interface` that is being used by `PageSelectorComponent` to check for events and stuff which can also be used by other components. Another solution is to make use of observer `broadcast / emit` pattern. Try to improve your question with your current problem so we could come up with a better solution, now you know what's the problem – masterpreenz Aug 31 '17 at 22:34
  • Thanks. I think I get your point. By trying to subscribe to this component I am really treating it like a service. Instead, I should be creating a service that does my calculations. Then I can create a component that subscribes to it to draw the UI. I will rework my code and update this post! – David Chu Aug 31 '17 at 22:57

1 Answers1

0

Many thanks to masterpreenz for setting me straight on this.

I will answer this to close the thread with how I understand Angular now. Since I am new to this please let me know if I still have it wrong!

As expected this was a basic misunderstanding of the Subject/Observer pattern. As it turns out I was trying to create a new Subject from within component1 for which I was going to have another component2 observe and react to clicks. To get access to the subject of component1, component2 needed to be instantiated in the constructor.

constructor(private pager: coomponent1) {}

This treats component1 like a service (because it is being injected) which is why I needed to include it in both the declarations and providers sections of the app.module.

The way to do this (I am sure not the only way) is to create a service that handles the logic. component1 can then call the service when it is clicked. component2 can then subscribe to the service.

Effectively this allows component2 to react to clicks from component1.

David Chu
  • 11
  • 2