Can you use an angular standalone component to import a module that contains your whole app

Discussão em 'Angular' iniciado por adam, Março 11, 2025.

  1. adam

    adam Guest

    I am trying to make a project manager in angular and host it with cloudflare. I can't get my login page to come up. The console gives me this

    main-NTC3P324.js:7 ERROR TypeError: Cannot read properties of null (reading 'nextSibling')


    Here's my directory structure:

    src
    |___app
    | |___base
    | | |___http
    | | | |___auth-inteceptor.ts
    | | |___pages
    | | | |___private
    | | | | |___BaseComponent.ts
    | | | |___public
    | | | | |___login
    | | | | | |___login.component.html
    | | | | | |___login.component.scss
    | | | | | |___login.component.ts
    | | | | |___BaseComponent.ts
    | | |___services
    | | | |___user.service.ts
    | | | |___cache.service.ts
    | | |___base.module.ts
    | |___lib
    | | |___model.ts
    | |___app.component.html
    | |___app.component.scss
    | |___app.component.ts
    | |___app.config.server.ts
    | |___app.config.ts
    | |___app.routes.server.ts
    | |___app.routes.ts
    | |___environment.ts
    |____routes.json
    |___index.html
    |___main.server.ts
    |___main.ts
    |___server.ts
    |___styles.scss


    src/main.ts

    import { bootstrapApplication } from '@angular/platform-browser';
    import { appConfig } from './app/app.config';
    import { AppComponent } from './app/app.component';

    bootstrapApplication(AppComponent, appConfig)
    .catch((err) => console.error(err));


    src/app/app.config.ts

    import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
    import { provideRouter } from '@angular/router';

    import { routes } from './app.routes';
    import { provideClientHydration, withEventReplay } from '@angular/platform-browser';

    export const appConfig: ApplicationConfig = {
    providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideClientHydration(withEventReplay())]
    };


    src/app/app.component.ts

    import { Component } from '@angular/core';
    import { RouterOutlet } from '@angular/router';
    import { BaseModule } from './base/base.module';

    @Component({
    selector: 'app-root',
    imports: [RouterOutlet, BaseModule],
    templateUrl: './app.component.html',
    styleUrl: './app.component.scss'
    })
    export class AppComponent {}


    src/app/app.component.html

    <router-outlet />


    src/app/app.routes.ts

    import { Routes } from '@angular/router';
    import { LoginComponent } from './base/pages/public/login/login.component';

    export const routes: Routes = [
    { path: '', component: LoginComponent }
    ];


    src/app/environment.ts

    export const BASE_URL = 'https://projectile.us';
    export const API_BASE_URL = 'https://api.project.us';


    src/app/base/base.module.ts

    import { NgModule } from '@angular/core';
    import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
    import { BrowserModule } from '@angular/platform-browser';
    import { CommonModule } from '@angular/common';
    import { FormsModule } from '@angular/forms';
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    import { MatDialogModule } from '@angular/material/dialog';
    import { MatButtonModule } from '@angular/material/button';
    import { MatAutocompleteModule } from '@angular/material/autocomplete';
    import { MatCardModule } from '@angular/material/card';
    import { MatCheckboxModule } from '@angular/material/checkbox';
    import { MatBadgeModule } from '@angular/material/badge';
    import { MatDatepickerModule } from '@angular/material/datepicker';
    import { MatExpansionModule } from '@angular/material/expansion';
    import { MatFormFieldModule } from '@angular/material/form-field';
    import { MatGridListModule } from '@angular/material/grid-list';
    import { MatIconModule } from '@angular/material/icon';
    import { MatInputModule } from '@angular/material/input';
    import { MatListModule } from '@angular/material/list';
    import { MatMenuModule } from '@angular/material/menu';
    import { MatPaginatorModule } from '@angular/material/paginator';
    import { MatProgressBarModule } from '@angular/material/progress-bar';
    import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
    import { MatRadioModule } from '@angular/material/radio';
    import { MatSelectModule } from '@angular/material/select';
    import { MatSidenavModule } from '@angular/material/sidenav';
    import { MatSnackBarModule } from '@angular/material/snack-bar';
    import { MatSortModule } from '@angular/material/sort';
    import { MatTableModule } from '@angular/material/table';
    import { MatTimepickerModule } from '@angular/material/timepicker';
    import { MatTooltipModule } from '@angular/material/tooltip';
    import { MatDividerModule } from '@angular/material/divider';

    import { authInterceptor } from './http/auth-interceptor';
    import { LoginComponent } from './pages/public/login/login.component';

    const BASE = [
    LoginComponent
    ]

    @NgModule({
    declarations: BASE,
    imports: [
    BrowserModule,
    CommonModule,
    FormsModule,
    BrowserAnimationsModule,
    MatDialogModule,
    MatButtonModule,
    MatAutocompleteModule,
    MatCardModule,
    MatCheckboxModule,
    MatBadgeModule,
    MatDatepickerModule,
    MatExpansionModule,
    MatFormFieldModule,
    MatGridListModule,
    MatIconModule,
    MatInputModule,
    MatListModule,
    MatMenuModule,
    MatPaginatorModule,
    MatProgressBarModule,
    MatProgressSpinnerModule,
    MatRadioModule,
    MatSelectModule,
    MatSidenavModule,
    MatSnackBarModule,
    MatSortModule,
    MatTableModule,
    MatTimepickerModule,
    MatTooltipModule,
    MatDividerModule,
    ],
    providers: [
    provideHttpClient(withFetch(), withInterceptors([authInterceptor]))
    ],
    exports: BASE
    })
    export class BaseModule {}


    src/app/base/services/user.service.ts

    import { Injectable, inject } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { Observable } from 'rxjs';

    import { API_BASE_URL } from '../../environment';
    import { User } from '../../lib/model';


    export interface LoginResponse {
    user: User;
    authToken: string;
    }

    @Injectable({
    providedIn: 'root'
    })
    export class UserService {
    private http = inject(HttpClient);

    get authToken(): string | null {
    return localStorage.getItem('authToken');
    }

    set authToken(value: string) {
    localStorage.setItem('authToken', value);
    }

    user!: User;

    constructor() { }

    login(email: string, password: string, remember: boolean): Observable<LoginResponse> {
    return this.http.post<LoginResponse>(API_BASE_URL + 'authenticate', {
    email,
    password,
    remember
    });
    }

    isLoggedIn(): Observable<LoginResponse | false> {
    return this.http.get<LoginResponse | false>(API_BASE_URL + 'authenticated');
    }
    }


    src/app/base/servivces/cache.service.ts

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

    @Injectable({
    providedIn: 'root'
    })
    export class CacheService extends Map<string, any> {}


    src/app/base/http/auth-interceptor.ts

    import { inject } from "@angular/core";
    import { HttpRequest, HttpHandlerFn, HttpEvent } from "@angular/common/http";
    import { Observable } from 'rxjs';
    import { UserService } from "../services/user.service";

    export function authInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> {
    let svc = inject(UserService);
    let request = req;

    if(svc.authToken) {
    request = req.clone({
    setHeaders: {
    Authorization: `Bearer ${svc.authToken}`
    }
    });
    }

    return next(request);
    }



    src/app/base/pages/public/BaseComponent.ts

    import { Component, OnInit } from '@angular/core';
    import { Router } from '@angular/router';

    import { UserService } from '../../services/user.service';
    import { CacheService } from '../../services/cache.service';

    @Component({
    selector: 'app-public-base',
    template: '',
    styles: [],
    standalone: false
    })
    export class BaseComponent implements OnInit {
    constructor(
    protected router: Router,
    protected userService: UserService,
    protected cache: CacheService
    )
    {}

    ngOnInit() {
    this.userService.isLoggedIn().subscribe(res => {
    if(res) {
    this.router.navigate(['/dashboard']);
    }
    });
    }
    }


    src/app/base/pages/public/login/login.component.ts

    import { Component } from '@angular/core';
    import { LoginResponse, UserService } from '../../../services/user.service';
    import { BaseComponent } from '../BaseComponent';
    import { Router } from '@angular/router';
    import { CacheService } from '../../../services/cache.service';

    @Component({
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrl: './login.component.scss',
    standalone: false
    })
    export class LoginComponent extends BaseComponent {
    email: string = '';
    password: string = '';
    remember: boolean = false;

    constructor(
    router: Router,
    userService: UserService,
    cache: CacheService
    ) { super(router, userService, cache); }

    login() {
    this.userService.login(this.email, this.password, this.remember).subscribe(res => {
    this.userService.authToken = res.authToken;
    this.userService.user = res.user;

    this.router.navigate([this.cache.has('landingPage') ? this.cache.get('landingPage') : '/dashboard']);
    });
    }
    }


    src/app/base/pages/public/login/login.component.html

    <div class="flexbox">
    <div class="inner">
    <form (ngSubmit)="login()">
    <mat-card appearance="outlined">
    <mat-card-header>
    <mat-card-title>Login</mat-card-title>
    </mat-card-header>
    <mat-card-content>
    <mat-form-field appearance="fill">
    <mat-label>Email</mat-label>
    <input matInput [(ngModel)]="email" required email>
    </mat-form-field>
    <mat-form-field apperaence="fill">
    <mat-label>Password</mat-label>
    <input matInput type="password" [(ngModel)]="password" required>
    </mat-form-field>
    <section>
    <mat-checkbox [(ngModel)]="remember">Remember Me</mat-checkbox>
    </section>
    </mat-card-content>
    <mat-card-actions>
    <button mat-raised-button color="primary" type="submit">Login</button>
    </mat-card-actions>
    </mat-card>
    </form>
    </div>
    </div>


    src/app/base/pages/public/login/login.component.scss

    .flexbox {
    display: flex;
    align-items: center;
    justify-content: center;
    }

    .flexbox > .inner {
    width: 400px;
    }


    Am I getting that error because I'm importing BaseModule into a standalone component and routing to the base module's login component?

    Continue reading...

Compartilhe esta Página