1

I'm using Angular Material 2 and I want to open a dialog window with MdDialog which shows some information about a user stored in firebase.

@Injectable()
export class TweetService {

  dialogRef: MdDialogRef<TweetDialogComponent>;

  constructor(public dialog: MdDialog) {
  }

  sendTweet(viewContainerRef: ViewContainerRef) {
    let config = new MdDialogConfig();
    config.viewContainerRef = viewContainerRef;

    this.dialogRef = this.dialog.open(TweetDialogComponent, config);

    this.dialogRef.afterClosed().subscribe(result => {
      this.dialogRef = null;
    });
  }
}

@Component({
  selector: 'app-tweet-dialog',
  templateUrl: './tweet-dialog.component.html'
})
export class TweetDialogComponent implements OnInit {
  private user: FirebaseObjectObservable<any[]>;

  constructor(
    public dialogRef: MdDialogRef<TweetDialogComponent>,
    private usersService: UsersService,
    private authService: AuthService) { }

  ngOnInit() {
    let uid = this.authService.getUser().uid;
    this.user = this.usersService.getUser(uid);
  }

}

The template is a simple as this atm

<h1>{{ (user | async)?.email }}</h1>

The user is stored in Firebase, and the problem is that for a brief moment the dialog window displays null until the user is retrieved. So I thought, ok, maybe is a good idea to retrieve the user in TweetService and pass it as a parameter to the TweetDialogComponent, but then I realized I don´t know how to do that.

I saw this angular2-material-mddialog-pass-in-variable and so I tried this

@Injectable()
export class TweetService {

  private dialogRef: MdDialogRef<TweetDialogComponent>;
  private user: FirebaseObjectObservable<any[]>;

  constructor(
    private dialog: MdDialog,
    private usersService: UsersService,
    private authService: AuthService) {
  }

  getUser(): FirebaseObjectObservable<any[]> {
    return this.user;
  }

  sendTweet(viewContainerRef: ViewContainerRef) {
    let config = new MdDialogConfig();
    config.viewContainerRef = viewContainerRef;

    let uid = this.authService.getUser().uid;
    this.user = this.usersService.getUser(uid);

    this.dialogRef = this.dialog.open(TweetDialogComponent, config);

    this.dialogRef.afterClosed().subscribe(result => {
      this.dialogRef = null;
    });
  }
}

@Component({
  selector: 'app-tweet-dialog',
  templateUrl: './tweet-dialog.component.html'
})
export class TweetDialogComponent implements OnInit {
  private user: FirebaseObjectObservable<any[]>;

  constructor(
    public dialogRef: MdDialogRef<TweetDialogComponent>,
    private tweetService: TweetService) { }

  ngOnInit() {
    this.user = this.tweetService.getUser();
  }

}

But that's giving me an error Can't resolve all parameters for TweetDialogComponent: (MdDialogRef, ?).

Any idea on how to do this? Thanks,

UPDATE

It seems this might be related with the order of imports in the barrels, but I'm not using barrels, I'm doing the imports directly from the file. This is my ngModule declaration (sorry, it's a bit long...)

@NgModule({
  declarations: [
    AppComponent,
    ProfileComponent,
    PeopleComponent,
    TimelineComponent,
    TweetDialogComponent,
    ProfilePipe
  ],
  entryComponents: [
    TweetDialogComponent
  ],
  imports: [
    routing,
    BrowserModule,
    AuthModule,
    AngularFireModule.initializeApp(firebaseConfig, firebaseAuthConfig),
    MaterialModule.forRoot()
  ],
  providers: [
    AUTH_PROVIDERS,
    AuthGuard,
    UsersService,
    { provide: TweetService, useClass: TweetService },
    { provide: LocationStrategy, useClass: HashLocationStrategy },
    { provide: APP_BASE_HREF, useValue: '/' }
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {
}

TweetService is working fine in my AppComponent, so there shouldn´t be a problem with the provider. This is the sequence of imports in my TweetDialogComponent (I can´t see anything wrong).

import { Component, OnInit } from '@angular/core';
import { MdDialogRef } from '@angular/material/dialog';

import { FirebaseObjectObservable } from 'angularfire2';

import { TweetService } from '../../shared/services/tweet.service';

The structure of the project (for the affected component) is this:

src/app/
       /app.module.ts
       /app.component.ts
       /shared/services/
                       /tweet.service.ts
                       /users.service.ts
       /components/tweet-dialog/
                               /tweet-dialog.component.ts
Community
  • 1
  • 1
David
  • 3,364
  • 10
  • 41
  • 84
  • 1
    Can your reproduce it here https://plnkr.co/edit/60XVFwQrc3ssSVvgUOIH?p=preview? – yurzui Nov 27 '16 at 06:58
  • That was some work, thanks! But I couldn´t reproduce it in the plunker... I reviewed everything and couldn´t find the flaw. I'm guessing it might be related to the ngModule, as it´s the only thing that's different with my code. Does the error mean that can´t find a provider for TweetService or that it can´t find an instance of TweetService or what? – David Nov 27 '16 at 10:28
  • Try to print `console.log(TweetService);` front of `TweetDialogComponent` component. Possible you have a wrong order of your imports. It's very well-known problem http://stackoverflow.com/questions/37997824/angular-2-di-error-exception-cant-resolve-all-parameters – yurzui Nov 27 '16 at 10:33
  • But I'm not using barrels... I can´t print console.log in TweetDialogComponent because the error breaks the execution in the constructor. – David Nov 27 '16 at 10:48
  • Print it before `@Component({ selector: 'app-tweet-dialog', templateUrl: './tweet-dialog.component.html' }) export class TweetDialogComponent implements OnInit {` `Can you show us structure of your project? – yurzui Nov 27 '16 at 10:51
  • I also injected another service in the constructor of TweetDialogComponent and it that one works fine... the error is still in TweetService for some reason ``Can't resolve all parameters for TweetDialogComponent: (MdDialogRef, UsersService, ?)`` – David Nov 27 '16 at 10:51
  • I think it's because `TweetService` is `undefined` – yurzui Nov 27 '16 at 10:52
  • Yes, it's undefined, but why?? I also printed UsersService and that one displays something. I'll update the post with the structure of the project. – David Nov 27 '16 at 10:53
  • See console output here https://plnkr.co/edit/60XVFwQrc3ssSVvgUOIH?p=preview – yurzui Nov 27 '16 at 10:55
  • Maybe you can share your project on github? – yurzui Nov 27 '16 at 10:58
  • sure thing, thanks https://github.com/davidanaya/angular2-twitter – David Nov 27 '16 at 11:00
  • It's circular dependency – yurzui Nov 27 '16 at 11:15
  • TweetDialogComponent --> TweetService --> TweetDialogComponent? – David Nov 27 '16 at 11:19
  • Ok, I get it. You can answer if you want and I'll accept the answer. Many thanks for your help. – David Nov 27 '16 at 11:25

1 Answers1

2

You faced with a circular dependency. (TweetDialogComponent --> TweetService --> TweetDialogComponent)

You can work around by using an abstract class:

base-tweet.service.ts

import { ViewContainerRef } from '@angular/core';

export abstract class BaseTweetService {
  getUser() {};

  sendTweet(viewContainerRef: ViewContainerRef) {}
}

app.module.ts

{ provide: BaseTweetService, useClass: TweetService },

app.component.ts

constructor(
    ...
    private tweetService: BaseTweetService, 

tweet-dialog.component.ts

constructor(
  ...
  private tweetService: BaseTweetService) {  

tweet.service.ts

export class TweetService implements BaseTweetService {

See also

Community
  • 1
  • 1
yurzui
  • 205,937
  • 32
  • 433
  • 399