Angular لا يمكنه حقن الخدمة: تحليل كامل للخطأ

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا يصرخ Angular بـ «Can't resolve all parameters»؟

أنت تكتب أول مكون Angular خاص بك، وتضيف بفخر خدمة في المُنشئ للعمل مع API، وتشغل التطبيق - وفجأة تحصل على رسالة حمراء في وحدة التحكم:

EXCEPTION: Can't resolve all parameters for MyComponent: (?).

مألوف؟ هذا الخطأ هو حجر عثرة حقيقي للمبتدئين وحتى المطورين ذوي الخبرة الذين ينتقلون من AngularJS. يحدث عندما لا يستطيع Angular فهم أي خدمة بالضبط يجب حقنها في المكون. في هذه المقالة، سنحلل جميع أسباب الخطأ Can't resolve all parameters for component، ونعرض أمثلة حية على TypeScript ونقدم حلولاً خطوة بخطوة. لن تقوم فقط بإصلاح الخلل، بل ستفهم أيضًا كيفية عمل Dependency Injection (DI) في Angular.



ما هو Dependency Injection ولماذا هو مهم؟

Angular مبني على نظام حقن التبعيات (DI). عندما تكتب:

constructor(private myService: MyService) {}

يقوم Angular تلقائيًا بإنشاء نسخة من MyService وتمريرها إلى المكون. ولكن للقيام بذلك، يجب أن يعرف ثلاثة أشياء:

  • أي نوع (فئة) يجب حقنه.
  • أين تم تسجيل المزود لهذا النوع.
  • ماذا يفعل إذا لم يكن هناك مزود.

إذا لم يتم استيفاء واحد على الأقل من هذه النقاط، تحصل على الخطأ «Can't resolve all parameters».



الأسباب الرئيسية للخطأ

لقد حددنا 5 سيناريوهات الأكثر شيوعًا التي تؤدي إلى هذا الخطأ. سنحلل كل منها مع الكود.



1. الخدمة غير مسجلة في المزودين

السبب الأكثر وضوحًا. لقد أنشأت خدمة، لكنك نسيت إضافتها إلى providers في الوحدة أو المكون.

مثال على الكود الخاطئ:

// my.service.ts@Injectable()export class MyService {  getData() { return 'data'; }}

// my.component.ts@Component({ selector: 'app-my', template: '...' })export class MyComponent { constructor(private myService: MyService) {} // خطأ!}

الحل: سجل الخدمة في الوحدة:

@NgModule({  providers: [MyService] // <-- إجباري})export class AppModule { }

أو في المكون نفسه (إذا كانت الخدمة مطلوبة له فقط):

@Component({  providers: [MyService]})export class MyComponent { ... }


2. عدم وجود المُزَيِّن @Injectable()

حتى إذا قمت بتسجيل الخدمة في المزودين، لكنك نسيت إضافة المُزَيِّن @Injectable() - لن يتمكن Angular من قراءة البيانات الوصفية.

مثال:

// بدون مُزَيِّنexport class MyService { ... }

// في المكونconstructor(private myService: MyService) {} // خطأ!

الحل: أضف دائمًا @Injectable():

@Injectable({ providedIn: 'root' }) // أو فقط @Injectable()export class MyService { ... }

بالمناسبة، providedIn: 'root' يسجل الخدمة تلقائيًا على مستوى الحاقن الجذري - هذه هي الطريقة الحديثة والموصى بها.



3. تعارض مع تجميع AOT ومعاملات المُنشئ

يستخدم Angular وضعين للتجميع: JIT (Just-in-Time) و AOT (Ahead-of-Time). غالبًا ما يظهر الخطأ Can't resolve all parameters مع AOT إذا لم يحتفظ TypeScript بمعلومات حول أنواع المعاملات.

السبب: في الإصدارات القديمة من Angular (قبل 5) أو عند استخدام إعدادات معينة لـ tsconfig، قد يقوم TypeScript بحذف البيانات الوصفية للأنواع. على سبيل المثال، إذا كنت تستخدم emitDecoratorMetadata: false أو نسيت استيراد reflect-metadata.

الحل:

  • تأكد من وجود "emitDecoratorMetadata": true و "experimental في tsconfig.json.

المدونات

توصيات الكتب