Ionic, SignalR ve TypeScript ile Mobile Uygulama Geliştirme Bölüm 3
Selamlar,
Bu makalede, Ionic 2. Makalesinden kalınan yerden konular anlatılmaya başlanacaktır. “team-home” sayfası ve “Ions-Tab” ile başlanıp, “Pull Request” konusu ile devam edilecektir. “team-home” sayfası aslında bir çeşit container’dır. Takım (team) ve Standings(Sıralama) sayfalarının tablerinin ve içeriğinin gösterildiği sayfadır. Daha sonra Lodash kütüphanesi, tarihe göre filitreleme, alert ve toastController kavramları bu makalenin devam konularıdır. Son olarak tournament sayfası ile maklenin sonuna gelinecektir.
Ion-Tabs: Ionic mobile uygulamalarında tabler büyük önem taşımaktadır. Alttaki sayfada bu konuya örnek bir uygulama yazılmıştır. “ionic generate page team-home” komutu ile ilgili sayfa create edilir.
team-home.html: Hatırlarsanız Ana sayfa(my-teams.html) ve Menude(app.component.html) favori takımlar tıklanınca gidilen sayfa, takım anasayfası yani “team-home” page idi. Şimdi gelin bu sayfayı, detaylıcı hep beraber inceleyelim.
- “<ion-navbar color=’primary’>“: Yukarıdaki resimde de görüldüğü gibi, takım adının yazıldığı mavi renkli header kısmıdır.
- “<ion-title>” : Takım adının yazıldığı “<ion-header>” altındaki yazı kısmıdır.
- “<button> ve <ion-icon name=”home”>” : İlgili button tıklanınca, en baştaki sayfaya yönlenilen “goHome()” methodu çağrılmaktadır.
- “<ion-tabs>” : team-home sayfasının üstünde 2 farkı daha sayfa bulunmaktadır. İlgili tabler tıklandığında “TeamDetailPage”
ve “StandingsPage”
page sayfalarından biri görünür hale gelir.
- tabTitle: Sayfanın altında görülen ve tabin üstünde yazan başlık kısmıdır. İlki “Team“, ikincisi “Standings“‘dir.
- [root] : Tıklandığında gösterilecek olan sayfayı belirtir.
- [rootParams]: Tab’e tıklandığında, ilgili sayfaya gidilecek olan parametre bu property ile tanımlanır. Bu sayfada ilgili parametre, tıklanan takım yani “team“‘dir. Not: Bu da bize, 2 sayfa arasında yönlenme yani navigasyon zamanı, sayfalar arasında parametre geçişinin nasıl olduğunu gösterir.
- tabIcon : İlgili tab’de görünmesi istenen ikon burada tanımlanır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<ion-header> <ion-navbar color="primary"> <ion-title>{{team.name}}</ion-title> <ion-buttons end> <button (click)="goHome()"> <ion-icon name="home"></ion-icon> </button> </ion-buttons> </ion-navbar> </ion-header> <ion-tabs> <ion-tab tabTitle="Team" [root]="teamDetailTab" [rootParams]="team" tabIcon="basketball"></ion-tab> <ion-tab tabTitle="Standings" [root]="standingsTab" [rootParams]="team" tabIcon="podium"></ion-tab> </ion-tabs> |
team-home.ts:
- “this.team=this.navParams.data” ile sayfaya önceden parameter olarak gönderilen takım bilgisi aktarılır. NavParamsın sayfada tanımlanabilmesi için, ‘ionic-angular’ kütüphanesinden import edilmesi gerekmektedir.
- teamDetailTab ve standingsTab değişkenlerine ilgili sayfalar atanır. Ekelenecek “StandingsPage, TeamDetailPage, MyTeamsPage” ==> “../pages” altından sayfaya import edilir.
- “goHome()“: İlgili methodda “this.navCtrl.push(MyTeamsPage)” komutu ile gidilmeye çalışıldığında, ilgili ana sayfada geri ok tuşu görülmektedir. Halbuki ana sayfada geri ok tuşu görünmemesi gereken bir durumdur. Bunun üzerine ilgili navigasyon işlemi ==>”this.navCtrl.popToRoot()” şekilinde yapıldığında, doğrudan ana sayfaya gidilmekte ve geri ok buttonu görülmemektedir.
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 |
import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams } from 'ionic-angular'; import { StandingsPage, TeamDetailPage, MyTeamsPage } from "../pages"; @IonicPage() @Component({ selector: 'page-team-home', templateUrl: 'team-home.html', }) export class TeamHomePage { team:any; teamDetailTab=TeamDetailPage; standingsTab=StandingsPage; constructor(public navCtrl: NavController, public navParams: NavParams) { this.team=this.navParams.data; } public goHome(){ //this.navCtrl.push(MyTeamsPage); this.navCtrl.popToRoot(); } ionViewDidLoad() { console.log('ionViewDidLoad TeamHomePage'); } } |
Şimdi sıra geldi tablere ait sayfaları oluşturmaya. “ionic generate page team-detail” ve “ionic generate page standings” komutları ile ilgili sayfalar yaratılır.
team-detail.html:
- “Pull-Refresh” – “<ion-refresher>“: “<ion-refresher (ionRefresh)=”refreshAll($event)”>” Meşhur :) sayfanın en tepesinde iken, ekranın aşağı doğru çekilerek datanın yenilenmesi işlemidir. Sayfa üzerindeki datanın yenilenmesi için “(ionRefresh)” eventindeki “refreshAll()” methodu çağrılır.
- “<ion-card>”: Yukarıda görüldüğü gibi 3 boyutlu plate bir yüzeyin oluşmasını sağlayan bir elementtir.
- “<ion-card-content>”: İlgili içeriğin yazılacağı containerdır. Bu örnekde “*ngIf=”teamStanding!=undifined”” ile “teamStanding” değişkenine birşeyler atanmış ise, score bilgisinin ekrana basılması sağlanmıştır. Böylece hatadan da kurtulunmuş olunur. Aksi takdirde null nesne ekrana basılmaya çalışıldığında, hata alınılması kaçınılmazdır.
- “<ion-row>” : Aynı Html Table’da olduğu gibi sayfa bir satırın basılacağını bildirir.
- “<ion-col>”: Sayfaya ilgili satır içinde kolon basılacağını belirtir. “width-50” tanımlaması, toplam satır genişliğini yarısının bu kolon tarafından kaplanacağını belirtir.
- “Record: {{teamStanding.wins}}–{{teamStanding.losses}}“: Takımın toplam kazandığı ve toplam kaybettiği maç sayısı ekrana basılır.
- “Coach: {{team.coach}}” : Takıma ait antrenör bilgisi, ekrana basılmaktadır.
- “<button outline (click)=”toggleFollow()” *ngIf=”!isFollowing”>” 2. bir kolon açılıp, yukarıda görüldüğü gibi favorilere ekle buttonu, eğer bu takım favorilere eklenmemiş(!isFollowing) ise gösterilir. Tıklama durumunda “toggleFollow()” methodu çağrılır. Son olarak “Add Favorite” yazısı ekrana basılır.
- “<button (click)=”toggleFollow()” *ngIf=”isFollowing”>” : Eğer takım takip ediliyor ise, o zaman da takibi bırak işlemi yapılacak button sayfaya basılır.
- IONIC – Filter: Yukarıda görüldüğü gibi Tarihe göre bir filitreleme işlemi yapılmıştır.
- “<ion-item>” : Sayfaya gurup halinde bir nesne topluluğu konucağı zaman, kapsayıcı containerın ta kendisidir.
- “<ion-label>” : Text alanın yazılacağı labeldır.
- “ion-toggle” : Sayfaya konan bir switch buttondur. “useDataFilter” değişkenine çift yönlü bağlanmıştır. (ionChange) eventinde, birazdan inceleyeceğimiz “dataChanged()” methodu çağrılmış ve yapılacak maçların listelendiği datanın tarihe göre filitrelenmesini veya filitrenin kaldırılmasını sağlanmıştır.
- “<ion-datetime>” : İlgili tarih elementi belli bir display Formatında yani “Ay/Gün/Yıl” görünümünde “dataFilter” değişkenine çift yönlü bağlanıp “(ionChange)” eventinde, yani değişme durumunda “dateChanged()” methodu çağrılmıştır. “([disabled])=”!useDateFilter”” tanımlaması ile, hemen yukarısında tanımlanan toggle switch değerine göre, ilgili tarih filitresi aktif veya pasif hale getirilmiştir.
- “<ion-item *ngFor=”let game of games” (click)=”gameClicked($event,game)”>” Çekilen oyun datası gezilerek ekrana basılır. Tıklanma durumunda “Game” sayfasına gidilir. Maç bilgileri yukarıda görüldüğü gibi 3 kolon olarak ekrana basılır.
- “<ion-row> ve <ion-col>” ile ilk satır ilk kolona, maç tarihi “{{game.time | date:’M/d/yy’}}” ve tarihin kısa hali “{{game.time | date:shortTime}}” formatında basılır. İlgili datanın yanına “|” ile konan tanımlama, Angular 4 tarafında pipes yani eski adı ile filter olarak adlandırılmaktadır.
- ” <p>{{game.homeAway}} {{game.opponent}}</p>” 2. kolona takım ve rakip takım yazılır. Hemen altına “{{game.location}}” yani maçın oynanacağı lokasyon belirtilir.
- “<h4>{{game.scoreDisplay}}</h4>” Son kolona da maç skoru yazılır.
- “<ion-badge [color]=”getScoreDisplayBadgeClass(game)”>{{getScoreWorL(game)}}</ion-badge>” Yukarıda yazdırılan skorun yanına, kazanılıp kaybedildiğini gösteren logo, “getScoreWorL()” methodu ile konturol edilip, yukarıda görüldüğü gibi ekrana kırmızı veya mavi logo şeklinde bastırılır.
- Son olarak tıklanınca “goHome()” methodu ile ana sayfaya dönülen “Go Home” button’u konur.
team-detail.html:
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 60 61 62 63 64 |
<ion-header> <ion-navbar color="primary"> <!-- <ion-title>{{team.name}}</ion-title> --> </ion-navbar> </ion-header> <ion-content padding> <h2>Team Detail</h2> <ion-refresher (ionRefresh)="refreshAll($event)"> <ion-refresher-content> </ion-refresher-content> </ion-refresher> <!-- <h3>Name:{{team.name}}</h3> --> <ion-card> <ion-card-content *ngIf="teamStanding!=undifined"> <ion-row> <ion-col width-50> <h2>Record: {{teamStanding.wins}}--{{teamStanding.losses}}</h2> <p>Coach: {{team.coach}}</p> </ion-col> <ion-col width-50 text-right> <button outline (click)="toggleFollow()" *ngIf="!isFollowing"> <ion-icon name="star"></ion-icon> Add Favorite </button> <button (click)="toggleFollow()" *ngIf="isFollowing"> <ion-icon name="star"></ion-icon> </button> </ion-col> </ion-row> <ion-item> <ion-label>Select Date:</ion-label> <ion-toggle [(ngModel)]="useDateFilter" (ionChange)="dateChanged()"> </ion-toggle> <ion-datetime displayFormat="M/D/YYYY" pickerfORMAT="M/D/YYYY" [(ngModel)]="dateFilter" (ionChange)="dateChanged()" ([disabled])="!useDateFilter"></ion-datetime> </ion-item> </ion-card-content> </ion-card> <ion-list> <ion-item *ngFor="let game of games" (click)="gameClicked($event,game)"> <ion-row> <ion-col width-20> <p>{{game.time | date:'M/d/yy'}}</p> <p>{{game.time | date:shortTime}}</p> </ion-col> <ion-col width-60> <p>{{game.homeAway}} {{game.opponent}}</p> <p>{{game.location}}</p> </ion-col> <ion-col width-20> <h4>{{game.scoreDisplay}}</h4> <ion-badge [color]="getScoreDisplayBadgeClass(game)">{{getScoreWorL(game)}}</ion-badge> </ion-col> </ion-row> <!-- {{game.opponent}} --> </ion-item> </ion-list> <button (click)="goHome()">Go Home</button> </ion-content> |
team-detail.ts: Aşağıda görüldüğü gibi takım detay sayfasında maç score’u, yaptığı ve yapacağı maçlar, ilgili takımı favorilere ekleme ve tarihiye göre maçları filitreleme işlemleri yapılmaktadır.
- “allGames[]“: Tüm maçların tutulduğu listedir.
- “dateFilter”: Filitreleme amaçlı seçilen tarih bilgisini tutar.
- “games“: Tarihe göre filitreleme işleminden sonra, tutlan maçların bilgisidir.
- “isFollow” : İlgili takımın takip edilip edilmediğini tutan boolen değişkendir.
- “team” “NavParams” ile filitrleme amaçlı gönderilen oyun datası bu değişkende tutulur.
- “teamStandings” : Kazanılan, kaybedilen maç sayısı ve antrenör bilgilerinin tutulduğu data modeldir.
- “tourneyData” [ ]: Seçilen turnuvaya ait tüm maç bilgisinin tutulduğu dizidir.
- “useDateFilter“: Tarih seçildiği zaman, “true” değerini alani buna göre bir filitreleme olduğu anlamına gelen boolen bir değişkendir.
Şimdi gelelim kullanılan kütüphanelere:
- “NavParams“: Başka bir sayafadan gelinirken parametre almak, ya da başka bir sayfaya yönlenmek ve son olarak bulunan sayfadan başka bir sayfaya parametre gönderebilmek için kullanılır.
- “EliteApi“: Firebase olarak adlandırılan, ilgili Database’den verileri çekmek için kullanılan servisdir.
- “AlertController“: Sayfaya Alert ve Confirm pencereleri çıkartmak için kullanılır.
- “ToastController” Sayfanın altından belli zaman aralığında bildirim göndermek için kullanılır.
“ionViewDidLoad()” : Zamanında :
- “this.team = this.navParams.data;” : Parametre olarak gönderilen takım bilgisi alınır.
-
“this.tourneyData = this.eliteApi.getCurrentTourney();” İlgili method ile önceden çekilmiş olan bu takımın bulunduğu turnuva maçları, ilgili diziye aktarılır.
-
Lodash : Javascript için yazılmış, popüler bir utility kütüphanesidir. Array yani diziler, object ve string değerler için kolayca iterasyon ve manipülasyon işlemlerinin yapılmasını sağlayan, helper classları sayesinde linq şeklinde kod yazmamıza yardımcı olan çok faydalı bir kütüphanedir. “.npm install lodash –save” şeklinde projeye yüklenir. Sayfaya import işlemi ==>”import * as _ from ‘lodash’;” şeklinde yapılır. Peki neden kullanıyoruz? Gelin aşağıdaki örnek ile inceleyelim:
- “this.games =_.chain(this.tourneyData.games)” : Yukarıda görüldüğü gibi belli bir ID’ye göre çekilen Turnuva bilgilerinden games nodu, bir array haline getirilir. Yani herbir games nodu tekbir nod haline gelir.
- “.filter(g => g.team1Id === this.team.id || g.team2Id === this.team.id)” : Method ile aynı Linq’de olduğu gibi 1. veya 2. takım ID değeri, seçilen bu takımın ID’sine eşitse, yani seçilen takıma ait tüm maçlar getirilir.
- .map(): Observer method ile yenen ve yenilen takımın belirlenmesi için kullanılır:
- “let isTeam1 = (g.team1Id === this.team.id);” seçilen takımın, ilk takım olup olmadığına bakılır.
- “let opponentName = isTeam1 ? g.team2 : g.team1;” : Rakip takım ismi, isTema1 değişkenine göre team1 ve team2’den hangisinin olduğuna karar verilir.
- “let scoreDisplay = this.getScoreDisplay(isTeam1, g.team1Score, g.team2Score);” : İlgili parametrelere göre score bilgisi, ilerde incelenecek olan “getScoreDisplay()” methodu ile ekrana basılır.
- Yukarıda tanımlanan Games sınıfına ait “id, opponentName, time, g.location, locationUrl, scoreDisplay, homeAway” alanlarına ilgili değeler atanır. Ve ==> filitrelenen tüm oyunlar, “this.allGames” değişkenine atanır.
- “this.teamStanding = _.find(this.tourneyData.standings, { ‘teamId’: this.team.id });” : Seçilen takıma ait Turnuva bilgilerinden standings bilgisi, seçilen takımın team.id’sine göre filitrelenir. Kısacası ilgili takımın puan sıralaması bulunur.
- “this.userSettings.isFavoriteTeam(this.team.id).then(value => this.isFollowing = value);” : Seçilen takıma ait ID bilgisi ile, “userSettings.isFavoriteTeam()” methodu kullanılarak, ilgili takımın takip edilip edilmediği bilgisine bakılır ve “isFollowing” değişkenine boolen bir değer atanır.
- getScoreDisplay(): İlgili method da amaç, oynanmış maçların scorelarını ve seçilen takımın kazanıp kazanamadığını göstermektir.
- “isTeam1” : Seçilen takımın, ilgili maçta ilk mi yoksa ikinci takım mı olduğunun belirlendiği değişkendir.
- “var teamScore= (isTeam1?team1Score:team2Score);” : Takımın score’u, parametre olarak gelen “isTeam1” değişkenine göre atanır.
- “var opponentScore = (isTeam1 ? team2Score : team1Score); ” : Rakip takımın score’u belirlenir.
- “var winIndicator = Number(teamScore) > Number(opponentScore) ? “W: ” : “L: “;” : Seçilen takımın kazanma durumuna göre “W” kaybetme durumuna göre “L” şeklinde sembolünün gözükmesi sağlanır.
- “winIndicator = Number(teamScore) === Number(opponentScore) ? “-: ” : winIndicator;” : Beraberlik durumu da :) bu şekilde “-” tanımlanmıştır.
- goHome(): Ana Sayfaya yönlenmek için kullanılır. Burada durum biraz farklıdır. Tab yapılarda root’a kadar çıkıp ordan yönlenme işlemi yapılmalıdır. Yanda görülen “.parent” bu işe yaramaktadır=>”this.navCtrl.parent.parent.push(GamePage, sourceGame);” Bunun yerine bu kodu da denemenizi tavsiye ederim==>”this.navCtrl.push(GamePage, sourceGame);” Nasıl yanlış bir durumla karşılaşıldığına şahit olacaksınız.
- gameClicked(): Bir maça tıklandığında, maça ait sayfaya gitmek için tıklanır.
- “let sourceGame = this.tourneyData.games.find(g => g.id == game.gameId);” : Tıklanan maça ait data, “ID” değerine göre filitrelenip “sourceGame” değişkenine atanır.
- “this.navCtrl.parent.parent.push(GamePage, sourceGame);” : Çekilen maç datası, “GamePage” sayfasına parametre olarak gönderilir.
Ionic Tarih İşlemleri:
Ben bu projede moment.js kütüpahenesini kullandım. Moment kütüphanesi == > “npm install moment –save” komutu ile kurulur.
- dateChanged() : Filitreleme amaçlı tarih seçildiği zaman (ionChange) event’i tetiklenir ve bu method devreye girer .
- “if(this.useDateFilter)” : İlgli switch’in açık olup olmadığına bakılır.
- “this.games = _.filter(this.allGames, g => moment(g.time).isSame(this.dateFilter, ‘day’));” : Lodash “_” ile filitreleme yapılırken, seçilen turnuvaya ait çekilen maçlar(allGames) içindeki her bir maçın zamanının, “g.time” == “isSame()” methodu ile seçilen tarihteki “this.dateFilter” değer ile gün cisinden “day” aynı olanlar ==>”games” [ ] dizisine atılır.
- Eğer “this.useDateFilter” switch’i açılmamış ise, yani tarih için bir filitreleme yok ise tüm data “games” [ ] dizisine atanır.
- getScoreWorL(): Projenin en kolay functionı :) Tek amacı, maça ait bir score var ise “game.scoreDisplay” bilgisini dönmek, yok ise boş ” ” bir string dönmektir.
-
getScoreDisplayBadgeClass() : Amaç takım kaybetmiş ise “danger” yani kırmızı, kazanmış ise “primary” yani mavi ve berabere ise gri yani “light” bir css rengi geriye dönmektir. Yukarıda belirtildiği gibi, maça ait “game.scoredisplay” propertsi içinde “W” veya “L” geçmesine göre kazanılıp kaybedildiği anlaşılmaktadır.
-
Ionic 2 Pull Requests
- refreshAll() : “this.eliteApi.refreshCurrentTourney()” Seçilen turnuvadaki tüm maç bilgisi, offline yerine servis ile databaseden tekrardan çekilir. Datanın çekildikten sonra “subscribe(() => {” dönen yükleniyor işareti yani refresher kapatılır ==>”refresher.complete()“. Sayfaya ilk gelindiğinde, yükleme işlemi tamamlandığı an çağrılan “ionViewDidLoad()” methodu tekrardan çağrılarak, yeni çekilen datanın ekrana basılması sağlanır.
-
“toggleFollow()” : Takım Detay sayfasında ilgili takımı ya favorilere eklemek ya da favorilerden çıkarmak için kullanılır. Bu iki duruma göre çalışacak aksiyonlar farklıdır.1. Durum Takibi Bırakma ==>”if (this.isFollowing) {” :
AlertController : Yukarıda görüldüğü gibi, sayfa üzerinde uyarı amaçlı pencerelerin client’a gösterilmesi amacı ile kullanılır. Bu durumda ilgili takım favorilerden çıkarılmak istendiğinde, “Takibi bırakmak istediğinize emin misiniz?” sorusu çıkartılır. 3 property’si vardır.
“let confirm = this.alertController.create({” : Yanda görüldüğü gibi “Create()” methodu ile aşağıda görülen propertyler ile oluşturulur.
- 1-) “title: ‘Unfollow?’,” : Açılan pencerenin başındaki başlık.
- 2-) “message: ‘Are you sure you want to unfollow?’,” : Ekranda görünecek uyarı mesajı.
-
3-) “buttons: [” : Ekranda görünecek buttonlar.
- “text:’Yes’” : İlk button text.
- “handler: () => {” : Tıklanma durumunda yapılacak işler. No cevabına basılmış ise:
- “this.isFollowing = false;” : Takip edilme işleminin sonlandığını belirten değişken.
- “this.userSettings.unforiteTeam(this.team);” : Servis tarafında ilgili method ile neler yapıldığı önceki yazılarda anlatılmıştır. 1-) Local Storage’dan ilgili takım çıkarılmıştır. 2-) Pub/Sub ==>Menüdeki favori takımlar arasından da çıkarılması için ilgili “favorites:changed” kanalına, “this.events.publish(‘favorites:changed’);” methodunun tetiklenmesi sağlanmıştır.
- ToastController : Yukarıda görüldüğü gibi, ekranın altından çıkrılan uyarı mesajları için kullanılırlar.
- “let toast = this.toastController.create({” : Yanda görüldüğü gibi “Create()” methodu ile aşağıda görülen propertyler ile birlikte oluşturulur.
- “message: ‘You have unfollowed ‘ + this.team.name,” : Gözükecek mesaj içeriği.
-
“duration: 2000,” : Ekranda kalma süresi.
- “position: ‘bottom’” : Sayfa üzerinde görüneceği yer.
- “toast.present();” : Uyarı mesajını gösteren komuttur.
- “let toast = this.toastController.create({” : Yanda görüldüğü gibi “Create()” methodu ile aşağıda görülen propertyler ile birlikte oluşturulur.
- Yes cevabına basılmış ise:
-
“this.isFollowing = true;” : Takip et değişkeni true atanır. Böylece takım ismi yanına yıldız şeklinde followe buttonu gözükür.
- “this.userSettings.favoriteTeam()” : Bu method, önceki makalede anlatıldığı gibi, favorilere eklenen takımı “Local Storage“‘a ekler. Ve “Pub/Sub Event” ile menü sayfasındaki listenin de triger edilerek değişmesini sağlar.
-
team-detail.ts:
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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams, AlertController, ToastController } from 'ionic-angular'; import * as _ from 'lodash'; import * as moment from 'moment'; import { GamePage } from "../pages"; import { EliteApi, UserSettings } from "../../shared/shared"; @IonicPage() @Component({ selector: 'page-team-detail', templateUrl: 'team-detail.html', }) export class TeamDetailPage { allGames: any[]; dateFilter: string; games: any[]; isFollowing = false; team: any; teamStanding: any; private tourneyData: any; useDateFilter = false; constructor(public navCtrl: NavController, public navParams: NavParams, private eliteApi: EliteApi, private alertController: AlertController, private toastController: ToastController, private userSettings: UserSettings ) { //this.team=this.navParams.data; console.log("data:", this.navParams); } ionViewDidLoad() { console.log('ionViewDidLoad TeamDetailPage'); this.team = this.navParams.data; this.tourneyData = this.eliteApi.getCurrentTourney(); this.games = _.chain(this.tourneyData.games) .filter(g => g.team1Id === this.team.id || g.team2Id === this.team.id) .map( g => { let isTeam1 = (g.team1Id === this.team.id); let opponentName = isTeam1 ? g.team2 : g.team1; let scoreDisplay = this.getScoreDisplay(isTeam1, g.team1Score, g.team2Score); return { gameId: g.id, opponent: opponentName, time: Date.parse(g.time), location: g.location, locationUrl: g.locationUrl, scoreDisplay: scoreDisplay, homeAway: (isTeam1 ? "vs." : "at") }; }) .value(); this.allGames = this.games; this.teamStanding = _.find(this.tourneyData.standings, { 'teamId': this.team.id }); this.userSettings.isFavoriteTeam(this.team.id).then(value => this.isFollowing = value); } getScoreDisplay(isTeam1, team1Score, team2Score) { if (team1Score && team2Score) { var teamScore = (isTeam1 ? team1Score : team2Score); var opponentScore = (isTeam1 ? team2Score : team1Score); var winIndicator = Number(teamScore) > Number(opponentScore) ? "W: " : "L: "; winIndicator = Number(teamScore) === Number(opponentScore) ? "-: " : winIndicator; return winIndicator + teamScore + "_" + opponentScore; } else { return ""; } } public goHome() { this.navCtrl.parent.parent.popToRoot(); //this.navCtrl.push(GamePage, sourceGame); } public gameClicked($event, game) { /* console.log(JSON.stringify(game)); */ let sourceGame = this.tourneyData.games.find(g => g.id == game.gameId); /* console.log("Source:" + JSON.stringify(sourceGame)); */ this.navCtrl.parent.parent.push(GamePage, sourceGame); } dateChanged() { if (this.useDateFilter) { this.games = _.filter(this.allGames, g => moment(g.time).isSame(this.dateFilter, 'day')); } else { this.games = this.allGames; } } getScoreWorL(game) { return game.scoreDisplay ? game.scoreDisplay[0] : ''; } getScoreDisplayBadgeClass(game) { let css: string; css = game.scoreDisplay.indexOf('W:') === 0 ? 'primary' : (game.scoreDisplay.indexOf('L:')!=-1 ? 'danger' : 'light'); return css; } refreshAll(refresher){ this.eliteApi.refreshCurrentTourney().subscribe(()=>{ refresher.complete(); this.ionViewDidLoad(); }) } public toggleFollow() { if (this.isFollowing) { let confirm = this.alertController.create({ title: 'Unfollow?', message: 'Are you sure you want to unfollow?', buttons: [ { text: 'Yes', handler: () => { this.isFollowing = false; this.userSettings.unforiteTeam(this.team); let toast = this.toastController.create({ message: 'You have unfollowed ' + this.team.name, duration: 2000, position: 'bottom' }); toast.present(); } }, { text: 'No' } ] }); confirm.present(); } else { this.isFollowing = true; this.userSettings.favoriteTeam(this.team, this.tourneyData.tournament.id, this.tourneyData.tournament.name); } } } |
Şimdi gelin isterseniz, Ana sayfada tıklanan, yukarıda görülen “Find Your Tournament” buttonu ile gidilen “tournaments” sayfasını kodlayalım.
tournaments.html: Yukarıda görülen sayfa “ionic generate page tournaments” komutu ile oluşturulur. Tüm turnuva maçları firebase databaseinden aşağıdaki gibi çekilir. “https://elite-schedule-app-1bbf9.firebaseio.com/tournaments.json”
tournaments.html: Servisden çekilen turnuva dataları “tournaments[ ]” dizisine doldurulur ve her bir turnuva bilgisi gezilerek, turnuva ismi ekrana basılır. “(click)” tıklanma eventinde “itemTapped()” methodu ile o turnuvadaki takımların listelendiği “teams.html” sayfasına yönlenilir. Son olarak sayfanın sonuna, geri dönüş buttonu “goBack()” methodunu çağracak şekilde yerleştirilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<ion-header> <ion-navbar color="primary"> <ion-title>Select a Tournament</ion-title> </ion-navbar> </ion-header> <ion-content padding> <ion-list> <button ion-item *ngFor="let item of tournaments" (click)="itemTapped($event,item)"> {{item.name}} </button> <!-- <button ion-item (click)="itemTapped()"> Summer Show Down </button> --> </ion-list> <button ion-button icon-rewind (click)="goBack()"> <ion-icon name="rewind"></ion-icon> Go Back </button> </ion-content> |
tournaments.ts:
- “ionViewDidLoad()“: Methodunda en başta bir “loader” create edilir ve “present()” methodu ile gösterilir.
- “this.eliteApi.getTournaments()” : “tournaments [ ]” dizisi servisden dönen json turnuva datası ile doldurulur.
- “loader.dismiss();” : Yükleniyor uyarısı kaldırılır.
- “goBack()”: Methodunda “this.navCtrl.pop();” komutu ile en baştaki sayfaya gidilir. Dikkat edilmesi gereken “this.navCtrl.push(TeamsPage);” komutunun kullanılması durumunda, ana sayfada back buttonunun görünmesi durumu oluşacaktır. Bu nedenle tercih edilmemelidir.
- “itemTapped()”: Methodu ile “this.navCtrl.push(TeamsPage, tourney);” Teams.html sayfasına tıklanma durumunda, turnuva bilgisi de parametre olarak eklenip “TeamsPage” sayfasına yönlenilir.
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 |
import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams, LoadingController } from 'ionic-angular'; import { TeamsPage } from "../teams/teams"; import { EliteApi } from "../../shared/elite-api.services"; @IonicPage() @Component({ selector: 'page-tournaments', templateUrl: 'tournaments.html', }) export class TournamentsPage { tournaments: any; constructor(public navCtrl: NavController, public navParams: NavParams, private eliteApi: EliteApi, private loadingController: LoadingController) { } ionViewDidLoad() { let loader = this.loadingController.create({ content: 'Getting tournaments...', spinner:'circles' }); loader.present().then(() => { this.eliteApi.getTournaments().subscribe(result => this.tournaments = result, err => console.log(err), () => { console.log("ok"); loader.dismiss(); }); }); console.log('ionViewDidLoad TournamentsPage'); } public goBack() { //this.navCtrl.push(TeamsPage); this.navCtrl.pop(); } itemTapped($event, tourney) { this.navCtrl.push(TeamsPage, tourney); } } |
teams.html: Seçilen turnuvaya ait takımların yukarıda olduğu gibi listesinin görüldüğü ve filitrelendiği sayfadır.
Geldik bir makalenin daha sonuna. Bu makalede Ionic ile nerde ise yapamıyacağımız hiçbirşeyin olmadığını gördük. Bolca hayatımızda kullandığımız “pull-request”‘in hiç de düşünüldüğü kadar zor olmadığını gördük. Filitreleme, guruplama gibi işlemlerde “Lodash” kütüphanesinin işleri nasıl da kolaylaştırdığına şahit olduk. Uyarı mesajları, sayfanın altından çıkan bildirimlerin nasıl yapılacağı, tarihe göre filitreleme ve switch yapısı, “ion-card” ile 3 boyutlu bir paletin çıkarılması gene bu makalede gördüğümüz Ionic kapsamındaki önemli toolardan sadece bir kaçıydı.
Bir sonraki makalede “Team” sayfasında kullanılan ION-SEARCH ve performans artışında büyük önem taşıyan “Standigs” sayfasında kullanılan VIRTUAL SCROLL konuları detaylıca anlatılacaktır. Bir sonraki makalede görüşmek üzere hoşçakalın.
Kaynaklar: Pluralsight Steve Michelotti, https://ionicframework.com, https://github.com/ionic-team/ionic, Gaurav Saini’nin “Hybrid Mobile Development with Ionic” kitabından faydalandım.
Son Yorumlar