[Çeviri] Angular’da, Decorator Aracılığı İle Router Verisine Ulaşmak.
Bu makale Georgii Kuzmin tarafından yazılan “Router’s data with the decorator in Angular” makalesinin Türkçe çevirisidir. Makaleyi orijinal dilinde okumak için aşağıdaki linki tıklayabilirsiniz.
Başlıyoruz….
Componentlere çözümlenmiş verileri hemen dahil edin.
Bir Angular geliştiricisi olarak, Router’da verileri component yüklenmeden çözümlemek isterim. Bu durum, veriler yüklenirken ekranın yanıp sönmesi veya iskelet yüklemesi olmaksızın, component’i daha kararlı yapmaktadır. Kullanıcılar sayfa yüklendiğinde sayfa ile veriyi aynı anda görmek ister. İşte bu yüzden Angular ekibi Router Resolver’ı icat ettiler.
☹️ Problem.
Mevcutta Routerdan gelen verilere ulaşmak için ActivatedRoute veya ActivatedRouteSnapshot inject etmek zorundayım.
Dahası, Eğer URL de dinamik değişen Id’ler mevcut ise Angular, Route Component’i tekrardan yüklemiyor. Angular dinamik değişen url’leri önceki route aynı olduğunu düşünüyor (library/1 = library/2). Çünkü Angular kaputun altında routerları karşılaştırırken, basit object referans karşılaştırması kullanıyor. Angular’a bu işlemi bir işaret yada RouteReuseStrategy sınıfı derleme yaklaşımı ile yeniden yapmamasını söyleyebilirsiniz.
Yani, dinamik olarak değişen bir route’niz varsa ve dinamik kısım değiştikçe yeni veriyi çözümlemek için ActivatedRoute kullanmak ve veri alanlarına ulaşmak için subscribe olmalısınız.
Frontend Meetup’larında konuşmacılara, componentin içinde garip injectionlar ve subscriptler olmadan verilere ulaşmak için bir çözüm bulup bulmadıklarını sıklıkla sorarım. Görünen o ki kimse bu konu hakkında düşünmemiş bile. Angular Ekibi, Veriyi çözümlemek için Input gibi bir decorator de sunmuyor.
İhtiyacım olan veriyi çözümlemek için ActivatedRoute inject edip, ona subscribe olmak ve pipe işlemleri yapmak istemiyorum.
Bunun yerine şöyle bir şey istiyorum:
😎 Çözüm.
Buradaki fikir; Router Context içerisinden mevcut route bulmak, router outlet’i almak, ve component’in içinde ona subscribe olmak, bir getter yardımı ile en güncel verileri subscription’dan döneceğiz. Ancak Decorator kullanılan component destroy olmayacak bu yüzden Router outlet’te yapılan subscription işlemini canlı tutamayacağız. Bu yüzden Angular her seferinde componenti tekrar derlediğinden, Bizim decorator, doğru olan veriyi dönmek yerine ilk router outletteki veriyi dönecektir.
Bazı fonksiyonlar yazalım!
Öncelikle; Decoratorler henüz Angular ortamlarında olmadığı için Angular DI Container’ına erişmemizi sağlayacak, inject edilebilen bir statik değişkene (bir önceki yazımda bahsetmiştim. )ihtiyacımız var. Ancak, bunlara ait servis ve inject edilebilir özelliklerini kullanmak zorundayız. Mevcutta hangi route’in aktif olduğunu anlama için en az bir tane Router’a ve Router’daki verileri çözülerken, Component’teki değişiklikleri tespit etmek için ChangeDetectorRef ihtiyacımız var.
Aşağıda görebileceğiniz gibi, StaticInjectorService’mizi modül’ün içinde sunuyoruz (8. satır). Bu işlem servisin Instance’nı oluşturmak ve servisin Constructor’ını calıştırmak için yapılmıştır.
Şimdi Decorator’ümüzü geliştirmek için her şeye sahibiz!
Bir kaç değişken tanımlayalım ve neden bu değişkenleri ihtiyacımız var satır satır anlamaya çalışalım
Bir önceki makalemde; Typescripte decorator’lerin nasıl calıştığını açıklamıştım. Herkesin bu konuyu bildiğini düşünüp, bu kısmı geçelim.
İhtiyaçlarımız:
— Route’mizi bulmak için bir adet router (7. satır).
— Subject tipindeki trigger
(8. satır) bize subscription’ı tekrardan çalışması ve router verilerini dönmek için yardımcı olacak tanımlandı . Nasıl uygulanacağını ilerde göreceğiz.
— Destroy subject(9. satır) ise trigger
‘in yaptığı işin tam tersini yapacak. Component’in işi bittiğinde(destroy) unsubscribe işlemi yapacak.
— Router, route context’indeki değişikleri tutar. Bu yüzden any
tipine cast etmeliyiz ve İhtiyacımız olan hilemizi yapabilelim(10. satır).
— Router verilerini tekrar kullanmak için routerData
değişkenini tanımlıyoruz(15. satır).
— ChangeDetectorRef’i ilerde kullanmak için tanımlanıyoruz(16. satır).
— Boolean inited
değişken ise component oluşturulduğunda false işaretlemek için tanımlandı(16. satır). Dosyada bunu değişinin kullanımını göreceğiz.
— Component’in referansını tutmak ve değişiklikleri yakalayıp, fonksiyonumuza bağlamak için
Bildiğiniz gibi Subject tipinde trigger
değişkenini tanımlamıştık. Amacı, Decorator’ün kullanıdığı değişkenden bir değer alındığında; Boş(EMPTY) bir emisyon yayarak Component’in yaratılışı hakkında bilgi vermektir. Bu sayede component’in ne zaman yaratığını biliyoruz ve router’in instancesini alarak sihrimizi gerçekleştirip değerimizi alabileceğiz.
Basit bir fonksiyon ile contextMapt
’en o an aktif olan outlet bilgisini arıyoruz (4. satır).
Daha sonra outlet’ten component’in referansını alıyoruz ve ihtiyacımız olan verilerle sırayla bir router arıyoruz(13. satır).
Component’imize bağılı olan bir değişik takip(change detector) referansı almalıyız(2. satır). Data sonra onDestroy
metodunu register edelim. Bu kısımda inated
değişkeni false set edip boş bir değer yayarak, router verisinden unsubscribe oluyoruz(11. satır). En son olarak verinin içinden name || key bilgisini dönüyoruz.
Subscribe callback fonksiyonunda, aradığımız çöüzmlenmiş verileri alıyoruz ve Hedef sınıftaki değişken bilgisine atıyoruz. Sonrasında component’i markForCheck kullanarak dirty olarak işaretliyoruz.
Decorator’ümüz, kullanıldığı alan için getter ve setter’i içeren bir tanımlayıcı döner.
Getter’in içersinde inited
değişkenini true olarak değiştiriyoruz. Eğer bu değişken false ise, trigger
değişkenini bilgilendirmek için boş bir değer emit edecek. Sonrasında orijinal getter çalıştırarak routerdaki verileri dönüyoruz.
Decorator’e ait tüm kod şu şekilde.
Basitçe aşağıdaki şekilde kullanın,
Data değişkeni için Router’daki bilgi şu şekilde.
Angular ekibi neden buna benzer bir çözüm sunmuyor bilmiyorum. Benim bakış acıma göre, bu yöntem daha açıklayıcı ve sürekli olarak subscription’ları yönetmeye göre, kullanımı daha kolay. Bu decorator yönetiminin bazı sorunlara neden olabileceği durumlar olduğuna da inanıyorum.
Tüm koda, repository’imden ulaşabilirsiniz.
Kullanımına da buradan bakabilirsiniz.
Alena Rotaru ✈ and Ivan Radchenko’ye teşekküler.