İlk AngularJS Uygulamanız İçin Adım Adım Eğitim

Yayınlanan: 2022-03-11
AngularJS gelişti ve daha da iyi hale geldi. Şimdi Angular olarak adlandırılan bu, tamamen yeni bir geliştirme iş akışına göre yeniden yazıldı. Material ve Firebase içeren yeni Angular 5 eğiticimize ve hatta daha yeni Angular 6 tam yığın eğiticimize göz atın.

AngularJS 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.

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 sunar. Bununla, modelinizi ve iş mantığınızı ön uca taşıyabilir ve arka uçtan bağımsız web uygulamaları oluşturabilirsiniz.

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:

angularjs öğreticisi - iskeletle başlayın

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 .

ş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}}&nbsp;{{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 olan driversController 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}}&nbsp;{{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.

uygulama arama çubuğu

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}}&nbsp;{{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:

CSS ile oluşturulan sayfa

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.