AJAX ve Snippet'ler
İşlevselliğin genellikle sunucu ve tarayıcı arasında yayıldığı modern web uygulamaları çağında, AJAX önemli bir bağlantı unsurudur. Nette Framework bu alanda hangi seçenekleri sunuyor?
- Şablonun snippet olarak adlandırılan parçalarını gönderme
- PHP ve JavaScript arasında değişken aktarımı
- AJAX isteklerinde hata ayıklama araçları
AJAX İsteği
Bir AJAX isteği temelde klasik bir HTTP isteğinden farklı değildir. Bir sunucu belirli parametrelerle çağrılır. İsteğe nasıl yanıt verileceği sunucuya bağlıdır – JSON biçiminde veri döndürebilir, HTML kodunun bir bölümünü, bir XML belgesini vb. gönderebilir.
Tarayıcı tarafında, fetch()
işlevini kullanarak bir AJAX isteği başlatıyoruz:
fetch(url, {
headers: {'X-Requested-With': 'XMLHttpRequest'},
})
.then(response => response.json())
.then(payload => {
// yanıtın işlenmesi
});
Sunucu tarafında, bir AJAX isteği, HTTP isteğini kapsülleyen hizmetin
$httpRequest->isAjax()
yöntemi tarafından tanınır. Bu yöntem X-Requested-With
HTTP
başlığını kullanır, bu yüzden bunu göndermek çok önemlidir. Sunucu içinde $this->isAjax()
yöntemini
kullanabilirsiniz.
Verileri JSON biçiminde göndermek istiyorsanız sendJson()
yöntemi. Yöntem
ayrıca sunum yapan kişinin etkinliğini de sonlandırır.
public function actionExport(): void
{
$this->sendJson($this->model->getData);
}
AJAX için tasarlanmış özel bir şablonla yanıt vermeyi planlıyorsanız, bunu aşağıdaki şekilde yapabilirsiniz:
public function handleClick($param): void
{
if ($this->isAjax()) {
$this->template->setFile('path/to/ajax.latte');
}
//...
}
Parçacıklar
Sunucuyu istemciye bağlamak için Nette tarafından sunulan en güçlü araç snippet'lerdir. Bunlarla, sıradan bir uygulamayı minimum çaba ve birkaç satır kodla bir AJAX uygulamasına dönüştürebilirsiniz. Fifteen örneği tüm bunların nasıl çalıştığını göstermektedir ve kodu GitHub'da bulunabilir.
Parçacıklar veya kırpmalar, tüm sayfayı yeniden yüklemek yerine sayfanın yalnızca bazı bölümlerini güncellemenize olanak tanır. Bu daha hızlı ve daha verimlidir ve ayrıca daha rahat bir kullanıcı deneyimi sağlar. Snippet'ler size Ruby on Rails için Hotwire veya Symfony UX Turbo'yu hatırlatabilir. İlginç bir şekilde, Nette snippet'leri 14 yıl önce tanıtmıştı.
Parçacıklar nasıl çalışır? Sayfa ilk yüklendiğinde (AJAX olmayan bir istek), tüm snippet'ler dahil olmak üzere sayfanın tamamı yüklenir. Kullanıcı sayfayla etkileşime girdiğinde (örneğin, bir düğmeye tıkladığında, bir form gönderdiğinde vb.), sayfanın tamamını yüklemek yerine bir AJAX isteği yapılır. Sunucudaki kod eylemi gerçekleştirir ve hangi parçacıkların güncellenmesi gerektiğine karar verir. Nette bu parçacıkları işler ve bir JSON dizisi şeklinde gönderir. Tarayıcıdaki işleme kodu daha sonra alınan parçacıkları sayfaya geri ekler. Bu nedenle, yalnızca değiştirilen parçacıkların kodu aktarılır, bant genişliğinden tasarruf edilir ve tüm sayfa içeriğinin aktarılmasına kıyasla yükleme hızlandırılır.
Naja
Tarayıcı tarafında snippet'leri işlemek için Naja kütüphanesi kullanılır. Bunu bir node.js paketi olarak yükleyin (Webpack, Rollup, Vite, Parcel ve diğerleri gibi uygulamalarla kullanmak için):
npm install naja
… veya doğrudan sayfa şablonuna ekleyin:
<script src="https://unpkg.com/naja@2/dist/Naja.min.js"></script>
Öncelikle kütüphaneyi başlatmanız gerekir:
naja.initialize();
Sıradan bir bağlantıyı (sinyal) veya form gönderimini AJAX isteği haline getirmek için ilgili bağlantıyı, formu veya
düğmeyi ajax
sınıfıyla işaretlemeniz yeterlidir:
<a n:href="go!" class="ajax">Go</a>
<form n:name="form" class="ajax">
<input n:name="submit">
</form>
or
<form n:name="form">
<input n:name="submit" class="ajax">
</form>
Parçacıkları Yeniden Çizme
Control sınıfının her nesnesi (Presenter'ın kendisi de dahil
olmak üzere) yeniden çizilmesini gerektirecek değişikliklerin olup olmadığının kaydını tutar. Bu amaç için
redrawControl()
yöntemi kullanılır.
public function handleLogin(string $user): void
{
// giriş yaptıktan sonra ilgili kısmı yeniden çizmek gerekir
$this->redrawControl();
//...
}
Nette ayrıca nelerin yeniden çizilmesi gerektiğinin daha iyi kontrol edilmesini sağlar. Yukarıda bahsedilen yöntem, snippet adını bir argüman olarak alabilir. Böylece, şablon parçası düzeyinde geçersiz kılmak (yani yeniden çizmeye zorlamak) mümkündür. Bileşenin tamamı geçersiz kılınırsa, her parçacığı da yeniden çizilir:
// 'header' parçacığını geçersiz kılar
$this->redrawControl('header');
Latte'de Parçacıklar
Latte'de snippet'leri kullanmak son derece kolaydır. Şablonun bir bölümünü snippet olarak tanımlamak için, onu
{snippet}
ve {/snippet}
etiketlerine sarmanız yeterlidir:
{snippet header}
<h1>Hello ... </h1>
{/snippet}
Kod parçacığı bir öğe oluşturur <div>
HTML sayfasında özel olarak oluşturulmuş bir
id
. Bir snippet yeniden çizilirken, bu öğenin içeriği güncellenir. Bu nedenle, sayfa ilk kez render
edildiğinde, başlangıçta boş olsalar bile tüm snippet'ler de render edilmelidir.
dışında bir öğe ile de bir snippet oluşturabilirsiniz <div>
bir n:özniteliği kullanarak:
<article n:snippet="header" class="foo bar">
<h1>Hello ... </h1>
</article>
Snippet Alanları
Snippet adları ifadeler de olabilir:
{foreach $items as $id => $item}
<li n:snippet="item-{$id}">{$item}</li>
{/foreach}
Bu şekilde, item-0
, item-1
, vb. gibi birkaç snippet elde edeceğiz. Dinamik bir snippet'i
(örneğin, item-1
) doğrudan geçersiz kılacak olursak, hiçbir şey yeniden çizilmeyecektir. Bunun nedeni,
snippet'lerin gerçek alıntılar olarak işlev görmesi ve yalnızca kendilerinin doğrudan render edilmesidir. Ancak, şablonda
teknik olarak item-1
adında bir snippet yoktur. Yalnızca snippet'in çevresindeki kod, bu durumda foreach
döngüsü çalıştırıldığında ortaya çıkar. Bu nedenle, şablonun çalıştırılması gereken kısmını
{snippetArea}
etiketiyle işaretleyeceğiz:
<ul n:snippetArea="itemsContainer">
{foreach $items as $id => $item}
<li n:snippet="item-{$id}">{$item}</li>
{/foreach}
</ul>
Ve hem bireysel parçacığı hem de tüm alanı yeniden çizeceğiz:
$this->redrawControl('itemsContainer');
$this->redrawControl('item-1');
Ayrıca $items
dizisinin yalnızca yeniden çizilmesi gereken öğeleri içerdiğinden emin olmak da
önemlidir.
Parçacıkları olan {include}
etiketini kullanarak ana şablona başka bir şablon eklerken, dahil edilen
şablonu tekrar bir snippetArea
içine sarmak ve hem parçacığı hem de alanı birlikte geçersiz kılmak
gerekir:
{snippetArea include}
{include 'included.latte'}
{/snippetArea}
{* dahil.latte *}
{snippet item}
...
{/snippet}
$this->redrawControl('include');
$this->redrawControl('item');
Bileşenlerdeki Snippet'ler
Bileşenler içinde parçacıklar oluşturabilirsiniz ve Nette
bunları otomatik olarak yeniden çizer. Bununla birlikte, belirli bir sınırlama vardır: parçacıkları yeniden çizmek için,
herhangi bir parametre olmadan render()
yöntemini çağırır. Bu nedenle, şablonda parametre geçmek işe
yaramayacaktır:
OK
{control productGrid}
will not work:
{control productGrid $arg, $arg}
{control productGrid:paginator}
Kullanıcı Verilerinin Gönderilmesi
Parçacıkların yanı sıra, istemciye herhangi bir ek veri gönderebilirsiniz. Bunları payload
nesnesine
yazmanız yeterlidir:
public function actionDelete(int $id): void
{
//...
if ($this->isAjax()) {
$this->payload->message = 'Success';
}
}
Parametreleri Gönderme
AJAX isteği aracılığıyla bileşene parametreler gönderdiğimizde, ister sinyal parametreleri ister kalıcı parametreler
olsun, bileşenin adını da içeren global adlarını sağlamalıyız. Parametrenin tam adı getParameterId()
yöntemini döndürür.
let url = new URL({link //foo!});
url.searchParams.set({$control->getParameterId('bar')}, bar);
fetch(url, {
headers: {'X-Requested-With': 'XMLHttpRequest'},
})
Bileşende ilgili parametreleri içeren bir tutamaç yöntemi:
public function handleFoo(int $bar): void
{
}