NG0203:必须从注入上下文调用 Inject()。角度 v19.0.1

问题描述 投票:0回答:1

如所见,接收注入上下文的常见角度错误。试图让所有各种角度组件包都在 v19.0.1 上,但某种不匹配仍然存在。尝试过各种其他解决方案,例如 persistsymlinks: true、覆盖包、删除不明确的路径等。我有一种感觉,这是由于角度/材料造成的,这就是

npm ls @angular/core
显示的内容。 我的package.json:

{
  "name": "client",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "tailwind": "npx tailwindcss -i ./src/input.css -o ./src/output.css",
    "tailwind:watch": "npx tailwindcss -i ./src/input.css -o ./src/output.css --watch",
    "dev": "npm run tailwind:watch & ng serve"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "19.0.1",
    "@angular/common": "19.0.1",
    "@angular/compiler": "19.0.1",
    "@angular/core": "19.0.1",
    "@angular/forms": "19.0.1",
    "@angular/platform-browser": "19.0.1",
    "@angular/platform-browser-dynamic": "19.0.1",
    "@angular/router": "19.0.1",
    "@supabase/supabase-js": "^2.46.2",
    "rxjs": "~7.8.0",
    "supabase": "^1.223.10",
    "tslib": "^2.3.0",
    "zone.js": "~0.15.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^19.0.1",
    "@angular/cli": "^19.0.1",
    "@angular/compiler-cli": "19.0.1",
    "@types/jasmine": "~5.1.0",
    "css-loader": "^7.1.2",
    "jasmine-core": "~5.4.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "style-loader": "^4.0.0",
    "tailwindcss": "^3.4.15",
    "typescript": "~5.6.2"
  },
  "resolutions": {
    "@angular/material": "19.0.1",
    "@angular/cdk": "19.0.1",
    "@angular/core": "19.0.1",
    "@angular/common": "19.0.1",
    "@angular/forms": "19.0.1",
    "@angular/animations": "19.0.1",
    "@angular/platform-browser": "19.0.1",
    "@angular/router": "19.0.1"
  },
  "overrides": {
    "@angular/core": "19.0.1",
    "@angular/common": "19.0.1",
    "@angular/forms": "19.0.1",
    "@angular/platform-browser": "19.0.1",
    "@angular/router": "19.0.1",
    "@angular/animations": "19.0.1",
    "@angular/material": "19.0.1",
    "@angular/cdk": "19.0.1",
    "@supabase/supabase-js": {
      "@supabase/auth-js": "2.61.0"
    }
  }
}

我的supabase服务.ts:

import { Injectable } from '@angular/core'
import {
  AuthChangeEvent,
  AuthError,
  AuthSession,
  createClient,
  Session,
  SupabaseClient,
  User,
} from '@supabase/supabase-js';
import { environment } from '../environments/environment'
import { Database } from '../types/database.types';
import { Observable, Subject, Subscription } from 'rxjs';

export interface Profile {
  id?: string
  avatar_url: string
}

export interface Destination {
  id: number;
  Destination: string;
  Region: string;
  Country: string;
  Description?: string;
  Latitude?: number;
  Longitude?: number;
  Best_time_to_visit?: string;
  Average_temperature?: number;
}

export interface DestinationList {
  id?: number;
  user_id: string;
  name: string;
  description?: string;
  is_public: boolean;
  destinations: string[];
  created_at: Date;
  updated_at: Date;
}

export interface DestinationListWithDetails extends DestinationList {
  destinations_details?: Destination[]; // Full destination details
}

export interface ListReview {
  id?: number;
  list_id: number;
  user_id: string;
  username: string;
  rating: number;
  comment: string;
  created_at: Date;
}


@Injectable({
  providedIn: 'root',
})
export class SupabaseService {
  private supabase: SupabaseClient;
  // using a subject here, emits observables and can receive observables
  private authSubject = new Subject<{ event: string, session: Session | null }>();

  constructor() {
    this.supabase = createClient<Database>(environment.supabaseUrl, environment.supabaseKey, {
      auth: {
        persistSession: true
      }
    }); 
    // auth change listener
    this.supabase.auth.onAuthStateChange((event, session) => {
      this.authSubject.next({ event, session });
    });
  }
  
  async getSession(): Promise<{ data: { session: Session | null }; error: AuthError | null }> {
    return this.supabase.auth.getSession();
  }

  profile(user: User) {
    return this.supabase
      .from('profiles')
      .select(`username, website, avatar_url`)
      .eq('id', user.id)
      .single()
  }

  async searchDestinations(name: string = '', region: string = '', country: string = '', resultLimit: number = 5) {
    try {
      console.log('Search parameters:', { name, region, country });
      let query = this.supabase.from('Destinations').select('*');
  
      // reject empty fields from the search
      if (name && name.trim() !== '') {
        query = query.ilike('Destination', `${name.trim()}%`);
      }
    
      if (region && region.trim() !== '') {
        query = query.ilike('Region', `${region.trim()}%`);
      }
    
      if (country && country.trim() !== '') {
        query = query.ilike('Country', `${country.trim()}%`);
      } 
  
      query = query.limit(resultLimit); // limit the number of results shown

      const { data, error } = await query;
      console.log('basic query:', await query);
      console.log('Query Results:', data);
    if (error) {
      console.error('Query Error:', error);
    }

      return { data, error }; // Ensure you're returning an object
    } catch (err) {
      console.error('Unexpected error in searchDestinations:', err);
      return { data: null, error: err };
    }
  }

  // emit observable authcange events
  authChanges(): Observable<{ event: AuthChangeEvent; session: Session | null }> {
    return new Observable((observer) => {
      const { data: { subscription } } = this.supabase.auth.onAuthStateChange((event, session) => {
        observer.next({ event, session });
      });
  
      // Cleanup: Unsubscribe when the observer unsubscribes
      return () => subscription.unsubscribe();
    });
  }

  async getCurrentUser(): Promise<User | null> {
    const { data } = await this.getSession();
    return data.session?.user || null;
  }

  async getCurrentUserId(): Promise<string | null> {
    const user = await this.getCurrentUser();
    return user?.id || null;
  }

  async getCurrentUsername(): Promise<string | null> {
    const user = await this.getCurrentUser();
    return user?.email?.split('@')[0] || null; // Fallback to email username
  }

  signIn(email: string) {
    return this.supabase.auth.signInWithOtp({ email })
  }

  signOut() {
    return this.supabase.auth.signOut();
  }

  updateProfile(profile: Profile) {
    const update = {
      ...profile,
      updated_at: new Date(),
    }

    return this.supabase.from('profiles').upsert(update)
  }

  downLoadImage(path: string) {
    return this.supabase.storage.from('avatars').download(path)
  }

  uploadAvatar(filePath: string, file: File) {
    return this.supabase.storage.from('avatars').upload(filePath, file)
  }


  // *** User list creation *** //
  async createDestinationList(list: Partial<DestinationList>): Promise<{ data: DestinationList | null, error: any }> {
    // Validate required attributes
    if (!list.name || !list.user_id) {
      return { data: null, error: 'Name and user_id are required' };
    }

    // Check if user already has a list with this name
    const { data: existingLists, error: checkError } = await this.supabase
      .from('destination_lists')
      .select('*')
      .eq('user_id', list.user_id)
      .eq('name', list.name)
      .single();

    if (existingLists) {
      return { data: null, error: 'A list with this name already exists' };
    }

    // Check if user has reached the maximum number of lists
    const { count, error: countError } = await this.supabase
      .from('destination_lists')
      .select('*', { count: 'exact' })
      .eq('user_id', list.user_id);

    if (count && count >= 20) {
      return { data: null, error: 'Maximum number of lists (20) reached' };
    }

    // Prepare list data
    const listToCreate = {
      user_id: list.user_id,
      name: list.name,
      description: list.description || null,
      is_public: false, // Default to private
      destinations: list.destinations || [],
      created_at: new Date(),
      updated_at: new Date()
    };

    // Insert the list
    const { data, error } = await this.supabase
      .from('destination_lists')
      .insert(listToCreate)
      .select()
      .single();

    return { data, error };
  }


  async getUserLists(userId: string): Promise<{ data: DestinationList[] | null, error: any }> {
    const { data, error } = await this.supabase
      .from('destination_lists')
      .select('*')
      .eq('user_id', userId);

    return { data, error };
  }

  // Add these additional methods for list management
  async getListDetails(listId: number, userId: string): Promise<{ data: DestinationListWithDetails | null, error: any }> {
    const { data, error } = await this.supabase
      .from('destination_lists')
      .select(`
        *,
        destinations(*)
      `)
      .eq('id', listId)
      .eq('user_id', userId)
      .single();

    return { data, error };
  }

  async updateDestinationList(listId: number, userId: string, updates: Partial<DestinationList>): Promise<{ data: DestinationList | null, error: any }> {
    // Validate user ownership
    const { data: existingList, error: checkError } = await this.supabase
      .from('destination_lists')
      .select('*')
      .eq('id', listId)
      .eq('user_id', userId)
      .single();

    if (!existingList) {
      return { data: null, error: 'List not found or unauthorized' };
    }

    // Validate destination existence if destinations are being modified
    if (updates.destinations) {
      for (const destination of updates.destinations) {
        const { data: destCheck } = await this.searchDestinations(destination);
        if (!destCheck || destCheck.length === 0) {
          return { data: null, error: `Destination ${destination} does not exist` };
        }
      }
    }

    const updateData = {
      ...updates,
      updated_at: new Date()
    };

    const { data, error } = await this.supabase
      .from('destination_lists')
      .update(updateData)
      .eq('id', listId)
      .select()
      .single();

    return { data, error };
  }


  async deleteDestinationList(listId: number, userId: string): Promise<{ success: boolean, error: any }> {
    const { error } = await this.supabase
      .from('destination_lists')
      .delete()
      .eq('id', listId)
      .eq('user_id', userId);

    return { 
      success: !error, 
      error 
    };
  }


  // *** List reviews *** //
  async addListReview(review: Partial<ListReview>): Promise<{ data: ListReview | null, error: any }> {
    // Validate review data
    if (!review.list_id || !review.user_id || !review.rating) {
      return { data: null, error: 'Missing required review information' };
    }
  
    const reviewToCreate = {
      ...review,
      created_at: new Date()
    };
  
    const { data, error } = await this.supabase
      .from('list_reviews')
      .insert(reviewToCreate)
      .select()
      .single();
  
    return { data, error };
  }
  
  async getListReviews(listId: number): Promise<{ data: ListReview[] | null, error: any }> {
    const { data, error } = await this.supabase
      .from('list_reviews')
      .select('*')
      .eq('list_id', listId)
      .order('created_at', { ascending: false });
  
    return { data, error };
  }
}

npm ls @angular/core:

 npm ls @angular/core
+-- @angular/[email protected]
| +-- @angular/[email protected]
| | `-- @angular/[email protected] deduped
| +-- @angular/[email protected]
| | `-- @angular/[email protected] deduped
| +-- @angular/[email protected]
| | `-- @angular/[email protected] deduped
| +-- @angular/[email protected]
| +-- @angular/[email protected]
| | `-- @angular/[email protected] deduped
| `-- @angular/[email protected]
|   `-- @angular/[email protected] deduped
`-- @auth0/[email protected]
  +-- @angular/[email protected] deduped
  `-- @angular/[email protected]
    `-- @angular/[email protected] deduped

期望能够在我的项目中使用该组件而不会抛出错误。尝试过:调整包版本、各种配置设置、删除并重新下载node_modules、收缩包以确保版本正确。

angular dependency-injection angular-material dependencies supabase
1个回答
0
投票

我自己的解决办法是,正如用户 Raphael VO 所说,删除计算的信号。问题是由于库使用不同版本的 Angular...

© www.soinside.com 2019 - 2024. All rights reserved.