التوجيه نطاق عزل مع نطاق نوغ تكرار في AngularJS




angularjs-directive angularjs-scope (2)

بدون محاولة مباشرة لتجنب الإجابة على أسئلتك ، بدلاً من ذلك ، ألقِ نظرة على ما يلي:

http://jsfiddle.net/dVPLM/

النقطة الأساسية هي أنه بدلاً من محاولة محاربة السلوك التقليدي للزاوية وتغييره ، يمكنك بناء توجيهك للعمل مع ng-repeat بدلاً من محاولة تجاوزه.

في القالب الخاص بك:

    <name-row 
        in-names-list="names"
        io-selected="selected">
    </name-row>

في التوجيه الخاص بك:

    template:
'        <ul>' +      
'            <li ng-repeat="name in inNamesList" ng-class="activeClass($index)" >' +
'                <a ng-click="setSelected($index)">' +
'                    {{$index}} - {{name.first}} {{name.last}}' +
'                </a>' +
'            </li>' +
'        </ul>'

ردا على أسئلتك:

  • سيعمل ng-repeat على إنشاء نطاق ، فأنت لا تحاول تغيير هذا.
  • الأولوية في التوجيهات ليست مجرد أمر تنفيذ - راجع: AngularJS: كيف يقوم مترجم HTML بترتيب ترتيب التحويل؟
  • في Batarang ، إذا قمت بالتحقق من علامة تبويب الأداء ، فيمكنك رؤية التعبيرات المرتبطة بكل نطاق ، وتحقق مما إذا كان هذا يطابق توقعاتك.

لدي توجيه مع نطاق عزل (حتى أتمكن من إعادة استخدام التوجيه في أماكن أخرى) ، وعندما أستخدم هذا التوجيه مع ng-repeat ، فإنه يفشل في العمل.

لقد قرأت كل الوثائق و إجابات Stack Overflow حول هذا الموضوع وفهمت المشاكل. أعتقد أنني قد تجنبت كل المحتالين المعتاد.

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

قرأت أيضًا أنه عند وجود توجيهات متعددة على عنصر معين ، يتم إنشاء نطاق واحد فقط. ويمكن وضع priority في كل توجيه لتحديد الترتيب الذي يتم فيه تطبيق التوجيهات ؛ يتم فرز التوجيهات حسب الأولوية ثم يتم استدعاء وظائف الترجمة الخاصة بهم (البحث عن كلمة الأولوية في http://docs.angularjs.org/guide/directive ).

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

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

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

بدلا من ذلك ، فإن الأسئلة التي لدي هي:

  • كيف يمكنني منع ng-repeat من إنشاء نطاق برمجيًا يرث من النطاق الرئيسي ، وبدلاً من ذلك يستخدمه نطاق العزل لعنصر Directive؟
  • لماذا لا يعمل مستوى الأولوية 2000 في التوجيه الخاص بي؟
  • باستخدام Batarang ، هل من الممكن معرفة نوع النطاق قيد الاستخدام؟

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

  • لا يؤثر ngRepeat على نطاق العزل الذي اخترته
  • تستخدم المعلمات التي تم تمريرها إلى ngRepeat للاستخدام على سمات التوجيه الخاص بك نطاقًا موروثًا بشكل أولي
  • السبب الذي لا يعمل التوجيه الخاص بك له علاقة مع نطاق العزل

في ما يلي مثال على الشفرة نفسها ولكن مع إزالة التوجيه:

<li ng-repeat="name in names"
    ng-class="{ active: $index == selected }"
    ng-click="selected = $index">
    {{$index}}: {{name.first}} {{name.last}}
</li>

هنا هو JSFiddle مما يدل على أنه لن ينجح. تحصل على نفس النتائج بالضبط كما في التوجيه الخاص بك.

لماذا لا يعمل؟ لأن النطاقات في AngularJS تستخدم الميراث النموذجي. القيمة selected في نطاقك الأصلي هي بدائية . في JavaScript ، هذا يعني أنه سيتم الكتابة فوقه عندما يقوم الطفل بتعيين نفس القيمة. توجد قاعدة ذهبية في نطاقات AngularJS: يجب أن تحتوي قيم النموذج دائمًا على . فيهم. بمعنى ، لا ينبغي أبدا أن تكون الأوليات. انظر هذا الجواب SO لمزيد من المعلومات.

في ما يلي صورة لما تبدو عليه النطاقات في البداية.

بعد النقر على العنصر الأول ، تبدو النطاقات الآن كالتالي:

لاحظ أنه تم إنشاء خاصية جديدة محددة على نطاق ngRepeat. لم يتم تغيير نطاق وحدة تحكم 003.

ربما يمكنك تخمين ما يحدث عندما نضغط على العنصر الثاني:

لذلك فإن سبب المشكلة ليس ناتجًا عن ngRepeat على الإطلاق - إنه ناتج عن كسر قاعدة ذهبية في AngularJS. طريقة لإصلاحها هي ببساطة استخدام خاصية كائن:

$scope.state = { selected: undefined };
<li ng-repeat="name in names"
    ng-class="{ active: $index == state.selected }"
    ng-click="state.selected = $index">
    {{$index}}: {{name.first}} {{name.last}}
</li>

هنا هو JSFiddle الثانية التي تبين هذا يعمل أيضا.

إليك الشكل الذي تبدو عليه النطاقات في البداية:

بعد النقر على العنصر الأول:

هنا ، يتأثر نطاق وحدة التحكم ، حسب الرغبة.

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

النطاقات في البداية:

النطاقات بعد النقر على العنصر الأول:

في الختام: مرة أخرى ، لم تكن مشكلتك متعلقة بنطاق العزلة ولا تتعلق بكيفية عمل ngRepeat. مشكلتك هي أنك تخالف قاعدة معروفة تؤدي إلى هذه المشكلة ذاتها. النماذج في AngularJS يجب أن يكون دائما . .





angularjs-ng-repeat