0

I am trying to use angular v18's provider to provide a new APP_INITIALIZER with dependencies JwtService and Auth Service. here's the code snippet for the logics

export function initAuth(jwtService: JwtService, authService: AuthService) {
  return () => (jwtService.getToken() ? authService.getCurrentUser() : EMPTY);
}

export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
    provideHttpClient(withInterceptors([jwtInterceptor])),
    {
      provide: APP_INITIALIZER,
      useFactory: initAuth,
      deps: [JwtService, AuthService, HttpClient],
      multi: true,
    },
  ],
};

the service for JwtService:

@Injectable({ providedIn: 'root' })
export class JwtService {
  getToken(): string {
    return window.localStorage['jwtToken'];
  }

  setToken(token: string): void {
    window.localStorage['jwtToken'] = token;
  }

  destroyToken(): void {
    window.localStorage.removeItem('jwtToken');
  }
}

the service for AuthService:

@Injectable({ providedIn: 'root' })
export class AuthService {
  private apiUrl = environment.apiUrl + '/Auth';
  private http = inject(HttpClient);
  private router = inject(Router);

  private _loggedInUserSubject = new BehaviorSubject<User | null>(null);
  currentUser$ = this._loggedInUserSubject.asObservable();
  isAuthenticated$ = this.currentUser$.pipe(map((u) => u !== null));

  constructor(private jwtService: JwtService) {}

  register(credentials: RegisterCredentials): Observable<boolean> {
    return this.http
      .post<{ username: string }>(this.apiUrl + '/register', credentials)
      .pipe(map((user) => user.username === credentials.username));
  }

  login(credentials: LoginCredentials): Observable<User> {
    return this.http
      .post<User>(this.apiUrl + '/login', credentials)
      .pipe(tap((user) => this.setAuth(user)));
  }

  logout() {
    this.purgeAuth();
    this.router.navigate(['']);
  }

  getCurrentUser() {
    return this.http.get<User>(this.apiUrl).pipe(tap((u) => this.setAuth(u)));
  }

  private setAuth(user: User) {
    this._loggedInUserSubject.next(user);
    this.jwtService.setToken(user.token);
  }

  private purgeAuth() {
    this._loggedInUserSubject.next(null);
    this.jwtService.destroyToken();
  }
}

the problem is when I run the application it gave me this error: enter image description here

as far as I know, this error only occurs when I haven't add a provider for the services. So then I tried to add providers:

export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
    provideHttpClient(withInterceptors([jwtInterceptor])),
    JwtService,
    AuthService,
    {
      provide: APP_INITIALIZER,
      useFactory: initAuth,
      deps: [JwtService, AuthService, HttpClient],
      multi: true,
    },
  ],
};

And then I got a new error: enter image description here

How do I resolve this issue when I try to add dependencies to APP_INITIALIZER in angular 18? Or is there an issue that I am missing at?

EDIT:

After I checked the code, it appears that the AuthService is the reason for the 'Invalid provider' Error.

3
  • Why did you add HttpClient to the deps? Commented Sep 4, 2024 at 8:28
  • @JSONDerulo I tried following angular.dev/api/core/APP_INITIALIZER and assume that my app is also a standalone project. Tho nothing changed and the errors are still the same Commented Sep 4, 2024 at 8:44
  • 1
    Oh I just realized that HttpClient is totally unnecessary, my bad. The main error is Invalid provider when I try to add JwtService and AuthService @JSONDerulo Commented Sep 4, 2024 at 10:21

2 Answers 2

0

The error might be that you do not return a corresponding value. The app initializer expects a function to be returned, if that's not the case, try

 useFactory: () => initAuth,
Sign up to request clarification or add additional context in comments.

1 Comment

It still gives me the same error unfortunately
0

After trying out the deps and providers by adding some things, and removing it; I figure out that I need to add the dependencies by using inject(). (not deps)

const initAuth = () => {
  const jwtService = inject(JwtService);
  const authService = inject(AuthService);
  return () => (jwtService.getToken() ? authService.getCurrentUser() : EMPTY);
};

export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
    provideHttpClient(withInterceptors([jwtInterceptor])),
    {
      provide: APP_INITIALIZER,
      useFactory: initAuth,
      multi: true,
    },
  ],
};

1 Comment

Aside, based on your code in the question, the argument in initAuth must be the same (type & position) as what you provide in deps. As there is no HttpClient in the initAuth arguments, so you should remove HttpClient from the deps array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.