Angular: استثناء: لقد تغير التعبير بعد فحصه.

تم إنشاؤها على ١٨ ديسمبر ٢٠١٥  ·  147تعليقات  ·  مصدر: angular/angular

التعليق الأكثر فائدة

هذا ليس خطأ ، إنه سمة من سمات وضع dev الذي يعمل على النحو المنشود. استدعاء enableProdMode( ) - اطلع على تحديث plunk عند بدء تشغيل التطبيق يمنع طرح الاستثناء.

ومع ذلك ، يتم إلقاؤه لسبب وجيه: باختصار ، بعد كل جولة من اكتشاف التغيير ، يقوم وضع dev على الفور بإجراء جولة ثانية للتحقق من عدم تغيير أي ارتباطات منذ نهاية الجولة الأولى ، حيث يشير ذلك إلى حدوث تغييرات عن طريق الكشف عن التغيير نفسه.

في مخططك ، لديك الارتباط [attr.spinner]=isLoading ، و isLoading يتغير كنتيجة لمكالمتك بـ this.load() ، والذي يحدث عند إطلاق ngAfterViewInit ، والذي يحدث كجزء من المنعطف الأولي لاكتشاف التغيير. هذا في حد ذاته ليس مشكلة - المشكلة هي أن this.load() يغير ارتباطًا ولكنه لا يؤدي إلى جولة جديدة من اكتشاف التغيير ، مما يعني أن هذا الارتباط لن يتم تحديثه حتى جولة مستقبلية من اكتشاف التغيير.

ال 147 كومينتر

لقد كنت أواجه مشكلة مماثلة ، ويبدو أن السبب في ذلك هو كيفية تهيئة الطفل ، وكيف يمكن لأحد الوالدين تحديث الطفل كجزء من عملية التهيئة الخاصة به. لدي عينة مماثلة باستخدام حل قبيح باستخدام المنطقة: http://plnkr.co/edit/GI45u805pnFUtFeORnxn؟p=preview ، مع ظهور الحل كما يلي:

المنشئ (private _zone: NgZone) {}

ngAfterViewInit (): باطل {
this._zone.overrideOnTurnDone (() => {
this.child.title = 'title from parent'؛
}) ؛
}

هذا ليس خطأ ، إنه سمة من سمات وضع dev الذي يعمل على النحو المنشود. استدعاء enableProdMode( ) - اطلع على تحديث plunk عند بدء تشغيل التطبيق يمنع طرح الاستثناء.

ومع ذلك ، يتم إلقاؤه لسبب وجيه: باختصار ، بعد كل جولة من اكتشاف التغيير ، يقوم وضع dev على الفور بإجراء جولة ثانية للتحقق من عدم تغيير أي ارتباطات منذ نهاية الجولة الأولى ، حيث يشير ذلك إلى حدوث تغييرات عن طريق الكشف عن التغيير نفسه.

في مخططك ، لديك الارتباط [attr.spinner]=isLoading ، و isLoading يتغير كنتيجة لمكالمتك بـ this.load() ، والذي يحدث عند إطلاق ngAfterViewInit ، والذي يحدث كجزء من المنعطف الأولي لاكتشاف التغيير. هذا في حد ذاته ليس مشكلة - المشكلة هي أن this.load() يغير ارتباطًا ولكنه لا يؤدي إلى جولة جديدة من اكتشاف التغيير ، مما يعني أن هذا الارتباط لن يتم تحديثه حتى جولة مستقبلية من اكتشاف التغيير.

أحتاج إلى إعداد المكون الخاص بي في afterViewInit لأن لدي ChildView تمت تهيئته هنا. ما هي الطريقة الصحيحة لإجراء هذا التغيير على isLoading ؟ إلغاء المكالمة إلى this.load بواسطة setTimeout ؟

ما عليك سوى القيام بشيء ما ، أي شيء ، يؤدي إلى جولة أخرى من اكتشاف التغيير خلال تلك الطريقة - قم بإصدار حدث ، أو أي شيء آخر. يعد تغليفها في مهلة (قائمة الانتظار للارتجاع إلى ng1 :-P) إحدى الطرق التي ستنجح ، لكنها تشعر بالفوضى الفائقة بالنسبة لي في ng2.

لا يبدو سهل الاستخدام. أفكر في هذه الطريقة اعتبارًا من المكان الذي يمكنني فيه إكمال تهيئة المكون الخاص بي عندما يتم تحديد عناصرها الفرعية ، والآن اتضح أن لديها بعض القواعد المخصصة. أعتقد أنه يجب عليك فرض جولة جديدة للكشف عن التغيير داخليًا بحيث يتم إخفاؤها داخل ng2 من المستخدم.

هل يمكنك نشر عينة تمثيلية أكثر لما تحاول تحقيقه هنا؟ إذا كانت الصورة تدور حول صورتك ، فمن الأفضل استخدام ربط قياسي.

@ AerisG222 كما سبق لك. هل هناك أي سبب يمنعك من استخدام رابط بسيط لتحقيق ذلك؟ عادة لا يوصى بتجاوز سلوك المنطقة.

robwormald نعم ، في هذه الحالة يمكنني عمل ربط الخاصية. تتضمن الحالة الحقيقية التي أملكها أيضًا خاصية أخرى أكثر تعقيدًا بعض الشيء - مجموعة من الكائنات المخصصة ، ولكن من المؤكد أيضًا أنه يمكن تعيينها عبر ربط الخاصية.

أفترض أنه إذا لم يكن هناك شيء مثل @ViewChild ، فلن أهتم كثيرًا ، لأن هذه ستكون الطريقة المعقولة الوحيدة لتمرير المعلومات. ومع ذلك ، كنت متحمسًا جدًا لرؤية @ViewChild حتى أتمكن من التخلص من ذلك على مراجع المكون في التعليمات البرمجية. هذا يبسط الترميز ويسمح بمزيد من التحكم عبر الكود ، وهو أيضًا ذو قيمة مع الكتابة المطبوعة حيث يوجد المزيد من دعم الأدوات (مثل التحسس والتحقق من وقت الترجمة). كما أنه يبسط مكون الحاوية لأنه لا يتعين عليه تتبع متغيرات الأعضاء التي تهدف فقط إلى استخدامها كحالة للطفل.

نقطة ثانوية أخرى هي عند البحث في تطبيق باستخدام بناء جملة ربط الخاصية ، يجب عليك فحص القالب لمعرفة من الذي يستهلك البيانات في النهاية. سيكون هذا أكثر وضوحًا عند توصيله سلكيًا عبر رمز.

لقد قمت بتنظيف الكود لإظهار ما يهم فقط في المثال. الفكرة هي إظهار القرص الدوار فقط أثناء تحميل الصورة ثم إزالة القرص الدوار وإظهار الصورة. يتم تحميل الصورة فقط عندما يكون العنصر مرئيًا على الشاشة.

inflate.ts

import {Component, Input, Renderer, ElementRef, AfterViewInit, ViewChild} from 'angular2/core';

@Component({
  selector: '[inflate]',
  templateUrl: './inflate.html',
  styleUrls: ['./inflate.css']
})
export class Inflate implements AfterViewInit {
  @Input('inflate') url: string;
  @ViewChild('holder') holder: ElementRef;
  isLoaded = false;
  isLoading = false;

  constructor(private renderer: Renderer) {}

  ngAfterViewInit() {
    setTimeout(_=> this.inflate()); // BUGFIX: https://github.com/angular/angular/issues/6005#issuecomment-165911194
  }

  inflate() {
    let bounds = <ClientRect>this.holder.nativeElement.getBoundingClientRect();
    if(bounds.bottom > 0 && bounds.top < window.innerHeight) {
      this.isLoading = true;
      let img = new Image();
      img.src = this.url;
      img.onload = _=> {
        this.isLoaded = true;
        this.isLoading = false;
        this.renderer.setElementStyle(this.holder,
          'background-image', 'url("' + this.url + '")');
      };
    }
  }
}

inflate.html

<image-holder #holder></image-holder>
<spinner *ngIf="isLoading"></spinner>

أحتاج إلى الاحتفاظ بالصورة ليست في المضيف لأنه بينما تتلاشى مع الرسوم المتحركة عند اكتمال التحميل ، لا ينبغي أن تؤثر على تعتيم خلفية المضيف.

لدي مشكلة يحتمل أن تكون مرتبطة بتوجيه متداخل.
http://plnkr.co/edit/myX2Alx9jie2q0FDIME7؟p=preview
أنا هنا ملزم بـ ngStyle في progressBar.ts.
أقوم بتسجيل كائن الأنماط قبل العودة لإثبات أنها متساوية.
أحصل أيضًا على ExpressionChangedAfterItHasBeenCheckedException.

@ svi3c أنت تقوم بالفعل بإرجاع كائن _different_. سيعود كل استدعاء دالة إلى مثيل كائن جديد "يساوي" مثيله السابق من حيث المفاتيح / القيم ولكن ليس من حيث الأمثلة / المراجع.

هناك عدة طرق للتعامل مع هذا الموقف:

  • تحديث القيم في مثيل كائن واحد ، بدلاً من إرجاع نسخة جديدة
  • باستخدام إستراتيجية ChangeDetectionStrategy.OnPush لذلك يتم استدعاء وظيفتك فقط عندما يتغير أحد المدخلات ، على سبيل المثال: http://plnkr.co/edit/NWyVoTtkiAzqWJphLMbi؟p=preview

قد ترغب في التحقق من https://github.com/ng-bootstrap/core/blob/master/src/progressbar/progressbar.ts كمثال آخر لتوجيه شريط التقدم لـ ng2 (باستخدام HTML / CSS الخاص بـ bootstrap)

@ pkozlowski-openource شكرا جزيلا لك!
قرأت فقط https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngstyle ولم أتعثر بعد على استراتيجيات الكشف عن التغيير. هذا جيد! :)

@ درو مور:

ما عليك سوى القيام بشيء ما ، أي شيء ، يؤدي إلى جولة أخرى من اكتشاف التغيير خلال تلك الطريقة - قم بإصدار حدث ، أو أي شيء آخر.

هل يمكنك أن تنصح ما هي الطريقة _ الصحيحة _ والأبسط _ لإعادة تشغيل اكتشاف التغيير داخل ngAfterViewInit - بافتراض أن كل ما هو مطلوب هو خاصية يجب تحديثها. ApplicationRef.tick() لا يعمل هنا لأن هذا يتسبب في استدعاء "ApplicationRef.tick بشكل متكرر" ؛ إن إصدار حدث لمجرد تشغيل اكتشاف التغيير يبدو خاطئًا (ولم ينجح معي) ، وكذلك الأمر مع setTimeout .

استنادًا إلى التعليقات هنا ، يبدو أنه من المتطلبات الشائعة إلى حد ما تحديث خاصية ملزمة في ngAfterViewInit (بسبب الاعتماد على مكون فرعي) ، لذلك يبدو أن Angular 2 تفتقد إلى طريقة بسيطة للقيام بذلك.

إذا كان تحديث خاصية ملزمة في ngAfterViewInit هو الشيء _wrong_ الذي يجب القيام به ، فما البديل؟

هذه واحدة سريعة:

تحد:
قم بتعيين ارتفاع عنصر dom (عبر صيغة معينة) بناءً على عرضه المقدم.

توقع:
عندما يتم عرض العنصر ، احصل على العرض وبناءً عليه ، احسب ارتفاعه.

الواقع:
setTimeout ؟!

  ngAfterViewInit() {
    window.setTimeout(() =>
      this.elementHeight = (this.nativeElement.offsetWidth * this.randomImage.dim.h) / this.randomImage.dim.w
    )
  }

تضمين التغريدة

zoechi هنا مثال: http://plnkr.co/edit/MML5uHEFQdL0k0TA5HtY

يمكنك تبديل setTimeout في app/app.component.ts#21 في ربط دورة الحياة ngAfterViewInit .

لقد واجهت أيضًا شيئًا مشابهًا عند محاولة تطبيق طريقة writeValue( newValue ) لطريقة ngModel valueAccessor . عندما أحاول تطبيق newValue على المكون ، يخبرني أن القيمة قد تغيرت (بطريقة سيئة). مثلما وجدتم جميعًا ، فإن تغليفه في setTimeout () "يصلح" ؛ ولكن ليس بطريقة جيدة.

لدي مثال آخر . إنه أبسط نوعًا ما لأنه تم إعداد @HostBinding() ويتم إخطاره بواسطة QueryList .

مثل مشكلتي رقم 5950.

بعض التوصيات هنا حول كيفية القيام بذلك بشكل نظيف.
http://stackoverflow.com/questions/34827334/triggering-angular2-change-detection-manually

ومع ذلك ، ما زلت ألتف في setTimeout لأنني لم أتمكن من جعل أي منهم يفعل ما أحتاجه. يبدو أنه يمكنني ChangeDetectorRef.detectChanges() في نهاية رد الاتصال وتشغيل القرص المضغوط .... هل فاتني شيء؟ ربما سيساعد أحدكم يا رفاق.

أنا أستخدم ملحقات مصدر وسائط HTML5 لإنشاء سياق صوتي بناءً على عنصر فيديو ، لذا يلزم استخدام @ViewChild . بناءً على سياق الصوت ، أحاول عرض بعض المعلومات ، مثل عدد القنوات. ومع ذلك ، واجهت هذه المشكلة أيضًا. ما هي الطريقة الصحيحة لتجاوز هذا؟

ElswhereGames من الصعب معرفة ذلك دون رؤية بعض التعليمات البرمجية الفعلية. يمكنك إنشاء Plunker

zoechi ليس لدي خطأ فعلي للإبلاغ عنه ، فقط قائلًا إن عدم الوصول إلى DOM مباشرة ، على الرغم من أنه مرغوب فيه ، إلا أنه ليس دائمًا شيء يمكن تجنبه (ردًا على تعليق robwormald ). بالنسبة لواجهة برمجة التطبيقات الفعلية ، راجع المستندات الموجودة على

لقد أرسلت مرة أخرى في يناير مع مشكلة _ngModel_. الآن ، عدت مرة أخرى مع مشكلة _ViewChildren_. ومع ذلك ، على عكس بعض هذه الأمثلة الأخرى ، فأنا لا أحاول فعل أي شيء في العرض التوضيحي الخاص بي. بمعنى ، وحدات التحكم الخاصة بي لها منطق صفري - إنها جميع بيانات التعريف وارتباطات العرض. على هذا النحو ، لست متأكدًا من المكان الذي توجد فيه مساحة كبيرة للمناورة لأفهم الأشياء:

http://www.bennadel.com/blog/3040-i-have-a-fundamental-misunderstanding-of-change-detection-in-angular-2-beta-8.htm

تواجه مشكلة مماثلة ولكن يمكن إعادة كتابة التعليمات البرمجية للتغلب عليها. لقد ضحكت جيدًا مع مشاركة

https://github.com/angular/angular/issues/6618

حتى الآن ، كان لدينا دائمًا طريقة لحلها ، ولكننا سأقترحها هنا مرة أخرى على الأقل ، يمكن أن تستخدم آلية الكشف عن التغيير المزيد من الوثائق. bennadel مشكلتك تذكرني بقضية أخرى ،

https://github.com/angular/angular/issues/5177

مكان حل هذه المشكلة ، تم اقتراح إضافة خطاف دورة الحياة الإضافية OnBeforeBinding / OnBeforeRendering. يبدو أن هذا الحل سيحل مشكلتك أيضًا.

tandu فقط ngAfterViewInit إلى ngOnInit

@ e-oz https: //github.com/angular/issues/6005#issuecomment -165906207

tandu لا يهم حقًا متى سيبدأ الدوار الخاص بك (تحميل الطفل ، تحميل الصورة في الطفل - بالنسبة للمستخدم يتم تحميل كل شيء) ، يهم فقط عندما تحتاج إلى إيقاف تشغيله. يمكنك إيقاف تشغيله في "ngAfterViewInit" ، باستخدام setTimeout (أوافق على أنه قبيح) ، ولكنه سيكون خاطئًا - يجب أن يطلق المكون الفرعي حدثًا عند اكتمال تحميل الصورة ، إلى المكون الرئيسي. تحميل المكون الفرعي وتحميل الصورة حدثان مختلفان.

@ e-oz https://github.com/angular/angular/issues/6005#issuecomment -165951692 يمكنني الوصول إلى حدود الطفل لاكتشاف ما إذا كان يجب أن أبدأ تحميل الصورة.

tandu ويمكنك نقل كل هذا التحقق إلى كود المكون الفرعي (سيكون شرعيًا في ngAfterViewInit للمكون الفرعي) وإرسال الحدث إلى الأصل ، عند تغيير isLoading.

@ e-oz أعرّف المكون على أنه #holder في html: <image-holder #holder></image-holder> . لذلك لا يوجد ملف js لذلك.

لذلك قم بإنشائه ، وإلا فلن تكون هناك حاجة لاستخدام ngAfterViewInit ، إذا كان العرض
لا يحتوي على مكونات حقيقية مثل الأطفال - لن يتم تقديم أي شيء.

يوم الأحد ، 13 مارس 2016 الساعة 15:18 كتب tandu [email protected] :

@ e-oz https://github.com/e-oz أعرّف المكون على أنه #holder في html:

حامل>

. لذلك لا يوجد ملف js لذلك.

-
قم بالرد على هذا البريد الإلكتروني مباشرة أو قم بعرضه على GitHub
https://github.com/angular/angular/issues/6005#issuecomment -195963389.

يمكنني أيضًا استخدام element.getElementsByTagsName أو طرق مشابهة وعدم استخدام ChildComponent. هناك بالتأكيد حلول موجودة. أنا بخير مع setTimeout fix. تكمن المشكلة في أن اسم الطريقة يقترح أنه يمكن استخدامها لتحديد بعض المنطق الذي يريد أن يتم تهيئة المكونات الفرعية وربطها بالمكون ولكن الطريقة لا تخبرنا أنه يتم تشغيلها في منتصف دورة الكشف عن التغيير ولذا لدينا فترة طويلة سلسلة من الشكاوى من مختلف الناس.

tandu أتفق معك تمامًا في هذا ، إنه تقييد مزعج للغاية.

لما يستحق ، لقد غيرت الحل الأصلي الخاص بي إلى ما يلي ، والذي بدأ يشعر وكأنه نهج معقول. ربما هذا يستحق المحاولة لموقفك:

    constructor(private _changeDetectionRef : ChangeDetectorRef) { }

    ngAfterViewInit() : void {
        // your code

        this._changeDetectionRef.detectChanges();
    }

أحصل على نفس الاستثناء عند استخدام التحقق من صحة النموذج (الإدخال المطلوب). ذات صلة بهذه القضية؟

الغطاس: http://plnkr.co/edit/Fp6XT5mC6ZCB14Z1gvTi؟p=preview

eivindr ألقى نظرة سريعة ولم أر ngFormControl على أحد المدخلات من قبل ، ولا أستطيع أن أرى لماذا أو ماذا يعني ذلك لأنه يجب أن يستمر في عنصر النموذج لربطه بمجموعة تحكم وسيكون للإدخال الفردي المقابل ngControl. في أي حال في إزالة الغطاس الخاص بك

 [ngFormControl]="formModel.find('title')" 

ويصلح الخطأ الخاص بك.

أرفض التخلي عن هذه المشكلة :) بالأمس ، تمكنت من إثبات أن مشكلتي كانت مرتبطة على وجه التحديد بربط المضيف الذي يعتمد على خصائص الإدخال :

http://www.bennadel.com/blog/3056-host-bindings-are-breaking-the-ngmodel-bridge-in-angular-2-beta-11.htm

يجب أن أعتقد أن هذا خطأ في هذه المرحلة لأن المكون له شيئين يعتمدان على الإدخال - قالب العرض وارتباطات المضيف - و _ واحد منهم فقط _ يسبب استثناء التغيير. إذا تسبب كلاهما في المشكلة ، فأنا أفكر في شيء آخر ؛ ولكن ، نظرًا لأن واحدًا منهم فقط هو الذي يسبب المشكلة ، فلا بد أنه خطأ ، أليس كذلك؟

eivindr لدي أيضًا نفس المشكلة عند البدء بنموذج فارغ ثم تعيين قيمة عناصر التحكم في النموذج برمجيًا. هل وجدت عمل في الجوار؟

MarkPerryBV لا ، ما زلت أتلقى "تم تغييره بعد التحقق منه" عند

@ user414 إذا قمت بإزالة [ngFormControl] ... فليس هناك "مطلوب" التحقق من صحة الإدخال.

MarkPerryBV لقد وجدت حلاً

لا يؤدي استخدام enableProdMode() إصلاح أي شيء حقًا - إنه يخفي العارض فقط عن طريق منعه من إجراء الفحص المزدوج وإعلامك بأن هناك خطأ ما على الأرجح.

يبدو إصلاح AerisG222 أفضل من استخدام setTimeout . هل هو فعلاً أن السلوك المقصود هو تشغيل اكتشاف التغيير يدويًا بعد استدعاء addControl() باستخدام مدقق؟

نفس المشكلة هنا بعد استدعاء addControl (). أعتقد أن addControl () يجب أن يستدعي ChangeDetectionRef.detectChanges ().

CaptainCodeman وأنا أعلم - لقد كان حلًا مؤقتًا.

لن يفشل هذا بعد الآن في وضع dev عندما أستخدم ng2 @ beta17 ، [email protected] ، zone. [email protected]. لا يزال يتعين علي الاتصال بـ ChangeDetectionRef.detectChanges ()

eivindr هل يمكنك تحديث plnkr الخاص بك لإصلاح beta17؟
أنا أفقد عقلي بشأن هذا ، أرفض الخضوع لـ enableProdMode() .

@ AerisG222 نهجك يعمل بالنسبة لي!

هل استخدام النهج الذي نشر @ AerisG222 منهجًا جيدًا للاستخدام؟ نعم ، إنه يعمل ولكن هل هناك ضمائر لإطلاق changeDetectionRef.detectChanges() يدويًا؟

أواجه نفس المشكلة عند محاولة التحقق من صحة النموذج الديناميكي ثم إعادة تعيين النموذج. هنا غطائي

خطوات التكاثر. إرسال النموذج مع الموظف فحص. بعد تحديث النموذج ، تحقق من الموظف مرة أخرى.

أنا أستخدم changeDetectionRef.detectChanges () في وظيفة الإرسال.

شكرا لهذا @ AerisG222 :)

لا أحب كل ذلك الحل البديل الذي تم تعيينه في مهلة. أقترح ما يلي:

http://plnkr.co/edit/9umnTGsdFWhbaOBeftuZ؟p=preview

استخدام ChangeDetectorRef.detectChanges ليس دائمًا طريقة جيدة. مثال لماذا:

يستدعي المكون الرئيسي واجهة برمجة التطبيقات العامة لمكونات الطفل أثناء ngAfterViewInit . هذه المكالمة تغير ارتباط الطفل. سيؤدي الاتصال بـ detectChanges من أحد الوالدين إلى حل المشكلة أيضًا ، ولكن هذا يعني أنه يجب على الوالد معرفة وقت الاتصال بـ detectChanges بعد استدعاء الطفل لواجهة برمجة التطبيقات. ستلاحظ أن استدعاء detectChanges in childs الذي يغير الارتباط في هذه الحالة لا يعمل عندما تريد استخدام ChangeDetectionStrategy.OnPush .

لقد واجهت هذا الخطأ عند إضافة الأطفال ديناميكيًا عبر ViewContainerRef.createComponent() ثم تحديث النسخة الفرعية. أنا أستخدم RC2 (وأحاول عدم استخدام الأشياء المستهلكة).

في البداية كان الشيء يعمل بشكل جيد (التصيير الأول) ، ولكن بعد ذلك أضفت مكونًا ينبعث منه بيانات جديدة. تم الاستماع إلى هذا الحدث من قبل المكون الأصلي ، والذي قام بتحديث مصفوفة البيانات الخاصة به مما أدى إلى اكتشاف التغيير ومجتمع المكونات الفرعية الديناميكية الجديدة. تم تشغيل الحدث من خلال إرسال نموذج. إذا ضغطت على زر الإرسال ، فكل شيء على ما يرام. إذا قمت بالضغط على Enter لإنشاء الإرسال ، فسيؤدي ذلك إلى ظهور الخطأ.

انتهى بي الأمر بإضافة ChangeDetectorRef.detectChanges() فور إنشاء المكون الديناميكي وتحديثه. ليست مشكلة كبيرة ، ولكن يبدو من الغريب أنه على الرغم من أنني قمت للتو بإضافة مكون جديد إلى العرض ، فإن النظام لا يقوم تلقائيًا بتشغيل اكتشاف التغيير للطفل.

@ aerisg222 هل أحتاج إلى استدعاء this._changeDetectionRef.detectChanges () بعد كل تغيير في خاصية الأطفال من الوالد؟

حسنًا ، لقد واجهت هذه المشكلة للتو. لدي مكونان من الأخوين يستخدمان نفس كائن البيانات. من المفترض أن يكون كلا الكائنين قادرين على تحديث مصدر البيانات. يرى المصدر الآخر في الواقع التغيير في الكائن ولكنه يؤدي إلى تغيير التعبير بعد التحقق منه. القيمة السابقة: "صحيح". القيمة الحالية: "خطأ"

حدث هذا لي بعد الترقية من RC1 إلى RC4

كذلك هنا. بدأت في الحصول على هذا مرة أخرى بعد الترقية من RC1 إلى RC4.

ربما كان من المفترض أن يتم الإبلاغ عن التغيير الذي تسبب في ذلك كتغيير كسر في سجل التغيير ...

نحن بحاجة إلى انتظار النهائي.
توقفت عن استخدام المكونات الفرعية لأن تحديث الخصائص الخارجية سيء.
اعتقدت أن المناطق كانت هنا من أجل ذلك ...

كذلك هنا. يبدو أن تحميل المكون الديناميكي عبر ViewComponentRef يتصرف بشكل مختلف في RC2 و RC4 كما حدث في RC1

فيما يلي تبعيات العمل الخاصة بي:
"التبعيات": {
"@ angular / common": "2.0.0-rc.1"،
"@ angular / compiler": "2.0.0-rc.1"،
"@ angular / core": "2.0.0-rc.1"،
"@ angular / http": "2.0.0-rc.1"،
"@ angular / platform-browser": "2.0.0-rc.1"،
"@ angular / platform-browser-dynamic": "2.0.0-rc.1"،
"systemjs": "0.19.31"،
"core-js": "^ 2.4.0"،
"عكس البيانات الوصفية": "^ 0.1.3"،
"rxjs": "5.0.0-beta.6"،
"zone.js": "^ 0.6.12"
} ،
"devDependencies": {
"typecript": "^ 1.8.10" ،
"الكتابة": "^ 1.0.4" ،
"بشكل متزامن": "^ 2.2.0"،
"lite-server": "^ 2.2.2"
}

وإليكم التبعيات التي تنتج الخطأ المذكور:
"التبعيات": {
"@ الزاوي / المشترك": "2.0.0-rc.4"،
"@ angular / compiler": "2.0.0-rc.4"،
"@ angular / core": "2.0.0-rc.4"،
"@ angular / http": "2.0.0-rc.4"،
"@ angular / platform-browser": "2.0.0-rc.4"،
"@ angular / platform-browser-dynamic": "2.0.0-rc.4"،
"systemjs": "0.19.31"،
"core-js": "^ 2.4.0"،
"عكس البيانات الوصفية": "^ 0.1.3"،
"rxjs": "5.0.0-beta.6"،
"zone.js": "^ 0.6.12"
} ،
"devDependencies": {
"typecript": "^ 1.8.10" ،
"الكتابة": "^ 1.0.4" ،
"بشكل متزامن": "^ 2.2.0"،
"lite-server": "^ 2.2.2"
}

RC2 لا يعمل أيضًا!

مجرد سؤال ولكن هل هناك أي طريقة للحصول على مزيد من المعلومات حول الخطأ؟ على سبيل المثال ، سيكون من الجيد معرفة "التعبير" عندما يقول الخطأ "يتغير التعبير من" صواب "إلى" خطأ "!.

لدي أيضًا نفس المشكلة بالضبط بعد الترقية من RC1 إلى RC4. وما اكتشفته يرجع إلى وظيفة ngOnInit في المكون الخاص بي. إذا قمت بالتعليق على هذه الوظيفة ، فستختفي رسالة الخطأ ويعمل كل شيء بشكل جيد. أي أفكار؟

إغلاق هذه القضية لأنها قديمة وتم اتخاذ الإجراءات. إذا استمرت المشكلة ، فتأكد من إنشاء مشكلة جديدة واملأ نموذج المشكلة بجميع التفاصيل المطلوبة . شكرا

لكن الناس كانوا يقولون إنهم ما زالوا يواجهون هذه المشكلة في اتفاقية جديدة ...

يوم الأربعاء ، 13 تموز (يوليو) 2016 ، الساعة 00:52 ، فيكتور بيرشيت [email protected]
كتب:

مغلق # 6005 https://github.com/angular/angular/issues/6005.

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/angular/angular/issues/6005#event -720794445 ، أو كتم الصوت
الخيط
https://github.com/notifications/unsubscribe/AAgIEFEVZmE0M53XxNpzAYg9hJT_E_viks5qVAyGgaJpZM4G4J_s
.

نعم ، لقد قمت للتو بالترقية إلى RC4 ولم أجري تغييرًا واحدًا في أي مكون بخلاف تكوين جهاز توجيه جديد وواجهت هذه المشكلة. كان كل شيء جيدًا في RC1 ، ويبدو أن هذا لا يزال موجودًا.

مزيد من المعلومات:

اتضح أنه بسبب الاتصال async داخل ngOnInit ، حدث هذا الخطأ. إذا قمت بالتعليق على رمز الاتصال غير المتزامن أو قمت بنقل هذا الجزء من الكود إلى المُنشئ ، فإن كل شيء يعمل بشكل جيد.

@ ammar91
اتصل بهذا بعد التغييرات:
changeDetectionRef.detectChanges ()

@ zigzag95 نعم ، هذا حل بديل بالفعل ولكن من الصعب جدًا القيام بذلك. أتوقع أن يتعامل إطار مثل الزاوي مع هذا بشكل أكثر رشاقة بدلاً من جعلنا نشغل يدويًا آلية اكتشاف التغيير الخاصة به.

في حالتي ، يحدث ذلك عندما أشترك في باعث الحدث الزاوي في app.component.ts لإظهار وإخفاء شريط التقدم. كان كل شيء جيدًا مع RC1 ولكن كسر في RC4.

هنا هو Repro ، http://plnkr.co/edit/jEtfUrQdc4sJBySj5kWN؟p=preview
انقر فوق Heroes Link وحدد أحد الأبطال لتحريره وسترى الخطأ.
يرجى الاطلاع على التغييرات في app.component.ts و hero.service.ts

مرحبًا vicb ، شكرًا على التحديث. هل يمكن أن تخبرنا ما هي الإجراءات التي تم اتخاذها؟ هل تقصد أن مثل هذا سيتم إصلاحه في الإصدار القادم؟

الحل البديل البسيط الآخر الذي نجح معي هو إرجاع القيمة كقيم يمكن ملاحظتها وتأخير الانبعاث بمقدار 10 مللي ثانية. في حالتي ، كان الاستثناء يحدث مع قيمة الدوران
<app-spinner *ngIf="spinner"></app-spinner>

  this.eventService.toggleSpinnerAnnounced$.subscribe(
      (show: boolean) => this.spinner = show
    );

هذا عمل لي:

private spinner = new Subject<boolean>();
toggleSpinnerAnnounced$ = this.spinner.asObservable().delay(10); // This  delay() is important

announceSpinnerToggle(show: boolean) {
        this.spinner.next(show);
    }

لقد نجح هذا الأمر بالنسبة لك لأنك تستخدم التأخير وليس له علاقة بالملاحظة.
سيكون لديك نفس السلوك عند استخدام stettimeout.

Jarvens من فضلك توقف عن نشر هذا التعليق في الأماكن غير المناسبة.

مشكلات GitHub مخصصة لتقارير الأخطاء وطلبات الميزات.
لأسئلة الدعم ، يرجى استخدام قنوات أخرى مثل تلك المدرجة في CONTRIBUTING - هل لديك سؤال أو مشكلة؟

تعليقك لا يوفر معلومات كافية لتشخيص مشكلتك.

لمعلوماتك: لقد تلقيت هذا الخطأ بسبب امتداد الكروم ng-inspector for AngularJS (ملحق الزاوية 1 البديل لـ batarang)

هذا جنون! بعد قراءة الموضوع بالكامل ، كان ما تم إصلاحه في وضع التطوير هو تعطيل ng-inspector لـ AngularJS كما يقول @ KarlGustav-unimicro.

مع ذلك ، فإن ChangeDetectorRef.detectChanges() يعمل أيضًا بالنسبة لي ، لكنني شعرت بأنه متسلل حقًا.

@ pkozlowski- مفتوح المصدر ،
ما زلت لا أعرف لماذا سيتم استدعاء indicatorStyle() عندما يتغير أحد المدخلات ،
هل يمكنك إعطاء المزيد من الشرح؟
إذا قمت بتنفيذ ngDoCheck في مكون شريط التقدم _ بدون تعيين ChangeDetectionStrategy.OnPush في المكون الأصلي ،
اكتشفت أن تنفيذ ngDoCheck مرتين ،
أنا أعرف لماذا سيتم إعدام أول واحد ،
لكنني في حيرة من أمري بشأن ngDoCheck ...

http://plnkr.co/edit/myX2Alx9jie2q0FDIME7؟p=preview

LiTiang ،

ما زلت ليس لدي أي فكرة عن سبب استدعاء indexStyle () عندما يتغير أحد المدخلات ،
هل يمكنك إعطاء المزيد من الشرح؟

نظرًا لأن indicatorStyle() مرتبط بـ [ngStyle] في طريقة العرض ، فسيتم استدعاؤه دائمًا عند تشغيل أداة الكشف عن التغيير. سيحدث هذا بغض النظر عما إذا كانت المدخلات قد تغيرت بالفعل أم لا.

اكتشفت أن تنفيذ ngDoCheck مرتين ،
أنا أعرف لماذا سيتم إعدام أول واحد ،
لكنني في حيرة من أمري حول ngDoCheck الثاني ...

هذا على الأرجح لأنه ، كما ذكرنا سابقًا في هذا الموضوع ، يتم دائمًا تشغيل اكتشاف التغيير مرتين في وضع التطوير. يقوم بذلك للتحقق من أنه ليس لدينا رمز يغير الارتباطات أثناء اكتشاف التغيير ، مما قد يتسبب في حدوث أخطاء صعبة في الإنتاج.

تباين في setTimeout ()

تحديث: ذهبت وحدة المعالجة المركزية بنسبة 100٪ بدون رفيق ارتفاعأخر مقارنة: كانت تحديثات AFAIK تتكرر!

UPDATE2: مثال على Plunker

كنت أرغب في ارتفاع كتلة <ul> الديناميكية للتحكم في ارتفاع <img> التي ارتبطت بـ "companionHeight".

شرير جدا ... لكن الأعمال التالية باستخدام الملاحظة.

هذا هو عنصر <ul> الذي يتم مراقبة ارتفاعه:

<ul class="title-list-ul" #listul (window:resize)="setCompanionHeight(listul)">

هنا يتم التحكم في عنصر <img>:

<img class="title-list-companion-img" [src]="getCompanionImageURL()" [height]="companionHeight"/>

فيما يلي طرق المكونات التي تتفاعل:

import { Component, OnInit, AfterViewChecked, ElementRef } from '@angular/core';  // redacted
import { Observable } from 'rxjs';

@Component({
  selector: 'resume-title-list',
  templateUrl: './title-list.component.html',
  styleUrls: ['./title-list.component.scss']
})
export class TitleListComponent implements OnInit, AfterViewChecked {

  private error: Object;
  private companionHeight: number = 0;
  private companionHeightLast: number = 0;

   // Lots of irrelevant stuff like ngInit redacted for simplicity.

  constructor(private elementRef: ElementRef) { }  // redacted, mine is more complicated.

  setCompanionHeight(listElement: any) {
    let clientRect = listElement.getBoundingClientRect();
    if (clientRect) {
      this.companionHeight = clientRect["height"];
    }
  }

  // window::resize only happens when the window is resized: This is an initialization 
  // function that sets the initial size of the image... Without it the image height is 
  // initially zero and the image is not shown. 
  // The height was not correct in ngAfterViewInit, so I used ngAfterViewChecked instead.

  ngAfterViewChecked() {
    let ularray = this.elementRef.nativeElement.getElementsByClassName("title-list-ul");
    if (ularray && ularray.length > 0) {
        let h = ularray[0].getBoundingClientRect().height;
        if (h && h != this.companionHeightLast) {
          this.companionHeightLast = h;
          Observable
          .of(h)
          .delay(10)
          .subscribe(h => this.companionHeight = h,
                     error => this.error = error);
        }
    }
  }
}

قد لا تتم قراءة التعليقات على القضايا المغلقة من قبل أعضاء فريق Angular.
ماذا عن نشر سؤال في إحدى هذه القنوات المساهمة - هل لديك سؤال أو مشكلة؟ مع Plunker للتكاثر؟

واجهت نفس المشكلة مع:

<div *ngIf="isLoading">
   <app-some-viewchild></app-some-viewchild>
</div>

استخدم [مخفي] بدلاً من ذلك * ngIf حل المشكلة.

التقيت هذه القضية أيضا. أخيرًا ، وجدت أن كائن inition الافتراضي هو نفسه مع كائن ngModle.

تعيين changeDetection: ChangeDetectionStrategy.OnPush في مصمم الديكور @Component إصلاحه لي

elvismercado شكرًا ، يحل

كان لدي مكون فرعي يعتمد على قيمة تم تمريرها بواسطة القالب الأصلي ، مع القالب الفرعي الذي يطرح هذا الاستثناء عندما تتغير القيمة الأصلية. تؤدي إضافة اقتراحك إلى المكون الفرعي إلى عدم تشغيل اكتشاف التغيير حتى يتم دفع القيمة المتغيرة إلى المكون الفرعي ، وتجنب الاكتشاف للتشغيل قبل الأوان على ما أفترض؟

إذا كان لدي إدخال تم التركيز عليه ثم قمت بإزالته من DOM (شرط ngIf) ، فسيحدث الخطأ "تم تغيير التعبير بعد التحقق منه" (فقط إذا كان الإدخال مرتبطًا بمجموعة نموذج).
هنا مكدس مع المشكلة:
https://plnkr.co/edit/dooRvC1gY1WEcaNdshoP؟p=preview
شكرا!

إذن ما الحل هنا؟

سيؤدي تغيير أي قيمة إدخال في ngOnInit إلى تشغيل هذا.

تضمين التغريدة
مجرد التفاف

setTimeout(()=>{
 ///your code here
}, 1);

لدي مجموعة من المكونات الفرعية التي يجب تحميلها مسبقًا عندما يريد المستخدم تعديل كيان موجود.
لقد كنت أعاني من هذه المشكلة لساعات حتى تمكنت من إصلاحها باستخدام drewlio post أعلاه.

إدخال _changeDetectionRef:

    constructor(
        private _changeDetectionRef: ChangeDetectorRef) {
    }

وبعد ذلك مباشرة بعد إجراء التغيير الخاص بك ، تكشف المكالمة عن التغييرات.
هذا فعل الخدعة لي.

    setSizeFromCtrl() {
        console.log("setSizeFromCtrl");
        if (this.sizeFromList && this.tradeProfile && this.tradeProfile.SizeFrom && this.sizeFromCtrl) {
            this.sizeFromCtrl.select(String(this.tradeProfile.SizeFrom));
            this._changeDetectionRef.detectChanges();
            console.log("setSizeFromCtrl DONE");
        }
    }

    setCentreTypeCtrl() {
        console.log("setCentreTypeCtrl");
        if (this.centreTypeList && this.tradeProfile && this.tradeProfile.centreTypeList && this.centreTypeCtrl) {

            for (let i of this.tradeProfile.centreTypeList) {
                this.centreTypeCtrl.select(i.value);
            }
            this._changeDetectionRef.detectChanges();
            console.log("centreTypeCtrl DONE");
        }
    }


لاحظ أن لدي نفس المشكلة ولكن سبب مختلف (مشابه؟) وحلول مختلفة.

  • يحتوي تطبيق Angular الخاص بنا - https://github.com/GeoscienceAustralia/GNSS-Site-Manager على نماذج تفاعلية نموذجية متداخلة ومبنية عبر مكونات متعددة في ngOnInit() . تم تصغير بعض هذه النماذج باستخدام ngIf في القالب
  • تتم قراءة البيانات أيضًا ngOnInit() وتم تطبيقها باستخدام theModelForm.patchValue(data)
  • ظهر هذا الخطأ عند توسيع أحد النماذج المطوية. يتعلق الأمر بحقيقة أن DOM لم يتم إنشاؤه لأن النموذج تم إنشاؤه في ngOnInit() الذي لم يتم إطلاقه حتى تم توسيعه. أخرج patchValue() واختفت المشكلة
  • توصلنا إلى حلين
  • قبل patchValue() بتشغيل this._changeDetectionRef.detectChanges(); . وقم بتغيير ngIf إلى [hidden] حتى يتم بناء النموذج و DOM بالكامل. الجانب السلبي لهذا هو الوقت وتكلفة الذاكرة حيث تم إنشاء النموذج الكامل و DOM ذي الصلة (قد لا تكون هذه مشكلة في العديد من التطبيقات ولكنها كانت بالنسبة لنا لأن لدينا نموذجًا عملاقًا).
  • الحل الأفضل هو تطبيق patchValue() (أو setValue() إذا كانت البيانات والحقول 1: 1) في المكونات ، وبالتالي يحدث فقط عند إنشاء النموذج في ngOnInit() .

لم أقم بتنفيذ هذه التغييرات بعد (22/3/17).

لذلك لا أعتقد أن هذا القرار سينقذ الجميع.
ولكن في نظري ، كان حدوث الخطأ المحدد مصحوبًا بإنشاء عنصر جديد للفئة. ثم إضافته إلى المصفوفة ، والتي يتم إخراجها عبر * ngFor.
لقد قمت بحل هذه المشكلة عن طريق إضافة مُنشئ إلى صفي ، والذي يملأ الحقول المطلوبة لعرض القيم الافتراضية في القالب (الأصفار ، الأسطر الفارغة)

export class Task {
    task_id: number;
....
    constructor() {
        this.task_name = '';
        this.task_desc = '';
        this.task_percent = 0;
  addNewTask():void{
    let newTask = new Task();
    this.tasksList.push(newTask);
  }

task_name & task_desc & task_percent أعرضها في القالب. إذا لم تتم تهيئة حقل واحد على الأقل من الحقول المدرجة في المُنشئ ، فسأحصل على خطأ مشابه.

+1

عمل حل AerisG222

constructor(private _changeDetectionRef : ChangeDetectorRef) { }

ngAfterViewInit() : void {
    // your code

    this._changeDetectionRef.detectChanges();
}

يعمل this._changeDetectionRef.detectChanges () ، ولكنه سيتسبب في مشكلات أخرى في حالتي. أنا فقط أقوم بلف الكود داخل وظيفة setTimeout () ، فهو يحلها.

فعل GuofuHuang لذلك هو وسيلة لتجنب المشكلة وعدم لاكتشاف التغيير

Toxicable آسف ، ربما لم أوضح ذلك ، أنا لا أستخدم this._changeDetectionRef.detectChanges () ؛ بدلاً من ذلك ، أقوم بلف شفرة المصدر الخاصة بي داخل setTimeout ().

GuofuHuang إذا كان كل ما تضعه داخل setTimeout يتسبب في حدوث قرص مضغوط وتقوم بتشغيله على خطاف دورة الحياة ، فمن المحتمل أنك تتسبب في دورات لا نهائية للقرص المضغوط. الحل هو عدم إجراء التغييرات التي تسبب القرص المضغوط أثناء تشغيل القرص المضغوط

Toxicable حتى أنا

GuofuHuang إذا كان الضبط على 0 يتسبب في وجود قرص مضغوط ثم نعم

Toxicable لقد وجدت هذا الرابط ، http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0- في بعض الأحيان- مفيد ، إنه يقول أن setTimeout من 0 شيء مثل الإيقاف المؤقت / العائد في C ، لا أفعل لا أعرف ما إذا كان سيتسبب في أي قرص مضغوط ، لكنه الآن يعمل بشكل مثالي في بلدي. إذا لم يكن هذا الحل ، فهل لديك حل أفضل لحل هذه المشكلة؟

GuofuHuang لا أعرف ما الذي

Settimeout هو الحل
لست بحاجة إلى تحديد معلمة ms وسأنتظر علامة واحدة

@ zigzag95GuofuHuang نرى هذا المثال لماذا setTimeout ليس هو الحل
https://plnkr.co/edit/dv8K9EvVQLG59Gxsl3oI؟p=preview

Toxicable شكرًا ، لكن حالتي مختلفة تمامًا عن هذه ، ولا أرى أي حلقة لا نهائية. لكن هذا بالتأكيد مثال جيد يساعدني على فهم الزاوي أكثر.

GuofuHuang في الواقع لن يحدث هذا في حالتك لأنك تفعل ذلك في ngAfterViewInit وهو ما يُستدعى مرة واحدة فقط. كانت وجهة نظري أنه من الممكن إحداث حلقة لا نهائية بهذه الطريقة ، وبالتالي من الخطر استخدامها. هذا ما يظهره Plunkr.

moutono حيلك ساعدتني! شكرا جزيلا 😄

نظرًا لأن المشكلة تتعلق ببدء اكتشاف التغيير ، فقد ينجح حل الوعد أيضًا لأن تصحيحات قرد ngZone تعد بالوعود أيضًا. لقد عمل هذا من أجلي:

ngAfterViewInit() {
  Promise.resolve().then(() => your_code_here);
}

نعم ، يعمل setTimeout ، لكن لم يعجبني هذا الإصلاح ، في حالتي كان السبب في ذلك لأنني كنت أقوم بتغيير القيمة في EventEmitter
كان الحل هو التغيير
private generalSubscriber: EventEmitter<any> = new EventEmitter<any>();
إلى
private generalSubscriber: EventEmitter<any> = new EventEmitter<any>(true);

الحق غريب؟
حسنًا ، هذا يعني أن صانع الأحداث غير متزامن
https://angular.io/docs/ts/latest/api/core/index/EventEmitter-class.html

هل هناك أي حل لهذا؟ لماذا تم إغلاقه؟

لا بد لي من مسح ذاكرة التخزين المؤقت في كل مرة

في حالتي ، كنت أستبدل كعب الصورة عند تحميل الصورة ، واضطررت إلى وضعه في setTimeout

intergleam @ wasa4587 @ caroso1222tandu @ AerisG222 @ لفت-مورrobwormald @ svi3c @ pkozlowski-مفتوحة المصدرpcroczoechistefankorubennadelbryanforbesNecroskillzdrewlioElsewhereGameszoechi @ user414 @ ه أوقية

تواجه الخطأ أثناء التطوير. على خادم الإنتاج يعمل بشكل جيد.

smartHasmukh إنه
لا يزال يتعين عليك إصلاحه.

إذا حدث هذا الخطأ ، فمن المرجح أن تقوم بقطع تدفق بيانات اتجاه واحد. والذي يمكن أن يكون شيئًا مثل تغيير بيانات مكون واحد في الأخ ، أو تغيير بيانات الوالدين في خطافات دورة حياة الأطفال ، ربما شيء آخر.
هذا الاستثناء الذي تم طرحه ليس خطأً ، ولكن مساعد المطور لفهم أن عقد تدفق بيانات اتجاه واحد معطل بطريقة ما. حقيقة أن هذا يعمل في الإنتاج هو عن طريق الصدفة ، يجب عليك مراجعة كيفية تغيير بياناتك في التواصل بين الوالدين والأطفال ، وإصلاحه في وضع التطوير.

smartHasmukh اعتدت أن أجد هذا غير مريح أيضًا. على سبيل المثال ، أقوم بربط أحداث الملاحة وأرسل حدثًا إضافيًا إلى المكون الرئيسي لإظهار أداة التحميل. وفي كل مكون ، أخفي هذا المُحمل ، بعد أن أتلقى البيانات من الخادم (لذلك ، ضمن اشتراك). هذا جيد. ولكن ، في أحد المكونات ، لم أحصل إلا على بعض البيانات من مصدر "ثابت" ، لا يمكن ملاحظته هناك ، لذلك حاولت ببساطة استخدام ngOnInit لإخبار المكون الرئيسي بإخفاء أداة التحميل. ثم حصلت على الخطأ بالطبع.

على الرغم من أن حالتي يجب أن تكون شيئًا بسيطًا ، إلا أنها ليست الطريقة الصحيحة للقيام بذلك. اضطررت إلى اتخاذ قرار بعدم إظهار المحمل في المقام الأول ، لهذا المكون (والذي قد يصبح أكثر صعوبة إذا كان لدي المزيد من المكونات من هذا القبيل) ... أو التعامل أيضًا مع إخفاء المحمل من خدمة البيانات الخاصة بي ، بدلاً من مستوى المكون. أو قد يكون الإصلاح القبيح هو التفاف تلك الحالة المحددة في setTimeout (). لأن النهج الأولي لم يكن هو النهج الصحيح.

TL / DR:
أنا متأكد من أنه يجب أن تكون هناك طريقة مناسبة للسيناريو الخاص بك أيضًا ، بخلاف _setTimeout () _ الإصلاح القبيح (الذي اخترته للأسف في تلك اللحظة ، ولكن مرة أخرى ، إنه سيناريو بسيط للغاية وأعرف ما هو يجري هناك - ومع ذلك ، قد أضطر إلى تغييره في وقت ما ، في إصدار مستقبلي).
يمكنك تجربة StackOverflow لحالتك المحددة ، وإعطاء مزيد من التفاصيل. يجب أن يكون هناك طريقة.

بالتأكيد شكرا @ MrCrofttytskyi وسأفعل ذلك السيد zoechi وأنا أعلم أنه ليس من المفاجئ. لكني علمت للتو. لا شيء آخر

تضمين التغريدة

حقيقة أن هذا يعمل في الإنتاج هو عن طريق الصدفة ، يجب عليك المراجعة

لا ، في معظم الحالات ، يكون إجابتي على هذا الخطأ "نعم ، أعرف ، وهي مقصودة". تقوم الكثير من المكونات في تطبيقاتي بتحميل شيء ما بعد البدء وبعد تلقي قيم جديدة في المتغيرات المرتبطة. هذه القضية هي مجرد "قبح معروف" من Angular ولا أحد يهتم.

@ e-oz إذا كنت تؤثر بطريقة ما على الوالد أو الأشقاء في أي من خطافات دورة الحياة ، فهذا يعني كسر تدفق بيانات اتجاه واحد. يجب إجراء مثل هذه التغييرات عندما تكون حالة التطبيق مستقرة ، ولكن ليس في منتصف اكتشاف التغيير. هذا هو السبب في وجود تلك الحيل مع microtask و setTimeout 0 وما إلى ذلك.

tytskyi اهدأ

@ e-oz كيف يتعلق ذلك بطلب HTTP. تؤدي استجابة طلب HTTP إلى اكتشاف التغيير ولن تحصل على الخطأ "تم تغيير التعبير ...".
هل يمكنك تقديم المزيد من المعلومات من فضلك؟

zoechi لا يوجد سبب لإضاعة الوقت في ذلك ، لن يغير أحد شيئًا ، تم إغلاق المهمة.

@ e-oz تم إغلاق المشكلة قبل عام وكان لفريق Angular أولويات مختلفة تمامًا في ذلك الوقت (الحصول على إصدار) ولم تكن هذه المشكلة مانعًا في ذلك الوقت.
إذا كنت تعتقد أن لديك حالة صالحة ، يجب عليك إنشاء عدد جديد.

zoechi لا أعتقد أنك ستقرر ما يجب أن أفعله. يمكنني إنشاء عدد جديد ، لكن لست مضطرًا لذلك. كل الاحترام ، أنا لا أحب تلك النغمة "يجب عليك".

@ e-oz أرى أن تعليقاتك هي فقط للتنفيس عن إحباطك ولست مهتمًا بالحصول على حل. من فضلك توقف عن إضاعة وقت الشعوب الأخرى هنا بتعليقاتك غير المجدية.

إذا كنت تتصل بـ http ، فقم بالاشتراك في المكون الخاص بك ، فقط أضف ..
Promise.resolve().then(() => your_code_here);
أو
myObservable.delay(10).subscribe(...)

أحد الحلين سيحل مشكلتك

vicb إيقاف إغلاق المشكلات التي لم يتم إصلاحها. لماذا تفعل هذا ؟

على الأقل اقترح بعض الإصلاحات بشكل صحيح ، لكن إغلاق هذا أمر غير مقبول

diegogarciaa ... وما الذي لم يتم إصلاحه أو الخطأ من وجهة نظرك؟ المحادثة ^ ^ ^ طويلة جدًا بحيث يصعب العثور على جوهرها الفعلي.

@ mlc-mlapis مع كل الاحترام الواجب ، أنا لست معلمك ، إذا كنت لا تستطيع قراءة أو فهم المشكلة ، توقف عن الإزعاج. قضيت دقائق طويلة في قراءة كل المحتوى ، أوصي بنفس الشيء.

يبدو أن موقف الفريق الزاوي (ليس كل الفريق ، ولكنهم هنا يغلقون هذه المشكلة) مقدام للغاية: عدم منع (راتبي) ، وعدم إصلاحه في أي وقت قريب.

تضمين التغريدة استمر كما هو مذكور أعلاه وسيرحب بك في كل مكان.

@ mlc-mlapis لا أريد أن أكون موضع ترحيب حيث لا يستطيع الناس القراءة ومحاولة الهراء حيث لا ينبغي.

diegogarciaa ... لقد اعتقدت للتو أن لديك مشكلة شخصيًا ويبدو أنها ليست صحيحة الآن. والحقيقة أيضًا أن معظم المشاكل مع Expression has changed after it was checked ... ليست أخطاء ولكنها ليست مجرد فهم صحيح لكيفية عمل القرص المضغوط.

@ mlc-mlapis طيب ... دعنا نفهم

http://plnkr.co/edit/nm8OkrpZCIp4cvA6TbpO؟p=preview

في هذا المخطط ، يمكنني أن أفهم أن المتغير كان مرتبطًا وفحصه عندما تم استدعاء ngAfterViewInit ، لذلك عندما يتلقى قيمة جديدة ، ولا يقوم بتشغيل جولة فحص جديدة ، يتم طرح الاستثناءات

لكن على سبيل المثال ، إذا كان لدي مرجع حاوية عرض ... وأستخدم على سبيل المثال:

this.service.GetData (). اشتراك (
استجابة => this.component.instance.dataModel = استجابة
) ؛

ضع في اعتبارك أن dataModel يتم استخدامه كـ {{dataModel.Field}} في html الخاص بي

this.component هو عنصر ديناميكي يتم تحميله في أحداث معينة ، كيف يمكن للمرء تجنب الخطأ؟ والتي ستكون الطريقة الصحيحة لتمرير البيانات إلى المكون الخاص بي قبل خطافات مركبة الحياة الخاصة باكتشاف التغيير

diegogarciaa ... نعم ، هذا مثال نموذجي حيث يتم خلط عملية المزامنة غير المتزامنة وتلتقي معًا في قرص مضغوط واحد وتأكيدها في وضع dev. لن أكرر الشرح من المنشور https://hackernoon.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4 ، لذا ربما حاول قراءته أولاً.

وانظر أيضًا إلى https://hackernoon.com/here-is-how-to-get-viewcontainerref-before-viewchild-query-is-evaluated-f649e51315fb.

لذلك تقول المقالة بشكل أساسي أنه يجب علي استدعاء جولة للكشف عن التغيير يدويًا ...

لنكن صادقين ، أنا مستاء جدًا من الوضع الحالي ... حتى الأشياء البسيطة في الزاوية مملة ومتعبة جدًا ... لا أستطيع حتى التنفس. فوك لك

diegogarciaa ... لا ، إنه مجرد حل إضافي. يمكنك أيضًا استخدام promise.then أو استخدام setTimeout ... لكن الحل الموصى به في هذه الحالة هو على الأرجح خدمة مشتركة ، لذا لن تقوم بتحديث خاصية المكون الديناميكي مباشرة عبر دورة القرص المضغوط ودوراته التأكيد.

أو قم فقط بإنشاء مثيل للمكون الديناميكي في اللحظة التي سيكون لديك فيها البيانات. لذلك سوف يستدعي اشتراكك إنشاء مثيل المكون الديناميكي.

ولكن ما هو مهم -> المنطق الأساسي لحدوث الخطأ -> لأن التغييرات أحادية الاتجاه يجب أن تتدفق دائمًا من أعلى إلى أسفل عبر الشجرة بأكملها وبعد دورة قرص مضغوط واحدة ، هناك تأكيد للحالة التي تم احترام مبدأ أحادية الاتجاه.

هذا "اللعنة عليك" لم يكن شخصيًا ... فقط تنفيس عني.

نستخدم مخططًا توجيهيًا للتعامل مع مكوناتنا. لقد أنشأنا مساعدًا يقوم بتحميل أحد المكونات في مرجع عرض المكون ، وكما نفهم ، يجب أن تكون البيانات متاحة عند تحميل أحد المكونات

protected loadPartialView(viewName: string, target: ViewContainerRef) : ComponentRef<any> {
        const factories = Array.from(this.resolver['_factories'].keys());
        const factoryClass = <Type<any>>factories.find((x: any) => x.name === viewName);
        const factory = this.resolver.resolveComponentFactory(factoryClass);
        return target.createComponent(factory);
}

في المثال أعلاه: أود أن أفعل شيئًا كالتالي:

return target.createComponent(factory, dataSource);

حيث سيكون مصدر البيانات الخاص بي متاحًا في وقت المُنشئ

مثل redux ، الذي يستخدم كائنًا للتعامل مع مصدر البيانات الذي يمر عبر المكونات ، فإننا نفكر في تنفيذ مكون قابل للحقن يتعامل مع البيانات من أجلنا ، حتى نتمكن من الحصول عليها قبل خطافات مركبة الحياة.

ديغوغارسيا

لا أعتقد أن البيانات يجب أن تكون متاحة من قبل ... لا يزال المكون الديناميكي مكونًا مع @Input() و @Output() ولكن السؤال هو متى ستغير البيانات.

... يجب أن تكون البيانات متاحة عند تحميل أحد المكونات ...

أفترض أنك بحاجة أيضًا إلى استخدام مكونات من وحدات محملة كسولًا ، لذلك أستخدم خريطة مباشرة في وحدة نمطية لإمكانية الوصول إلى المكونات باستخدام أسماء سلاسل فقط.

export default class LazyLoadedModule {
    cmps: Map<{}, {}> = new Map();
    constructor() {
        this.cmps.set('first-component', FirstComponent);
        ...
    }
}

ماذا يعني return target.createComponent(factory, dataSource); ؟ لأن API الفعلي هو createComponent(componentFactory, index, injector, projectableNodes, ngModule) .

وربما تكون وحدة @ angular / cdk الجديدة ممتعة بالنسبة لك. فقط مقدمة هنا: https://medium.com/@caroso1222/a -first-look-in-the-angular-cdk-67e68807ed9b.

لما يستحقه وما إذا كان يمكن أن يساعد أي شخص ، فبدلاً من استخدام setTimeout وبما أن استخدام ChangeDetectorRef.detectChanges() لم ينجح بالنسبة لي ، انتهى بي الأمر باستخدام NgZone.onStable وتنفيذ الكود الخاص بي من خلال الاشتراك مرة واحدة على EventEmitter ...

constructor(
  private zone: NgZone,
) { }

ngAfterViewInit() {
  this.zone.onStable.first().subscribe(() => {
    // your code here
  });
}

لست مدركًا تمامًا لعواقب القيام بذلك ولكن هل يمكن أن يكون أسوأ من استخدام setTimeout ؟ إذا كان لدى أي شخص أي تعليق على هذا الأمر ، فسيكون موضع ترحيب حقًا!

@ حل

constructor(private _changeDetectionRef : ChangeDetectorRef) { }

ngAfterViewChecked() : void {
    // your code
    this._changeDetectionRef.detectChanges();
}

هذا هو مكون html:

{{lastData.note [i] .date | التاريخ: 'dd.MM.yyy'}} | {{lastData.note [i] .date | التاريخ: "HH: mm"}}:# BFL15_200817 | {{lastData.status.name}} بواسطة {{lastData.note [i] .admin}}

حصلت على الخطأ إذا كانت البيانات في المصفوفة أكثر من واحد ، أي حل؟

هذه بالتأكيد مشكلة معقدة ، ولكن في بعض الحالات (خاصة عندما تقوم بتعديل الخصائص على ContentChild) يمكن حلها عن طريق نقل المنطق إلى ngAfterContentInit () بدلاً من ngAfterViewInit () أو ngOnInit ()

إنه لأمر مدهش كيف يمكن للأشياء البسيطة أن تسبب الكثير من الارتباك في الزاوية

لا تقلق ، فقد لاحظ الجميع أيضًا 😕
image

jakeNiemiec وظيفة عرجاء ، ترول ، لم يعد أحد يبحث عن Angularjs بعد الآن
https://trends.google.com/trends/explore؟date=all&q=Angular٪20tutorial ، React٪ 20tutorial
image

نعم ، أتوقع أن المزيد من الناس سيحتاجون إلى "البرنامج التعليمي الزاوي" في Google بدافع اليأس ، ومن هنا جاء التعليق الأولي على "الارتباك".

ولكن لا تقلق ، يمكننا التحقق من npm للحصول على إحصائيات الاستخدام الدقيقة: http://www.npmtrends.com/react-vs-@angular/cli -vs-vue-vs- @ angular / core
image
image

فقط قارن كمية القضايا. أرغب حقًا في رؤية الزاوية تتحسن ، لكنني أظن أن Vue.js ستمررها في المستقبل البعيد. بعد أن تمت برمجتها في جميع الأجهزة الثلاثة ، أوصي بشدة باستخدام Vue للتطوير الزاوي. إنه مثل الزاوي بدون النموذج المعياري.

موافق الإجابة مقبولة ، أنا بخير تمامًا مع تلك الإحصائيات.
أتخيل أن هناك المزيد من الأشخاص الذين يستخدمون PHP في الهند مثل Java في العالم بأسره. قد يكون المرء أحمقًا لاستخدام PHP لتطبيق مؤسسي واسع النطاق ، لذلك يجب أن تستخدم عقلك أحيانًا ، وستكون الحياة أفضل

jakeNiemiec ... تم وضع 50٪ من المشكلات التي يتم إنشاؤها عن طريق الخطأ هناك ... إنها قضايا دعم / معرفة في الواقع ويجب ألا تكون موجودة على الإطلاق. الممتع هو أن معظم الموضوعات المطلوبة موثقة جيدًا في المستندات الرسمية + الإجابات تستند إلى معرفة JavaScript. لكن كما تعلم ، لا يقرأ الناس المستندات بعمق كافٍ.

يمكن أن يكون HostBinding مصدرًا محيرًا لهذا الخطأ.

ضع في اعتبارك ربطًا بسيطًا لأحد المكونات ، مثل @HostBinding('style.background') .

يتم فحص هذه الخاصية عن طريق اكتشاف تغيير المكون * الأصل * كما لو كانت "مملوكة" لها. من وجهة نظرنا ، نريد أن نفكر فيه على أنه العنصر الفرعي "امتلاك" تلك الخاصية.

لذا يبدو أنه يجب أن تكون هناك طريقة لاستبعاد المكون لخصائص التحقق في هذه الحالة؟ أم أن الأمر أكثر تعقيدًا من ذلك؟

اضطررت إلى تشغيل المكون الرئيسي detectChanges (أو إضافة div إضافي في الطفل) لتجنب الخطأ في الحالة التي كان فيها المكون الفرعي يغير ببساطة لون الخلفية الخاص به (ولا يفعل ذلك في أي مكان آخر) .

وصف أكثر اكتمالاً: https://stackoverflow.com/questions/43375532/expressionchangedafterithasbeencheckederror-explained/51662105#51662105

ما عليك سوى القيام بشيء ما ، أي شيء ، يؤدي إلى جولة أخرى من اكتشاف التغيير خلال تلك الطريقة - قم بإصدار حدث ، أو أي شيء آخر. يعد تغليفها في مهلة (قائمة الانتظار للارتجاع إلى ng1 :-P) إحدى الطرق التي ستنجح ، لكنها تشعر بالفوضى الفائقة بالنسبة لي في ng2.

في الزاوية 4 ، هذا يعمل 4 لي <3

تم قفل هذه المشكلة تلقائيًا بسبب عدم النشاط.
يرجى تقديم مشكلة جديدة إذا كنت تواجه مشكلة مشابهة أو ذات صلة.

اقرأ المزيد عن سياسة قفل المحادثة التلقائي .

_تم تنفيذ هذا الإجراء تلقائيًا بواسطة روبوت.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات