İlk AngularJS Uygulamanız İçin Adım Adım Eğitim
Yayınlanan: 2022-03-11AngularJS nedir?
AngularJS, Google tarafından geliştirilmiş, iyi yapılandırılmış, kolayca test edilebilir ve bakımı yapılabilir ön uç uygulamalar oluşturmanıza olanak tanıyan bir JavaScript MVC çerçevesidir.
Ve Neden Kullanmalıyım?
Henüz AngularJS'yi denemediyseniz çok şey kaçırıyorsunuz. Çerçeve, daha az kod ve daha fazla esneklikle, iyi yapılandırılmış, zengin istemci tarafı uygulamaları modüler bir şekilde oluşturmanıza yardımcı olacak sıkı bir şekilde entegre edilmiş bir araç setinden oluşur.
AngularJS, işaretlemenize işlevsellik ekleyen ve güçlü dinamik şablonlar oluşturmanıza olanak tanıyan yönergeler sağlayarak HTML'yi genişletir. Ayrıca, ihtiyaçlarınızı karşılayan yeniden kullanılabilir bileşenler oluşturarak ve tüm DOM manipülasyon mantığını soyutlayarak kendi yönergelerinizi de oluşturabilirsiniz.
Ayrıca, HTML'nizi (görünümler) JavaScript nesnelerinize (modellerinize) sorunsuz bir şekilde bağlayarak iki yönlü veri bağlama uygular. Basit bir ifadeyle, bu, modelinizdeki herhangi bir güncellemenin, herhangi bir DOM manipülasyonuna veya olay işlemeye (örneğin, jQuery ile) ihtiyaç duymadan anında görünümünüze yansıtılacağı anlamına gelir.
Son olarak, sunucu iletişimi konusundaki esnekliği nedeniyle Angular'ı seviyorum. Çoğu JavaScript MVC çerçevesi gibi, uygulamanıza bir RESTful web API'si aracılığıyla hizmet verebildiği sürece herhangi bir sunucu tarafı teknolojiyle çalışmanıza izin verir. Ancak Angular, kodunuzu önemli ölçüde basitleştiren ve API çağrılarını yeniden kullanılabilir hizmetlere soyutlamanıza olanak tanıyan XHR'nin üzerinde hizmetler de sağlar. Sonuç olarak, modelinizi ve iş mantığınızı ön uca taşıyabilir ve arka uçtan bağımsız web uygulamaları oluşturabilirsiniz. Bu gönderide, her seferinde bir adım olacak şekilde tam da bunu yapacağız.
Peki, Nereden Başlamalıyım?
İlk olarak, oluşturmak istediğimiz uygulamanın doğasına karar verelim. Bu kılavuzda, arka uçta çok fazla zaman harcamamayı tercih ediyoruz, bu nedenle İnternet'te kolayca erişilebilen verilere dayalı bir şeyler yazacağız - bir spor yayını uygulaması gibi!
Motor yarışlarının ve Formula 1'in büyük bir hayranı olduğum için arka planımız olarak hareket etmesi için bir autosport API hizmeti kullanacağım. Neyse ki Ergast'taki adamlar, bizim için mükemmel olacak ücretsiz bir motor sporları API'si sağlayacak kadar kibarlar.
İnşa edeceğimiz şeye bir göz atmak için canlı demoya bir göz atın. Demoyu güzelleştirmek ve bazı Açısal şablonları göstermek için WrapBootstrap'tan bir Bootstrap teması uyguladım, ancak bu makalenin CSS ile ilgili olmadığını görünce, onu örneklerden soyutlayıp dışarıda bırakacağım.
Başlarken Eğitimi
Örnek uygulamamızı bazı ortak bilgilerle başlatalım. Açısal tohum projesini tavsiye ederim çünkü size sadece önyükleme için harika bir iskelet sağlamakla kalmıyor, aynı zamanda Karma ve Jasmine ile birim testi için zemin hazırlıyor (bu demoda herhangi bir test yapmayacağız, bu yüzden sadece şimdilik bunları bir kenara bırakın; projenizi birim ve uçtan uca test için ayarlama hakkında daha fazla bilgi için bu eğitimin 2. Bölümüne bakın).
EDIT (Mayıs 2014): Bu öğreticiyi yazdığımdan beri, açısal tohum projesi bazı ağır değişikliklerden geçti (paket yöneticisi olarak Bower'ın eklenmesi dahil). Projeyi nasıl dağıtacağınız konusunda herhangi bir şüpheniz varsa, başvuru kılavuzunun ilk bölümüne hızlıca göz atın. Bu öğreticinin 2. Kısmında, diğer araçların yanı sıra Bower daha ayrıntılı olarak ele alınmaktadır.
Tamam, şimdi depoyu klonladığımıza ve bağımlılıkları yüklediğimize göre, uygulamamızın iskeleti şöyle görünecek:
Artık kodlamaya başlayabiliriz. Bir yarış şampiyonası için bir spor yayını oluşturmaya çalışırken, en alakalı görünümle başlayalım: şampiyonluk tablosu .
Kapsamımız içinde zaten tanımlanmış bir sürücü listemiz olduğu için (benimle bekleyin – oraya geleceğiz) ve herhangi bir CSS'yi (okunabilirlik için) yok sayarak, HTML'miz şöyle görünebilir:
<body ng-app="F1FeederApp" ng-controller="driversController"> <table> <thead> <tr><th colspan="4">Drivers Championship Standings</th></tr> </thead> <tbody> <tr ng-repeat="driver in driversList"> <td>{{$index + 1}}</td> <td> <img src="img/flags/{{driver.Driver.nationality}}.png" /> {{driver.Driver.givenName}} {{driver.Driver.familyName}} </td> <td>{{driver.Constructors[0].name}}</td> <td>{{driver.points}}</td> </tr> </tbody> </table> </body>
Bu şablonda ilk fark edeceğiniz şey, değişken değerleri döndürmek için ifadelerin (“{{“ ve “}}”) kullanılmasıdır. AngularJS geliştirmede ifadeler, istenen bir değeri döndürmek için bazı hesaplamaları gerçekleştirmenize izin verir. Bazı geçerli ifadeler şunlar olabilir:
-
{{ 1 + 1 }}
-
{{ 946757880 | date }}
-
{{ user.name }}
Etkili olarak, ifadeler JavaScript benzeri snippet'lerdir. Ancak çok güçlü olmasına rağmen, herhangi bir üst düzey mantığı uygulamak için ifadeler kullanmamalısınız. Bunun için direktifleri kullanıyoruz.
Temel Direktifleri Anlamak
Fark edeceğiniz ikinci şey, tipik işaretlemede görmeyeceğiniz ng-attributes
varlığıdır. Bunlar direktif.
Yüksek düzeyde, yönergeler, AngularJS'ye belirli bir davranışı bir DOM öğesine eklemesini (veya dönüştürmesini, değiştirmesini vb.) söyleyen işaretlerdir (öznitelikler, etiketler ve sınıf adları gibi). Daha önce gördüklerimize bir göz atalım:
ng-app
yönergesi, uygulamanızın kapsamını tanımlayan önyükleme işleminden sorumludur. AngularJS'de aynı sayfada birden fazla uygulamanız olabilir, bu nedenle bu yönerge her farklı uygulamanın nerede başlayıp nerede bittiğini tanımlar.ng-controller
yönergesi, görünümünüzden hangi denetleyicinin sorumlu olacağını tanımlar. Bu durumda, sürücü listemizi (driversList
) sağlayacak olandriversController
belirtiyoruz.ng-repeat
yönergesi en yaygın olarak kullanılanlardan biridir ve koleksiyonlar arasında dolaşırken şablon kapsamınızı tanımlamaya yarar. Yukarıdaki örnekte,driversList
içindeki her sürücü için tablodaki bir satırı çoğaltır.
Denetleyici Ekleme
Elbette, denetleyici olmadan görüşümüzün bir anlamı yok. driversController
:
angular.module('F1FeederApp.controllers', []). controller('driversController', function($scope) { $scope.driversList = [ { Driver: { givenName: 'Sebastian', familyName: 'Vettel' }, points: 322, nationality: "German", Constructors: [ {name: "Red Bull"} ] }, { Driver: { givenName: 'Fernando', familyName: 'Alonso' }, points: 207, nationality: "Spanish", Constructors: [ {name: "Ferrari"} ] } ]; });
Denetleyiciye parametre olarak ilettiğimiz $scope
değişkenini fark etmiş olabilirsiniz. $scope
değişkeninin denetleyicinizi ve görünümlerinizi birbirine bağlaması gerekiyor. Özellikle, şablonunuz içinde kullanılacak tüm verileri tutar. Eklediğiniz her şey (yukarıdaki örnekte driversList
gibi) görünümlerinizden doğrudan erişilebilir olacaktır. Şimdilik, daha sonra API hizmetimizle değiştireceğimiz yapay (statik) bir veri dizisi ile çalışalım.
Şimdi bunu app.js'ye ekleyin:
angular.module('F1FeederApp', [ 'F1FeederApp.controllers' ]);
Bu kod satırıyla, aslında uygulamamızı başlatır ve bağlı olduğu modülleri kaydederiz. Bu dosyaya ( app.js
) daha sonra geri döneceğiz.
Şimdi her şeyi index.html
içinde bir araya getirelim:
<!DOCTYPE html> <html> <head> <title>F-1 Feeder</title> </head> <body ng-app="F1FeederApp" ng-controller="driversController"> <table> <thead> <tr><th colspan="4">Drivers Championship Standings</th></tr> </thead> <tbody> <tr ng-repeat="driver in driversList"> <td>{{$index + 1}}</td> <td> <img src="img/flags/{{driver.Driver.nationality}}.png" /> {{driver.Driver.givenName}} {{driver.Driver.familyName}} </td> <td>{{driver.Constructors[0].name}}</td> <td>{{driver.points}}</td> </tr> </tbody> </table> <script src="bower_components/angular/angular.js"></script> <script src="bower_components/angular-route/angular-route.js"></script> <script src="js/app.js"></script> <script src="js/services.js"></script> <script src="js/controllers.js"></script> </body> </html>
Modulo küçük hatalar, artık uygulamanızı başlatabilir ve (statik) sürücü listenizi kontrol edebilirsiniz.
Not: Uygulamanızın hatalarını ayıklamak ve modellerinizi ve kapsamınızı tarayıcıda görselleştirmek için yardıma ihtiyacınız varsa, Chrome için harika Batarang eklentisine bir göz atmanızı tavsiye ederim.
Sunucudan Veri Yükleme
Bizim görüşümüzde kontrolörümüzün verilerini nasıl görüntüleyeceğimizi zaten bildiğimize göre, RESTful sunucusundan gerçek anlamda canlı veri almanın zamanı geldi.
AngularJS, HTTP sunucularıyla iletişimi kolaylaştırmak için $http
ve $resource
hizmetlerini sağlar. Birincisi, XMLHttpRequest veya JSONP'nin üstündeki bir katmandır, ikincisi ise daha yüksek düzeyde bir soyutlama sağlar. $http
kullanacağız.
Sunucu API çağrılarımızı denetleyiciden soyutlamak için, verilerimizi getirecek ve bunu services.js
ekleyerek $http
etrafında bir sarmalayıcı görevi görecek kendi özel hizmetimizi oluşturalım:
angular.module('F1FeederApp.services', []). factory('ergastAPIservice', function($http) { var ergastAPI = {}; ergastAPI.getDrivers = function() { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK' }); } return ergastAPI; });
İlk iki satır ile yeni bir modül oluşturuyoruz ( F1FeederApp.services
) ve o modül içinde bir servis kaydediyoruz ( ergastAPIservice
). Bu hizmete parametre olarak $http
dikkat edin. Bu, Angular'ın bağımlılık enjeksiyon motoruna yeni hizmetimizin $http
hizmetini gerektirdiğini (veya bağlı olduğunu ) söyler.
Benzer şekilde, Angular'a yeni modülümüzü uygulamamıza dahil etmesini söylemeliyiz. Mevcut kodumuzu şununla değiştirerek app.js
ile kaydedelim:
angular.module('F1FeederApp', [ 'F1FeederApp.controllers', 'F1FeederApp.services' ]);
Şimdi tek yapmamız gereken controller.js
dosyamızda biraz ince ayar yapmak, ergastAPIservice
bir bağımlılık olarak dahil etmek ve şimdi gitmeye hazırız:
angular.module('F1FeederApp.controllers', []). controller('driversController', function($scope, ergastAPIservice) { $scope.nameFilter = null; $scope.driversList = []; ergastAPIservice.getDrivers().success(function (response) { //Dig into the responde to get the relevant data $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings; }); });
Şimdi uygulamayı yeniden yükleyin ve sonucu kontrol edin. Şablonumuzda herhangi bir değişiklik yapmadığımıza, ancak kapsamımıza bir nameFilter
değişkeni eklediğimize dikkat edin. Bu değişkeni kullanmak için koyalım.

filtreler
Harika! İşlevsel bir denetleyicimiz var. Ancak yalnızca sürücülerin bir listesini gösterir. Listemizi filtreleyecek basit bir metin arama girişi uygulayarak bazı işlevler ekleyelim. index.html
<body>
etiketinin hemen altına şu satırı ekleyelim:
<input type="text" ng-model="nameFilter" placeholder="Search..."/>
Şimdi ng-model
yönergesini kullanıyoruz. Bu yönerge metin alanımızı $scope.nameFilter
değişkenine bağlar ve değerinin giriş değeriyle her zaman güncel olmasını sağlar. Şimdi index.html'yi bir kez daha ziyaret edelim ve ng-repeat
yönergesini içeren satırda küçük bir ayar yapalım:
<tr ng-repeat="driver in driversList | filter: nameFilter">
Bu satır, ng-repeat
repeat'e, verilerin çıktısı alınmadan önce, driversList
dizisinin nameFilter
içinde depolanan değere göre filtrelenmesi gerektiğini söyler.
Bu noktada, iki yönlü veri bağlama devreye girer: arama alanına her değer girildiğinde, Angular hemen onunla ilişkilendirdiğimiz $scope.nameFilter
yeni değerle güncellenmesini sağlar. Bağlama her iki şekilde de çalıştığından, nameFilter
değeri güncellendiği anda, onunla ilişkili ikinci yönerge (yani, ng-repeat
) de yeni değeri alır ve görünüm hemen güncellenir.
Uygulamayı yeniden yükleyin ve arama çubuğuna bakın.
Bu filtrenin, modelin kullanılmayanlar da dahil olmak üzere tüm özniteliklerinde anahtar kelimeyi arayacağını unutmayın. Diyelim ki sadece Driver.givenName
ve Driver.familyName
ile filtreleme yapmak istiyoruz: İlk olarak, $scope.driversList = [];
hemen altına driversController
ekliyoruz; astar:
$scope.searchFilter = function (driver) { var keyword = new RegExp($scope.nameFilter, 'i'); return !$scope.nameFilter || keyword.test(driver.Driver.givenName) || keyword.test(driver.Driver.familyName); };
Şimdi index.html
dönersek, ng-repeat
yönergesini içeren satırı güncelliyoruz:
<tr ng-repeat="driver in driversList | filter: searchFilter">
Uygulamayı bir kez daha yeniden yükleyin ve şimdi ada göre bir aramamız var.
Rotalar
Bir sonraki hedefimiz, her bir sürücüye tıklamamıza ve kariyer ayrıntılarını görmemize izin verecek bir sürücü ayrıntıları sayfası oluşturmaktır.
İlk olarak, bu çeşitli uygulama yollarıyla başa çıkmamıza yardımcı olacak $routeProvider
hizmetini ( app.js
içinde) ekleyelim. Ardından, bu tür iki rota ekleyeceğiz: biri şampiyonluk tablosu ve diğeri sürücü ayrıntıları için. İşte yeni app.js
:
angular.module('F1FeederApp', [ 'F1FeederApp.services', 'F1FeederApp.controllers', 'ngRoute' ]). config(['$routeProvider', function($routeProvider) { $routeProvider. when("/drivers", {templateUrl: "partials/drivers.html", controller: "driversController"}). when("/drivers/:id", {templateUrl: "partials/driver.html", controller: "driverController"}). otherwise({redirectTo: '/drivers'}); }]);
Bu değişiklikle, http://domain/#/drivers
drivers'a gitmek, driversController
ve kısmi görünümün partials/drivers.html
drivers.html içinde oluşturulacağını arayacaktır. Fakat bekle! Henüz kısmi görüşümüz yok, değil mi? Bunları da yaratmamız gerekecek.
Kısmi Görünümler
AngularJS, rotalarınızı belirli denetleyicilere ve görünümlere bağlamanıza izin verir.
Ama önce, Angular'a bu kısmi görünümleri nerede oluşturacağımızı söylemeliyiz. Bunun için ng-view
yönergesini kullanacağız ve index.html
aşağıdakileri yansıtacak şekilde değiştireceğiz:
<!DOCTYPE html> <html> <head> <title>F-1 Feeder</title> </head> <body ng-app="F1FeederApp"> <ng-view></ng-view> <script src="bower_components/angular/angular.js"></script> <script src="bower_components/angular-route/angular-route.js"></script> <script src="js/app.js"></script> <script src="js/services.js"></script> <script src="js/controllers.js"></script> </body> </html>
Şimdi, uygulama rotalarımızda ne zaman gezinsek, Angular ilişkili görünümü yükleyecek ve onu <ng-view>
etiketinin yerine işleyecektir. Tek yapmamız gereken partials/drivers.html
adında bir dosya oluşturmak ve şampiyonluk tablosu HTML'mizi oraya koymak. Bu şansı, sürücü adını sürücü ayrıntıları rotamıza bağlamak için de kullanacağız:
<input type="text" ng-model="nameFilter" placeholder="Search..."/> <table> <thead> <tr><th colspan="4">Drivers Championship Standings</th></tr> </thead> <tbody> <tr ng-repeat="driver in driversList | filter: searchFilter"> <td>{{$index + 1}}</td> <td> <img src="img/flags/{{driver.Driver.nationality}}.png" /> <a href="#/drivers/{{driver.Driver.driverId}}"> {{driver.Driver.givenName}} {{driver.Driver.familyName}} </a> </td> <td>{{driver.Constructors[0].name}}</td> <td>{{driver.points}}</td> </tr> </tbody> </table>
Son olarak, ayrıntılar sayfasında neyi göstermek istediğimize karar verelim. Sürücüyle ilgili tüm ilgili gerçeklerin (örneğin doğum, uyruk) ve son sonuçlarını içeren bir tablonun özetine ne dersiniz? Bunu yapmak için services.js
şunu ekleriz:
angular.module('F1FeederApp.services', []) .factory('ergastAPIservice', function($http) { var ergastAPI = {}; ergastAPI.getDrivers = function() { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK' }); } ergastAPI.getDriverDetails = function(id) { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/driverStandings.json?callback=JSON_CALLBACK' }); } ergastAPI.getDriverRaces = function(id) { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/results.json?callback=JSON_CALLBACK' }); } return ergastAPI; });
Bu sefer, yalnızca belirli bir sürücüyle ilgili bilgileri alabilmemiz için sürücünün kimliğini hizmete veriyoruz. Şimdi controllers.js
dosyasını değiştiriyoruz:
angular.module('F1FeederApp.controllers', []). /* Drivers controller */ controller('driversController', function($scope, ergastAPIservice) { $scope.nameFilter = null; $scope.driversList = []; $scope.searchFilter = function (driver) { var re = new RegExp($scope.nameFilter, 'i'); return !$scope.nameFilter || re.test(driver.Driver.givenName) || re.test(driver.Driver.familyName); }; ergastAPIservice.getDrivers().success(function (response) { //Digging into the response to get the relevant data $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings; }); }). /* Driver controller */ controller('driverController', function($scope, $routeParams, ergastAPIservice) { $scope.id = $routeParams.id; $scope.races = []; $scope.driver = null; ergastAPIservice.getDriverDetails($scope.id).success(function (response) { $scope.driver = response.MRData.StandingsTable.StandingsLists[0].DriverStandings[0]; }); ergastAPIservice.getDriverRaces($scope.id).success(function (response) { $scope.races = response.MRData.RaceTable.Races; }); });
Burada dikkat edilmesi gereken önemli nokta, sürücü kontrolörüne $routeParams
hizmetini enjekte etmiş olmamızdır. Bu hizmet, $routeParams.id
kullanarak URL parametrelerimize (bu durumda :id
için) erişmemizi sağlar.
Artık verilerimiz kapsamda olduğuna göre, yalnızca kalan kısmi görünüme ihtiyacımız var. partials/driver.html
adında bir dosya oluşturalım ve şunu ekleyelim:
<section> <a href="./#/drivers"><- Back to drivers list</a> <nav class="main-nav"> <div class="driver-picture"> <div class="avatar"> <img ng-show="driver" src="img/drivers/{{driver.Driver.driverId}}.png" /> <img ng-show="driver" src="img/flags/{{driver.Driver.nationality}}.png" /><br/> {{driver.Driver.givenName}} {{driver.Driver.familyName}} </div> </div> <div class="driver-status"> Country: {{driver.Driver.nationality}} <br/> Team: {{driver.Constructors[0].name}}<br/> Birth: {{driver.Driver.dateOfBirth}}<br/> <a href="{{driver.Driver.url}}" target="_blank">Biography</a> </div> </nav> <div class="main-content"> <table class="result-table"> <thead> <tr><th colspan="5">Formula 1 2013 Results</th></tr> </thead> <tbody> <tr> <td>Round</td> <td>Grand Prix</td> <td>Team</td> <td>Grid</td> <td>Race</td> </tr> <tr ng-repeat="race in races"> <td>{{race.round}}</td> <td><img src="img/flags/{{race.Circuit.Location.country}}.png" />{{race.raceName}}</td> <td>{{race.Results[0].Constructor.name}}</td> <td>{{race.Results[0].grid}}</td> <td>{{race.Results[0].position}}</td> </tr> </tbody> </table> </div> </section>
Şimdi ng-show
yönergesini iyi kullanıma koyduğumuza dikkat edin. Bu yönerge, yalnızca sağlanan ifade true
(yani ne false
ne de null
) HTML öğesini gösterir. Bu durumda, avatar yalnızca sürücü nesnesi denetleyici tarafından kapsama yüklendikten sonra görünecektir.
Son Dokunuşlar
Bir sürü CSS ekleyin ve sayfanızı oluşturun. Bunun gibi bir şeyle sonuçlanmalısın:
Artık uygulamanızı başlatmaya ve her iki yolun da istediğiniz gibi çalıştığından emin olmaya hazırsınız. Kullanıcının gezinme yeteneklerini geliştirmek için index.html
statik bir menü de ekleyebilirsiniz. İmkanlar sonsuzdur.
DÜZENLEME (Mayıs 2014): Bu eğitimde oluşturduğumuz kodun indirilebilir bir sürümü için birçok istek aldım. Bu nedenle onu burada yayınlamaya karar verdim (herhangi bir CSS'den arındırılmış). Ancak, indirmenizi gerçekten tavsiye etmiyorum , çünkü bu kılavuz, aynı uygulamayı kendi ellerinizle oluşturmak için ihtiyacınız olan her adımı içerir, bu çok daha faydalı ve etkili bir öğrenme alıştırması olacaktır.
Çözüm
Eğitimin bu noktasında, basit bir uygulama (Formula 1 besleyici gibi) yazmak için ihtiyacınız olan her şeyi ele aldık. Canlı demoda kalan sayfaların her biri (örn., inşaatçı şampiyonası tablosu, takım ayrıntıları, takvim), burada incelediğimiz aynı temel yapıyı ve kavramları paylaşır.
Son olarak, Angular'ın çok güçlü bir çerçeve olduğunu ve sunduğu her şey açısından yüzeyi zar zor çizdiğimizi unutmayın. Bu öğreticinin 2. Bölümünde, Angular'ın emsal ön uç MVC çerçeveleri arasında neden öne çıktığına ilişkin örnekler vereceğiz: test edilebilirlik. Yeomen, Grunt ve Bower ile sürekli entegrasyon sağlayan Karma ile birim testleri yazma ve çalıştırma sürecini ve bu harika ön uç çerçevesinin diğer güçlü yönlerini gözden geçireceğiz.