如所见,接收注入上下文的常见角度错误。试图让所有各种角度组件包都在 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、收缩包以确保版本正确。
我自己的解决办法是,正如用户 Raphael VO 所说,删除计算的信号。问题是由于库使用不同版本的 Angular...