19 KiB
Bankacılık Uygulaması Yapımı Bölüm 3: Veri Alma ve Kullanma Yöntemleri
Ders Öncesi Test
Giriş
Her web uygulamasının temelinde veri bulunur. Veri birçok biçimde olabilir, ancak temel amacı her zaman kullanıcıya bilgi sunmaktır. Web uygulamaları giderek daha etkileşimli ve karmaşık hale geldikçe, kullanıcının bilgiye erişimi ve bu bilgiyle etkileşimi web geliştirme sürecinin önemli bir parçası haline gelmiştir.
Bu derste, bir sunucudan verileri asenkron olarak nasıl alacağımızı ve bu verileri HTML'yi yeniden yüklemeden bir web sayfasında nasıl göstereceğimizi göreceğiz.
Ön Koşul
Bu ders için web uygulamasının Giriş ve Kayıt Formu bölümünü oluşturmuş olmanız gerekiyor. Ayrıca Node.js kurmanız ve sunucu API'sini yerel olarak çalıştırmanız gerekiyor, böylece hesap verilerine erişebilirsiniz.
Sunucunun düzgün çalıştığını test etmek için bir terminalde şu komutu çalıştırabilirsiniz:
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
AJAX ve veri alma
Geleneksel web siteleri, kullanıcı bir bağlantı seçtiğinde veya bir form aracılığıyla veri gönderdiğinde, tam HTML sayfasını yeniden yükleyerek görüntülenen içeriği günceller. Yeni veriler her yüklendiğinde, web sunucusu tarayıcı tarafından işlenmesi gereken tamamen yeni bir HTML sayfası döndürür. Bu işlem, mevcut kullanıcı eylemini kesintiye uğratır ve yeniden yükleme sırasında etkileşimleri sınırlar. Bu iş akışı Çok Sayfalı Uygulama veya MPA olarak adlandırılır.
Web uygulamaları daha karmaşık ve etkileşimli hale gelmeye başladığında, AJAX (Asynchronous JavaScript and XML) adı verilen yeni bir teknik ortaya çıktı. Bu teknik, JavaScript kullanarak verileri bir sunucudan asenkron olarak göndermeye ve almaya olanak tanır, HTML sayfasını yeniden yüklemeye gerek kalmadan daha hızlı güncellemeler ve daha akıcı kullanıcı etkileşimleri sağlar. Sunucudan yeni veriler alındığında, mevcut HTML sayfası JavaScript kullanılarak DOM API'si ile güncellenebilir. Zamanla bu yaklaşım, günümüzde Tek Sayfalı Uygulama veya SPA olarak adlandırılan bir yapıya evrilmiştir.
AJAX ilk tanıtıldığında, verileri asenkron olarak almak için mevcut olan tek API XMLHttpRequest
idi. Ancak modern tarayıcılar artık JSON verilerini manipüle etmek için daha uygun ve güçlü olan, sözler (promises) kullanan Fetch
API'yi de destekliyor.
Tüm modern tarayıcılar
Fetch API
'yi desteklerken, web uygulamanızın eski veya eski tarayıcılarda çalışmasını istiyorsanız, öncelikle caniuse.com'daki uyumluluk tablosunu kontrol etmek her zaman iyi bir fikirdir.
Görev
Önceki derste bir hesap oluşturmak için kayıt formunu uygulamıştık. Şimdi mevcut bir hesapla giriş yapmayı ve verilerini almayı sağlayacak kodu ekleyeceğiz. app.js
dosyasını açın ve yeni bir login
fonksiyonu ekleyin:
async function login() {
const loginForm = document.getElementById('loginForm')
const user = loginForm.user.value;
}
Burada getElementById()
ile form öğesini alarak başlıyoruz ve ardından loginForm.user.value
ile giriş formundaki kullanıcı adını alıyoruz. Her form kontrolü, HTML'de name
özelliği ile ayarlanmış adıyla formun bir özelliği olarak erişilebilir.
Kayıt işlemi için yaptığımız gibi, hesap verilerini almak için bir sunucu isteği gerçekleştiren başka bir fonksiyon oluşturacağız:
async function getAccount(user) {
try {
const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user));
return await response.json();
} catch (error) {
return { error: error.message || 'Unknown error' };
}
}
Verileri sunucudan asenkron olarak almak için fetch
API'sini kullanıyoruz, ancak bu sefer yalnızca veri sorguladığımız için URL dışında başka bir parametreye ihtiyacımız yok. Varsayılan olarak, fetch
bir GET
HTTP isteği oluşturur, ki bu burada aradığımız şeydir.
✅ encodeURIComponent()
URL için özel karakterleri kaçış karakterine dönüştüren bir fonksiyondur. Bu fonksiyonu çağırmaz ve doğrudan user
değerini URL'de kullanırsak ne tür sorunlarla karşılaşabiliriz?
Şimdi login
fonksiyonumuzu getAccount
fonksiyonunu kullanacak şekilde güncelleyelim:
async function login() {
const loginForm = document.getElementById('loginForm')
const user = loginForm.user.value;
const data = await getAccount(user);
if (data.error) {
return console.log('loginError', data.error);
}
account = data;
navigate('/dashboard');
}
Öncelikle, getAccount
asenkron bir fonksiyon olduğu için sunucu sonucunu beklemek için await
anahtar kelimesini kullanmamız gerekiyor. Herhangi bir sunucu isteğinde olduğu gibi, hata durumlarıyla da başa çıkmamız gerekiyor. Şimdilik yalnızca bir hata mesajı göstermek için bir log mesajı ekleyeceğiz ve daha sonra buna geri döneceğiz.
Daha sonra verileri bir yere kaydetmemiz gerekiyor, böylece daha sonra gösterge paneli bilgilerini göstermek için kullanabiliriz. account
değişkeni henüz mevcut olmadığından, dosyamızın en üstünde bir global değişken oluşturacağız:
let account = null;
Kullanıcı verileri bir değişkene kaydedildikten sonra, giriş sayfasından gösterge paneline navigate()
fonksiyonunu kullanarak geçiş yapabiliriz.
Son olarak, giriş formu gönderildiğinde login
fonksiyonumuzu çağırmamız gerekiyor. HTML'yi şu şekilde değiştirerek bunu yapabiliriz:
<form id="loginForm" action="javascript:login()">
Her şeyin düzgün çalıştığını test etmek için yeni bir hesap oluşturun ve aynı hesapla giriş yapmayı deneyin.
Bir sonraki bölüme geçmeden önce, register
fonksiyonunu şu kodu ekleyerek tamamlayabiliriz:
account = result;
navigate('/dashboard');
✅ Varsayılan olarak, yalnızca görüntülediğiniz web sayfasıyla aynı alan adı ve porttan sunucu API'lerini çağırabilirsiniz. Bu, tarayıcılar tarafından uygulanan bir güvenlik mekanizmasıdır. Ama bekleyin, web uygulamamız localhost:3000
üzerinde çalışırken sunucu API'si localhost:5000
üzerinde çalışıyor, neden çalışıyor? Cross-Origin Resource Sharing (CORS) adı verilen bir teknik kullanılarak, sunucu yanıtına özel başlıklar eklenirse belirli alan adları için istisnalar tanımlanabilir.
API'ler hakkında daha fazla bilgi edinmek için bu dersi alın.
HTML'yi veri göstermek için güncelleme
Artık kullanıcı verilerine sahibiz, mevcut HTML'yi bu verileri göstermek için güncellememiz gerekiyor. Örneğin, bir öğeyi DOM'dan almak için document.getElementById()
kullanmayı zaten biliyoruz. Bir temel öğeye sahip olduktan sonra, onu değiştirmek veya alt öğeler eklemek için kullanabileceğiniz bazı API'ler şunlardır:
-
textContent
özelliğini kullanarak bir öğenin metnini değiştirebilirsiniz. Bu değeri değiştirmek, öğenin tüm alt öğelerini (varsa) kaldırır ve sağlanan metinle değiştirir. Bu nedenle, bir öğenin tüm alt öğelerini kaldırmak için boş bir dize''
atamak da etkili bir yöntemdir. -
document.createElement()
veappend()
yöntemlerini kullanarak bir veya daha fazla yeni alt öğe oluşturabilir ve ekleyebilirsiniz.
✅ Bir öğenin HTML içeriğini değiştirmek için innerHTML
özelliğini kullanmak da mümkündür, ancak bu özellik cross-site scripting (XSS) saldırılarına karşı savunmasız olduğu için kaçınılmalıdır.
Görev
Gösterge paneli ekranına geçmeden önce, giriş sayfasında yapmamız gereken bir şey daha var. Şu anda, var olmayan bir kullanıcı adıyla giriş yapmaya çalışırsanız, konsolda bir mesaj gösteriliyor ancak normal bir kullanıcı için hiçbir şey değişmiyor ve ne olduğunu anlamıyorsunuz.
Giriş <button>
öğesinin hemen öncesine bir hata mesajı gösterebileceğimiz bir yer tutucu öğe ekleyelim:
...
<div id="loginError"></div>
<button>Login</button>
...
Bu <div>
öğesi boş, yani ekrana hiçbir şey gösterilmeyecek. Ancak JavaScript ile içerik eklediğimizde görünür hale gelecek. Ayrıca id
özelliği ekleyerek JavaScript ile kolayca erişilebilir hale getiriyoruz.
app.js
dosyasına geri dönün ve yeni bir yardımcı fonksiyon updateElement
oluşturun:
function updateElement(id, text) {
const element = document.getElementById(id);
element.textContent = text;
}
Bu fonksiyon oldukça basit: bir öğe id ve metin verildiğinde, DOM'daki eşleşen id
öğesinin metin içeriğini günceller. Bu yöntemi login
fonksiyonundaki önceki hata mesajı yerine kullanalım:
if (data.error) {
return updateElement('loginError', data.error);
}
Şimdi geçersiz bir hesapla giriş yapmaya çalışırsanız, şöyle bir şey görmelisiniz:
Artık görsel olarak bir hata metni gösteriliyor, ancak bir ekran okuyucu ile denediğinizde hiçbir şeyin duyurulmadığını fark edeceksiniz. Bir sayfaya dinamik olarak eklenen metnin ekran okuyucular tarafından duyurulabilmesi için Live Region adı verilen bir şey kullanılması gerekir. Burada bir uyarı olarak adlandırılan özel bir tür canlı bölge kullanacağız:
<div id="loginError" role="alert"></div>
Aynı davranışı register
fonksiyon hataları için de uygulayın (HTML'yi güncellemeyi unutmayın).
Gösterge panelinde bilgi gösterme
Az önce gördüğümüz teknikleri kullanarak, hesap bilgilerini gösterge paneli sayfasında da göstereceğiz.
Sunucudan alınan bir hesap nesnesi şu şekilde görünüyor:
{
"user": "test",
"currency": "$",
"description": "Test account",
"balance": 75,
"transactions": [
{ "id": "1", "date": "2020-10-01", "object": "Pocket money", "amount": 50 },
{ "id": "2", "date": "2020-10-03", "object": "Book", "amount": -10 },
{ "id": "3", "date": "2020-10-04", "object": "Sandwich", "amount": -5 }
],
}
Not: işinizi kolaylaştırmak için, önceden doldurulmuş verilerle
test
hesabını kullanabilirsiniz.
Görev
HTML'deki "Bakiye" bölümünü yer tutucu öğeler eklemek için değiştirelim:
<section>
Balance: <span id="balance"></span><span id="currency"></span>
</section>
Ayrıca, hesap açıklamasını göstermek için hemen altına yeni bir bölüm ekleyeceğiz:
<h2 id="description"></h2>
✅ Hesap açıklaması, altındaki içeriğin başlığı olarak işlev gördüğü için semantik olarak bir başlık olarak işaretlenmiştir. Başlık yapısının erişilebilirlik için neden önemli olduğunu öğrenin ve sayfayı eleştirel bir gözle inceleyerek başka nelerin başlık olabileceğini belirleyin.
Şimdi app.js
dosyasına yeni bir fonksiyon ekleyerek yer tutucuyu dolduralım:
function updateDashboard() {
if (!account) {
return navigate('/login');
}
updateElement('description', account.description);
updateElement('balance', account.balance.toFixed(2));
updateElement('currency', account.currency);
}
Öncelikle, devam etmeden önce ihtiyacımız olan hesap verilerine sahip olduğumuzu kontrol ediyoruz. Ardından, daha önce oluşturduğumuz updateElement()
fonksiyonunu kullanarak HTML'yi güncelliyoruz.
Bakiye görüntüsünü daha güzel hale getirmek için, değeri ondalık noktadan sonra 2 basamakla zorlamak için
toFixed(2)
yöntemini kullanıyoruz.
Şimdi updateDashboard()
fonksiyonumuzu her gösterge paneli yüklendiğinde çağırmamız gerekiyor. Ders 1 ödevini zaten tamamladıysanız bu oldukça basit olmalı, aksi takdirde aşağıdaki uygulamayı kullanabilirsiniz.
updateRoute()
fonksiyonunun sonuna şu kodu ekleyin:
if (typeof route.init === 'function') {
route.init();
}
Ve rota tanımlarını şu şekilde güncelleyin:
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard', init: updateDashboard }
};
Bu değişiklikle, her gösterge paneli sayfası görüntülendiğinde updateDashboard()
fonksiyonu çağrılır. Giriş yaptıktan sonra hesap bakiyesini, para birimini ve açıklamayı görebilmelisiniz.
HTML şablonlarıyla tablo satırlarını dinamik olarak oluşturma
Birinci derste uygulamamızdaki navigasyonu uygulamak için HTML şablonlarını ve appendChild()
yöntemini kullandık. Şablonlar daha küçük olabilir ve bir sayfanın tekrarlayan bölümlerini dinamik olarak doldurmak için kullanılabilir.
Aynı yaklaşımı HTML tablosundaki işlem listesini göstermek için kullanacağız.
Görev
HTML <body>
içinde yeni bir şablon ekleyin:
<template id="transaction">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</template>
Bu şablon, bir işlem için tarih, nesne ve miktar gibi 3 sütunu doldurmak istediğimiz tek bir tablo satırını temsil eder.
Ardından, JavaScript ile kolayca bulabilmek için gösterge paneli şablonundaki tablonun <tbody>
öğesine şu id
özelliğini ekleyin:
<tbody id="transactions"></tbody>
HTML'miz hazır, şimdi JavaScript koduna geçelim ve yeni bir createTransactionRow
fonksiyonu oluşturalım:
function createTransactionRow(transaction) {
const template = document.getElementById('transaction');
const transactionRow = template.content.cloneNode(true);
const tr = transactionRow.querySelector('tr');
tr.children[0].textContent = transaction.date;
tr.children[1].textContent = transaction.object;
tr.children[2].textContent = transaction.amount.toFixed(2);
return transactionRow;
}
Bu fonksiyon tam olarak adının ima ettiği şeyi yapar: daha önce oluşturduğumuz şablonu kullanarak yeni bir tablo satırı oluşturur ve işlem verilerini kullanarak içeriğini doldurur. Bunu updateDashboard()
fonksiyonumuzda tabloyu doldurmak için kullanacağız:
const transactionsRows = document.createDocumentFragment();
for (const transaction of account.transactions) {
const transactionRow = createTransactionRow(transaction);
transactionsRows.appendChild(transactionRow);
}
updateElement('transactions', transactionsRows);
Burada, üzerinde çalışabileceğimiz yeni bir DOM parçası oluşturan document.createDocumentFragment()
yöntemini kullanıyoruz ve sonunda HTML tablomuzla iliştiriyoruz.
Bu kodun çalışabilmesi için hala yapmamız gereken bir şey var, çünkü updateElement()
fonksiyonumuz şu anda yalnızca metin içeriğini destekliyor. Kodunu biraz değiştirelim:
function updateElement(id, textOrNode) {
const element = document.getElementById(id);
element.textContent = ''; // Removes all children
element.append(textOrNode);
}
append()
yöntemini kullanıyoruz çünkü bu yöntem bir üst öğeye metin veya DOM Düğümleri eklemeye olanak tanır, bu da tüm kullanım durumlarımız için mükemmeldir.
Eğer test
hesabını kullanarak giriş yapmayı denerseniz, artık kontrol panelinde bir işlem listesi görmelisiniz 🎉.
🚀 Meydan Okuma
Birlikte çalışarak kontrol paneli sayfasını gerçek bir bankacılık uygulaması gibi görünmesini sağlayın. Eğer uygulamanızı zaten tasarladıysanız, media queries kullanarak hem masaüstü hem de mobil cihazlarda güzel çalışan bir duyarlı tasarım oluşturmayı deneyin.
İşte tasarlanmış bir kontrol paneli sayfası örneği:
Ders Sonrası Test
Ödev
Kodunuzu yeniden düzenleyin ve yorumlayın
Feragatname:
Bu belge, AI çeviri hizmeti Co-op Translator kullanılarak çevrilmiştir. Doğruluk için çaba göstersek de, otomatik çevirilerin hata veya yanlışlık içerebileceğini lütfen unutmayın. Belgenin orijinal dili, yetkili kaynak olarak kabul edilmelidir. Kritik bilgiler için profesyonel insan çevirisi önerilir. Bu çevirinin kullanımından kaynaklanan yanlış anlamalar veya yanlış yorumlamalar için sorumluluk kabul etmiyoruz.