AngularJS'de ng-tekrar kapsamı ile direktif izole kapsamı


95

İzole kapsamı olan bir yönergem var (böylece yönergeyi başka yerlerde yeniden kullanabilirim) ve bu yönergeyi bir ile ng-repeatkullandığımda çalışmıyor.

Bu konudaki tüm belgeleri ve Stack Overflow yanıtlarını okudum ve sorunları anladım. Her zamanki sorunlardan kaçtığıma inanıyorum.

Dolayısıyla, ng-repeatdirektif tarafından oluşturulan kapsam nedeniyle kodumun başarısız olduğunu anlıyorum . Benim direktifim bir izolat kapsamı yaratıyor ve üst kapsamdaki bir nesneye iki yönlü veri bağlama yapıyor. Yönergem bu bağlı değişkene yeni bir nesne-değeri atayacak ve yönergem olmadan kullanıldığında ng-repeat(ana değişken doğru şekilde güncellenir) bu mükemmel çalışır . Bununla birlikte, ile ng-repeatatama, ng-repeatkapsamda yeni bir değişken oluşturur ve ana değişken değişikliği görmez. Bütün bunlar okuduklarıma dayanarak beklendiği gibi.

Ayrıca, belirli bir öğe üzerinde birden çok yönerge olduğunda, yalnızca bir kapsamın oluşturulduğunu okudum. Ve prioritydirektiflerin uygulanma sırasını tanımlamak için her bir direktifte a ayarlanabilir; yönergeler önceliğe göre sıralanır ve sonra derleme işlevleri çağrılır ( http://docs.angularjs.org/guide/directive adresinde öncelik kelimesini arayın ).

Bu nedenle, yönergemin ilk önce çalıştığından ve sonunda bir izolat kapsamı oluşturduğundan emin olmak için önceliği kullanabileceğimi umuyordum ve ng-repeatçalıştırıldığında, ana kapsamdan prototip olarak miras alan bir kapsam oluşturmak yerine yalıtım kapsamını yeniden kullanır. ng-repeatBelgelerine durumları öncelik düzeyinde olduğu direktif ishal olduğunu 1000. Daha 1yüksek bir öncelik seviyesi mi yoksa daha düşük bir öncelik seviyesi mi olduğu net değildir . 1Direktifimde öncelik seviyesini kullandığımda bir fark yaratmadı, bu yüzden denedim 2000. Ancak bu işleri daha da kötüleştiriyor: iki yönlü bağlamalarım oluyor undefinedve yönergem hiçbir şey göstermiyor.

Sorunumu göstermek için bir keman oluşturdum . Yönergemdeki priorityayarı yorumladım . İsim nesnelerinin bir listesi ve isim nesnesindeki ad name-rowve soyad alanlarını gösteren bir yönergem var. Görüntülenen bir ada tıklandığında, selectedana kapsamda bir değişken ayarlamasını istiyorum . İsim dizisi, selecteddeğişken name-rowiki yönlü veri bağlama kullanılarak yönergeye aktarılır .

Ana kapsamdaki işlevleri çağırarak bunu nasıl çalıştıracağımı biliyorum. Ayrıca selectedbaşka bir nesnenin içindeyse ve dış nesneye bağlanırsam, her şeyin işe yarayacağını da biliyorum . Ancak şu anda bu çözümlerle ilgilenmiyorum.

Bunun yerine, sahip olduğum sorular:

  • ng-repeatÜst kapsamdan prototip olarak miras alan bir kapsam oluşturmayı nasıl engelleyebilirim ve bunun yerine yönergemin izolat kapsamını kullanmasını nasıl sağlayabilirim?
  • 2000Direktifimdeki öncelik seviyesi neden çalışmıyor?
  • Batarang kullanarak, ne tür bir kapsamın kullanımda olduğunu bilmek mümkün mü?

1
Normalde, yönergeniz diğer yönergelerle aynı öğe üzerinde kullanılacaksa, bir yalıtım kapsamı kullanmak istemezsiniz. Kendi kapsam özelliklerinizi yarattığınız ve ng-tekrar ile çalışmanız gerektiğinden scope: true, direktifiniz için kullanmanızı öneririm . Ayrıca bakınız (henüz yapmadıysanız) stackoverflow.com/questions/14914213/… Ayrıca, bir direktifin birden fazla yerde kullanılması otomatik olarak bir izolat kapsamı kullanmamız gerektiği anlamına gelmez.
Mark Rajcok

Cevaplarınızın çoğunu okudum (mükemmelin ötesinde, yazdığınız için teşekkürler), ama sorularınızı okumak hiç aklıma gelmedi :-). Neye bağlandığını okudum. Bana öyle geliyor ki, isolate-kapsam yönergeleri diğer yönergelerle karıştırılamaz. Bu tür direktiflerin bileşenler olduğu ve bu nedenle diğer direktiflerle karıştırılmaları gerekmediği düşüncesine katılıyorum. Benim için (şimdiye kadar) tek istisna olurdu ng-repeat. Bağımsız yönergeleri karıştırabilmenin değerli olduğunu düşünüyorum ng-repeat. Devam edecek ...
Deepak Nulu

Yukarıdan devam ediyor ... Öyleyse, bir öğe için kapsamı olan tek bir yönerge olması gerekiyorsa, o ng-repeatzaman bir kapsamı olmamalıdır. ng-repeatTipik kullanım durumu için bir kapsamın olması mantıklıdır, bu yüzden değiştirilmesini önermiyorum. Bunun yerine, Alex Osborn'un cevabında yorumladığım gibi ng-repeat, kendi kapsamını oluşturmayan buna dayalı bir tekrar yönergesi oluşturacağımı düşünüyorum . Bu, daha sonra kendi izolat kapsamlarına sahip tekrarlanan yönergeler için kullanılabilir. Devam edecek ...
Deepak Nulu

Bir yönergeyi yineleyen kodun artık kullanılıp kullanılmayacağını ng-repeatveya özel kapsamsız yineleme yönergesini bilmesi gerekir . "Arayanın" bunu bilmesinin sorun olmadığını düşünüyorum, ancak bir "aranan" ın (tekrarlanan direktif) tekrar edilip edilmediğini bilmesi uygun değildir. Devam edecek ...
Deepak Nulu

Burada açıklamalarla biraz deli alınıyor ... :-) ngRepeat gerekir kendi kapsamını oluşturmak. Neden burada izole bir kapsama ihtiyacınız olduğunu düşünüyorsunuz?
Josh David Miller

Yanıtlar:


203

Tamam, yukarıdaki birçok yorum sayesinde, kafa karışıklığını keşfettim. İlk olarak, birkaç açıklama noktası:

  • ngRepeat, seçtiğiniz izolat kapsamını etkilemez
  • senin yönerge niteliklerini kullanılmak üzere ngRepeat geçirilen parametreleri do bir prototip-miras kapsamı kullanın
  • Yönergenizin çalışmama nedeninin izolat kapsamı ile ilgisi yoktur

Aşağıda, aynı kodun, ancak yönergenin kaldırıldığı bir örnek verilmiştir:

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

İşte çalışmayacağını gösteren bir JSFiddle . Direktifinizdekiyle aynı sonuçları alırsınız.

Neden çalışmıyor? Çünkü AngularJS'deki kapsamlar prototip kalıtımı kullanır. selectedÜst kapsamınızdaki değer ilkeldir . JavaScript'te bu, bir çocuk aynı değeri ayarladığında bunun üzerine yazılacağı anlamına gelir. AngularJS kapsamlarında altın bir kural vardır: model değerleri her zaman içlerinde bir a sahip olmalıdır .. Yani, asla ilkel olmamalıdırlar. Daha fazla bilgi için bu SO cevabına bakın .


İşte kapsamların başlangıçta neye benzediğinin bir resmi.

görüntü açıklamasını buraya girin

İlk öğeye tıkladıktan sonra, kapsamlar artık şöyle görünür:

görüntü açıklamasını buraya girin

selectedNgRepeat kapsamında yeni bir özelliğin oluşturulduğuna dikkat edin. Denetleyici kapsamı 003 değiştirilmedi.

İkinci öğeye tıkladığımızda ne olacağını muhtemelen tahmin edebilirsiniz:

görüntü açıklamasını buraya girin


Yani sorununuz aslında hiç ngRepeat'ten kaynaklanmıyor - AngularJS'de altın bir kuralı ihlal etmekten kaynaklanıyor. Düzeltmenin yolu basitçe bir nesne özelliği kullanmaktır:

$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>

İşte bunun da işe yaradığını gösteren ikinci bir JSFiddle .

Kapsamlar başlangıçta şöyle görünür:

görüntü açıklamasını buraya girin

İlk öğeye tıkladıktan sonra:

görüntü açıklamasını buraya girin

Burada, denetleyici kapsamı istenildiği gibi etkilenir.

Ayrıca, bunun bir izolat kapsamı ile direktifinizle hala çalışacağını kanıtlamak için (çünkü bunun sizin sorununuzla hiçbir ilgisi yoktur), işte bunun için de bir JSFiddle , görünümün nesneyi yansıtması gerekir. Gerekli tek değişikliğin ilkel yerine bir nesne kullanmak olduğunu fark edeceksiniz .

Başlangıçta kapsamlar:

görüntü açıklamasını buraya girin

İlk öğeye tıkladıktan sonra kapsamlar:

görüntü açıklamasını buraya girin

Sonuç olarak: Bir kez daha, sorununuz izolat kapsamı ile değil ve ngRepeat'in nasıl çalıştığı ile ilgili değil. Senin sorunun, tam da bu soruna yol açtığı bilinen bir kuralı çiğniyor olman. AngularJS'deki modeller her zaman bir ..


İzolat kapsamları ve 2 yönlü veri bağlama ile direktiflerle yaptığım deneyler, .altın kuralın yalnızca prototip kalıtıma sahip kapsamlar için gerekli olduğuna inanmamı sağladı. İzolat kapsamları ile ilgilendiğiniz değişkenler scope: {}direktifte tanımlanır ve bu nedenle bu değişkenler izolat kapsamında baştan var olur. Ayrıca, izolat kapsamı prototip olarak üst kapsamdan devralmadığı için üst değişkenleri maskelemezler. yani, maskelenecek "ana" kapsam yoktur.
Deepak Nulu

1
Ayrıca olmalı ki: sizin yönergesi çocuk kapsamını oluşturmak değil, ancak kolayca olabilir kullanılan bir bağlamda gerektiren bir çocuk kapsamını. ngRepeat bir durumdur. Aşma da öyle. Güven bana - ..
Josh David Miller

1
AngularJS Google Grubu'nda @JoshDavidMiller'ın nihayet kafa karışıklığımı çözebildiği tartışma !
Deepak Nulu

2
Tüm bu harika diyagramları nereden alıyorsunuz? Bunları yayınlayan başka bir kullanıcı da gördüm.
Asad Saeeduddin

3
@Asad, aracı yakın zamanda GitHub'a koydum, adı Peri $ kapsamı .
Mark Rajcok

6

Doğrudan sorularınızı cevaplamaktan kaçınmaya çalışmadan, bunun yerine şu kemana bir göz atın:

http://jsfiddle.net/dVPLM/

Kilit nokta, Angular'ın geleneksel davranışıyla savaşmaya ve onu değiştirmeye çalışmak yerine, yönergenizi ng-repeatgeçersiz kılmaya çalışmak yerine üzerinde çalışacak şekilde yapılandırabilmenizdir .

Şablonunuzda:

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

Direktifinizde:

    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>'

Sorularınıza yanıt olarak:

  • ng-repeat bir kapsam yaratacaksa, bunu gerçekten değiştirmeye çalışmamalısınız.
  • Yönergelerde öncelik sadece yürütme sırası değildir - bakınız: AngularJS: HTML derleyicisi derleme sırasını nasıl düzenler?
  • Batarang'da performans sekmesine bakarsanız her kapsam için bağlı ifadeleri görebilir ve bunun beklentilerinize uygun olup olmadığını kontrol edebilirsiniz.

Bu kadar çabuk cevap verdiğiniz için teşekkür ederim. Yapmaya çalıştığım şey tahılın tersine giderse, biraz üzülürüm (AngularJS yine de harika bir çerçeve). Bir direktifin yeniden kullanılabilir bir bileşen olması amaçlanmıştır. Yazılırken yazarın bir ile kullanılıp kullanılmayacağı konusunda endişelenmemesi gerekir ng-repeat. Belki ilk yazıldığında asla kullanılmaz ng-repeat. Ve gelecekte bir zaman, alışabilir ng-repeatve bu noktada, yeniden yazmadan çalışması gerekir. Umarım AngularJS'in gelecekteki bir sürümü bunu mümkün kılar.
Deepak Nulu

Yukarıdaki yorumuma açıklık getirmek istiyorum. Birlikte kullanılıp kullanılmayacağı konusunda endişelenmeyen bir yönerge yazmanın mümkün olduğunu düşünüyorum ng-repeat. Ama öyle görünüyor ki, direktifin kendi kapsamındaki iki yönlü bir bağlamayı değiştirebilmek yerine, ana kapsamdaki değişkenleri değiştirebilmesi için direktife bir fonksiyon geçirmem gerekiyor. İki yönlü ciltleme ve yeniden kullanılabilir direktifler, AngularJS ile ilgili en sevdiğim iki şey ve merhemdeki ng-repeatbir sinek olduğunu kanıtlıyor. Belki ng-repeatkendi kapsamını oluşturmayan bir eşdeğer yazabilirim .
Deepak Nulu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.