AngularJS 2 Nedir? Bölüm 5
Selamlar,
Bugün Angular2’de nasıl server’a bağlanılır ve bir servisden nasıl data çekilir hep beraber inceleyeceğiz.
Http işlemlerinin yapılabilmesi için Index.html sayfasına aşağıdaki modullerin eklenmesi gerekmektedir:
<script src=”node_modules/angular2/bundles/http.dev.js”></script>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<html> <head> <title>AngularJs 2 Öğren</title> <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css"> <link rel="stylesheet" href="app/style.css"> <!-- 1. Load libraries --> <!-- IE required polyfills, in this exact order --> <script src="node_modules/es6-shim/es6-shim.min.js"></script> <script src="node_modules/systemjs/dist/system-polyfills.js"></script> <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="node_modules/rxjs/bundles/Rx.js"></script> <script src="node_modules/angular2/bundles/angular2.dev.js"></script> <script src="node_modules/angular2/bundles/http.dev.js"></script> <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous"> <!-- 2. Configure SystemJS --> <script> System.config({ packages: { app: { format: 'register', defaultExtension: 'js' } } }); System.import('app/boot') .then(null, console.error.bind(console)); </script> </head> <!-- 3. Sayfada Görünecek AngularJS2 Component --> <body> <my-app>Yükleniyor...</my-app> </body> </html> |
Örnek Json servisi için http://jsonplaceholder.typicode.com/ adresinden faydalanılacaktır. Amaç ilgili sevisden data çekmektir.
post.service.ts: Bir json servisden data çekmek ve post etmek için PostService adında yeni bir provider yazılacaktır. Aşağıdaki örnekde :
- “map”‘leme ve asenkron yüklme için gerekli olan “toPromise” ve “map” “rxjs” modulleri sayfanın başında import ile eklenmiştir.
- “http.get” ve “http.post” işlemleri için en başa “http” module yine import ile eklenmiştir.
- Ayrıca “Observable” module’ü de yine “post” işlemi için 2. bir yöntem olarak eklenmiştir.
- “getPosts()” methods ile”jsonplaceholder” sitesinden örnek amaçlı json data çekilmiştir.
- “getPosts()” 1. Yöntem de “Observable” ile ilgili siteden Constructor’da alınan, Http sınıfından alınan”_http”.”get()” methodu ile ilgili data alınmış ve “.map()” ile gelen result “json”‘a çevrilmiştir.
- “getPosts()” 2. Yöntem de asenkron bir yapı sağlıyan “promis()” kullanılmış ve diğerinden farklı olarak json() olarak çekilen datanın sonuna “.toPromis()” methodu eklenmiştir.
- “createPost()” methodunda “_http.post()” methodu ile methoda gelen “Post” “JSON.stringify()” ile post edilir yani gönderilir. Gelen cevap “json” tipinde map() lenir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import {Http} from 'angular2/http' import {Observable} from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/toPromise'; import { Injectable } from 'angular2/core'; import {Post} from './post' @Injectable() export class PostService { private _url = 'http://jsonplaceholder.typicode.com/posts'; constructor(private _http: Http) { } /*getPosts():Observable<Post[]> { console.log(this._url); return this._http.get(this._url) .map(res=>res.json()); }*/ getPosts(): Promise<Post[]> { //console.log(this._url); return this._http.get(this._url) .map(res => res.json()) .toPromise(); } createPost(post: Post) { console.log(JSON.stringify(post)); this._http.post(this._url, JSON.stringify(post)) .map(res => res.json()); } } |
Get() Methodu ile Url’den Dönen Örnek Json Data:
Post.ts: Çekilen ve Post edilen Url dataya karşılık gelen Post sınıfı. Yani data model’imiz aşağıdaki Post sınıfıdır.
1 2 3 4 5 6 |
export class Post { userId: number; id: number; title: string; body: string; } |
app.component.ts: Aşağıdaki örnekde 2 yöntem kullanılmıştır. Amaç ilgili servise post işlemi yapmaktır.
- Durum Http.Post “Constructer”‘da yukarıda yazılan PostService parametre olarak alınır. Yeni bir “Post()” nesnesi oluşturulup ilgili propertyler’i doldurulduktan sonra “PostService”‘in “createPost()” methodu çağrılır. Ve ilgili data gönderilir.
- Durum Http.Get “ngOnInit()” methodunda öncelikle “PostService”‘in “getPosts()” methodu ile ilgili Post() nesneleri, ilk önce “PostService”‘indeki “Observable” ‘a karşılık gelen ==>”subscribe()” methodu kullanılarak alınmış. Daha sonra da asenkron yapıya uygun “PostService”‘indeki “Promise()” methoduna karşılık gelen ==> “then()” methodu kullanılmıştır. Çekilen tüm Post[]’si, “map()” methodu ile herbir “post” gezilerek “title”‘ı console’a yazılır.
- Bu işlemler sırasında, yani get işlemi yapılırken ekrana “Loading” sembolü çıkarmak için öncelikle “fontawesome.io” sitesindeki css’den faydalanılmıştır.
- “template” içinde ilgili div içinde *ngIf=”isLoading” ile ilgili değişkene bağlı olarak, Loading svg yani font icon ekranda gösterilmiştir.
- ngOnInit() methodunda ilgili AppComponent sınıfı yüklenirken “PostService”‘inden ilgili data çekilirken “isLoading” değişkenine true değeri atanmıştır. Böylece “Loading” divi’nin gözükmesi sağlanmıştır. “getPost()” işlemi bittikten sonra “isLoading” değişkeni false’a atanarak “Loading” divi’nin tekrardan gizlenmesi sağlanmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import { Component, OnInit} from 'angular2/core'; import {Post} from './post' import {PostService} from './post.service'; import {HTTP_PROVIDERS} from 'angular2/http'; /*http://fontawesome.io/get-started/*/ /*https://www.bootstrapcdn.com/fontawesome/*/ @Component({ selector: 'my-app', template: ` <div *ngIf="isLoading"><i class="fa fa-spinner fa-spin fa-3x"></i></div> `, providers: [PostService, HTTP_PROVIDERS] }) export class AppComponent implements OnInit { post: Post; isLoading = true; constructor(private _postService: PostService) { this.post=new Post(); this.post.userId=1; this.post.title="a"; this.post.body="b"; this._postService.createPost(this.post); } ngOnInit() { this._postService.getPosts() //.subscribe(posts => { .then(posts => { this.isLoading=false; console.log(posts.map(post => post.title)) }); } } |
index.html: fontawesome.io sitesindeki csslerden faydalanmak için aşağıdaki css kütüpahanesi index.html sayfasına eklenir. “https://www.bootstrapcdn.com/fontawesome/” sitesinden alınan css yolu aşağıda gösterilmiştir.
1 |
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous"> |
Örnek : Bu örnekde GitHub’dan kullanıcı bilgisini ve takipçilerinin listesini alıp, ilgili json datayı directive ve service ile ekrana basacağız.
github.service.ts: Öncelikle Github’dan user ve Followers bilgilerini çeken bir “GitHubService”‘i yazalım.
- Öncelikle ilgili service’in başka bir sınıfa inject edilebilmesi için @Injectable() olması gerekmekte ve ilgili module’ün {Injectable} import edilmesi gerekmektedir.
- Bir Url’den get işlemi yapılacağı için {Http} module’ünün import edilmesi gerekmektedir.
- “Observable” ve “map”‘lame için rxjs kütüpahanesine ait {Observable} ve {Map} moduleleri import edilir.
- GitHubService sınıfına ait olan “getUser()” ve “getFollowers()” methodları ile ilgili datalar Github’dan json olarak çekilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import {Injectable} from 'angular2/core'; import {Http} from 'angular2/http' import {Observable} from 'rxjs/Observable'; import'rxjs/add/operator/map'; @Injectable() export class GitHubService{ private _baseUrl="https://api.github.com/users/" constructor(private _http: Http){ } getUser(username){ return this._http.get(this._baseUrl+username) .map(res=>res.json()); } getFollowers(username){ return this._http.get(this._baseUrl+username+"/followers") .map(res=>res.json()); } } |
github-profile.component.ts: Şimdi sıra geldi ilgili service’i kullanarak User ve Followers bilgisini ekrana yeni bir directive ile basmaya.
- İlgili tüm moduleler import ile eklenir. {Componenet},{OnInit},{HTTP_PROVIDERS},{Observable} ,{GitHubService} “forkJoin”
- İlgili directive’e ait selector yani app.component’da kullanılacak element ismi “<github-profile>” olarak tanımlanır.
- Gözükecek kullanıcı bilgisi için custom css “styles” property’si altında “.avatar” olarak tanımlanır.
- template kısmında yine loading font icon’unun gözükmesi “isLoading” değişkenine bağlanmıştır.
- Kullanıcı Adı {{user.login}} ve Url’i {{user.avatar_url}} olarak tanımlanmıştır.
- Çekilen tüm “followers” listesi “*ngFor” ile gezilerek ekrana Url {{follower.awatar_url}} ve Adı {{follower.login}} ekrana basılır.
- providers property’s olarak kullanılacak “HTTP_PROVIDERS ve GitHubService” tanımlanır.
- GitHubProfile sınıfının constructer’ında, yukarıda yazılan github.service’i alınır.
- “ngOnInit()” yani sınıfın yüklenme anında, 2 servisden çekilen json result’lar “Observable.forkJoin()” methodu ile tek bir diziye atanmıştır.
- Diziye atılan servisler map()’lem sonucları local değişkenler olan “user” ve “followers”‘a atanmıştır.
- Son olarak ilgili servislerin completed anında, sayfada gösterilen Loading sembolü ekrandan kaldırılmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import { Component, OnInit } from 'angular2/core'; import {HTTP_PROVIDERS} from 'angular2/http' import {Observable} from 'rxjs/Observable' import 'rxjs/add/observable/forkJoin' import {GitHubService} from './github.service' @Component({ selector: 'github-profile', styles: [ ` .avatar{ width:100; height:100; border-radius:100%; } ` ], template: ` <i *ngIf="isLoading" class="fa fa-spinner fa-spin fa-3x"></i> <h2>@{{user.login}}</h2> <img class="avatar" src="{{ user.avatar_url }}"> <h3>Takipciler</h3> <div *ngFor="#follower of followers" class="media"> <div class="media-left"> <a href="#"> <img class="media-object avatar" src="{{ follower.avatar_url }}"> </a> </div> <div class="media-body"> <h4 class="media-heading">{{ follower.login }}</h4> </div> </div> `, providers: [HTTP_PROVIDERS, GitHubService] }) export class GitHubProfile implements OnInit { isLoading = true; username = "borakasmer"; user = {}; followers = []; constructor(private _gitHubService: GitHubService) { } ngOnInit() { Observable.forkJoin( this._gitHubService.getUser(this.username), this._gitHubService.getFollowers(this.username) ) .subscribe(res => { this.user = res[0]; this.followers = res[1]; }, null, () => { this.isLoading = false; } ) } } |
Böylece geldik bir makalenin daha sonuna. Angular2’de servislerle asenkron olarak çalışmak gerçekten çok kolay. Farklı librarylerin yardımları ile harika şeyler yapmak mümkün. Kullanılan TypeScript ile Backend ve Forntend development’ı birbirinden ayırmak nerede ise mümkün değil. Bence gün gelecek herşey client side tarafta çözülecek. Backend, sadece servislerin kullanıldığı bir yapıdan ibaret olucak. O da sadece cloude üzerinde çalışan yapılar ile client arasında bir köprü olacak.
Yeni bir makalede görüşmek üzere hoşçakalın.
Kaynaklar : https://angular.io/, https://egghead.io, Mosh Hamedani(Angular 2 with TypeScript for Beginners The Pragmatic Guide), ng-book2 The Complete Book on AngularJS 2 …
angular 2 yazılarınız için teşekkürler, gerçekten özgün kaliteli bir anlatımınız var, son olarak ciddi bir projeyle bu anlatımı sonlandırmanız daha güzel sonuçlar doğurabilir.
Teşekkürler,
Evet güzel bir proje yazınca, bunu da makaleleştiricem.
İyi çalışmalar.
Elinize sağlık bora bey.
Bir sorum olacaktı.
UrlRouting yaptığımızda örn: http://www.site.com/user/detay/1 sayfasına direk girmek istediğimizde not found hatası veriyor.
fakat HashLocationStrategy aktif edildiğinde http://www.site.com/#/user/detay/1 şeklinde bir adresleme yapıyor ve direk girişte ilgili sayfa açılıyor.
http://www.site.com/#/user/detay/1 ilgili adreste ‘#’ işarti olamadan (PathLocationStrategy olarak adlandırılıyor galiba) direk girişlerde not found hatası almamak için ne yapmak gerekiyor.