AngularJS 2 Nedir? Bölüm 3
Selamlar,
Bugün AngularJS2’de Control Rendering nesneleri üzerinde duracağız.
*ngIf : Aşağıdaki örnekde 2 farklı div bulunmaktadır. 1.de yapılacak işlerin listelendiği, diğeri de ise eğer liste boş ise “Yapılacak bir işin” olmadığının bilgisinin verildiği bir div dir.
app.component.ts: Aşağıdaki örnekde “*ngIf” ile yapılacak işlerin dizisi olan “toDos[]“‘un boyutuna bakılarak, varsa dizi elemanları gezilip ekrana basılır. Yok ise “Yapılacak Bir İşiniz Yok :)” mesajı ekrana basılır. Ayrıca ekrana bir de “Temizle” buttonu konulmuştur. “(click)” eventinde “clean()” methodu çağrılmıştır. İlgili method çağrıldığında “toDos[]” dizisi temizlenmekte ve bu listeyi kulanan”<ul>” list için hiçbir kayıt kalmamaktadır. “*ngIf” ile yapılan koşul sonucu “toDos[].length==0”, “true” dönmekte ve sonuç olarak ekrana “Yapılacak Bir İşiniz Yok” yazısı basılmaktadı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 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template:` <form (submit)="changeText()"> <b>Yapılacak İşler:</b> <input type="text" [(ngModel)]="doText"/> <button type="button" (click)="clean()">Temizle</button> <div *ngIf="toDos.length>0"> <ul> <li *ngFor="#job of toDos"> {{job}} </li> </ul> </div> <div *ngIf="toDos.length==0"> <center><h1><b>Yapılacak Bir İşiniz Yok :)</b></h1></center> </div> </form> ` }) export class AppComponent{ toDos=[]; doText:string=""; changeText() { if(this.doText!=""){ this.toDos.push(this.doText); this.toDos.forEach(job => { console.log(job); }); this.doText=""; } } clean(){ this.toDos=[]; } } |
[innerHTML] : Eğer string bir html’in render edilip sayfaya basılması isteniyor ise, aşağıdaki örnekde olduğı gibi div elementinin propertysi olarak “[innerHTML]” kullanılıp ilgili “title” string değişkeni buna atanmalıdır. Böylece ilgili html string, örneğin aşağıda “<h1></h1>” elementi render edilerek ekrana formatlı olarak basılması sağlanır.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template: `<div [innerHTML]="title"></div>` }) export class AppComponent { title:string; constructor(){ this.title='<h1>Bora Kaşmer ile Angular 2 JS e Hoş Geldiniz!</h1>'; } } |
[ngSwitch]: Örneğin belli koşullara göre ilgili Htmller ekrana basılacaktır. Aşağıdaki örnekde Genel ve Liste adında 2 farklı menü vardır.
- viewModel adındaki değişkene başta “general” değeri atanmıştır. Bu değişken “general” iken Genel menü, “list” iken Liste menü ekrana basılacaktır.
- “[ngSwitch]” ile ilgili koşul aşağıdaki gibi tanımlanır. Örneğin “viewModel==’general'” olması ile genel menü ekrana basılır.
- “<a (click)>” eventinde “viewModel=’general'” şeklinde ilgili menüye ait olan değer atanmakta ve böylece seçilen listenin gözükmesi sağlanmaktadır.
- “ngSwitchWhen“=’general’ şeklinde ilgili koşulun seçenekleri belirlenmekte ve hangisi sağlanır ise o sayfaya render edilmektedir.
- Bu örnekde viewModel’e default olarak viewModel=’general’ şeklinde başlangıç değer atanmasından dolayı, gerek olmasa da “ngSwitchDefault” ile hangi şartın baştan sağlanacağı belirlenmiştir.
- Son olarak [class.active]=”viewModel==’general’” ile ilgili koşulu sağlıyan list item’in css’i değiştirilmiş ve içi dolu olarak menüde gözükmesi sağlanmıştır.
- Buradaki en önemli konu [ngSwitchWhen] koşulunu sağlanmayan “Html” ekrana kesinlikle render edilip basılmaz. Bu da büyük performans sağlar.
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 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template: `<div [innerHTML]="title"></div> <ul class="nav nav-pills"> <li [class.active]="viewModel=='general'"><a (click)="viewModel = 'general'">Genel</a></li> <li [class.active]="viewModel=='list'"><a (click)="viewModel = 'list'">Liste</a></li> </ul> <h1><font color='red'> <div [ngSwitch]="viewModel"> <template [ngSwitchWhen]="'general'" ngSwitchDefault>Genel Görünüm</template> <template [ngSwitchWhen]="'list'">Liste Görünüm</template> </div> </font></h1> ` }) export class AppComponent { viewModel='general'; title:string; constructor(){ this.title='<h1>Bora Kaşmer ile Angular 2 JS e Hoş Geldiniz!</h1>'; } } |
Pipes: AngularJS 1.0’deki filter karşılığıdır. Örneğin, derleme zamanı pipe’lar aşağıda gösterilmiştir. Burada amaç, sayfaya basılan data üzerinde bir takım işlemler yapmaktır. Yani bir çeşit alınan verinin functional bir operasyondan geçirip ekrana basılmasını sağlayan küçük macrolardır.
Aşağıdaki örnekte bir “product”‘a ait çeşitli özellikler listelenmiştir.
- “| upper” ekranan basılan string metnin büyük harfle basılmasını sağlar.
- “| number” ilgili sayısal verinin bindelik oranla ayraçlı yazılmasını sağlar.
- “| number:[tamsayı max basamak sayısı].[ondalık max basamak sayısı]-[ondalık min basamak sayısı]”=> number:2:2-2: Sayısal formatı
- “| currency: ‘Para Birimi’:Symbol mü?:[tamsayı max basamak sayısı].[ondalık max basamak sayısı]-[ondalık min basamak sayısı]”: Para formatı.
- “| date:’dd MMM yyyy'”: Tarih formatı
- “| json”: Tüm datayı ya da object’i, json olarak ekrana basar. Örneğin aşağıda product nesnesi json olarak bası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 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template:` Name: {{ product.name | uppercase}} <br/> Dpi: {{ product.dpi | number }} <br/> Rating: {{ product.rating | number:'2.2-2' }} <br/> Price: {{ product.price | currency: 'TRY':true:'2.2-2' }} <br/> Date: {{ product.releaseDate | date:'dd MMM yyyy' }} <br/> {{product | json}} ` }) export class AppComponent{ product={ name:"mx anywhere 2 mouse", rating: 4.5678, price:207.55, dpi:1600, releaseDate:new Date(2016,5,18) } } |
Custom Pipe: Burada amaç var olan hazır pipelar iş görmediği zaman, ihtiyaca göre özel bir pipeın yazılmasıdır. Aşağıdaki örnekte bir blog yazısına ait başlık ve final bölümü bulunmaktadır. Amaç final bölümünü bizim belirlediğimiz bir karakter sayısında sonlandırmak yani kısaltarak sona … koymaktır. Bu amaçla “| finish” özel pipe’ı kullanılmıştır.
app.componenet.ts:
- Yazılacak custom finish.pipe filter sayfaya tam yolu belirtilerek import edilir.
- @Componenet içerisine render zamanı, ilgili pipe’ın anlaşılabilmesi için “pipes:” property’si eklenip kullanılacak “[FinishPipe]” burada tanımlanır.
- İlgili blog yazısı ” | finish:30″ ile filitrelenip istenen, yani belirtilen “30” karaktere kadar kısaltılması sağlanır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import {Component} from 'angular2/core'; import {FinishPipe} from './finish.pipe' @Component({ selector: 'my-app', template:` <h1>{{ blog. title }}</h1> <br/> {{ blog.final | finish:30}} `, pipes:[FinishPipe] }) export class AppComponent{ blog={ title:"Angular2 Nedir?", final:`Böylece bir makalenin daha sonuna geldik. AngularJS2 makalelerinin devamında görüşmek üzere hoşçakalın. ` } } |
finish.pipe.ts: Kullanılacak Pipe ve PipeTransform tipleri import ile tanımlandıktan sonra “FinishPipe” sınıfı “PipeTransform” interface’inden türetilmiştir. “transform()” methodu override edilerek parametre alınmış ise ilgili parametre sayısına kadar alınmamış ise default 20 karaktere kadar kısaltma işlemi yapılmaktadır.
1 2 3 4 5 6 7 8 9 10 11 12 |
import {Pipe,PipeTransform} from 'angular2/core'; @Pipe({name:'finish'}) export class FinishPipe implements PipeTransform{ transform(value:string,args:string[]){ var limit=(args && args[0]) ?parseInt(args[0]):20; if(value){ return value.substring(0,limit)+"..."; } } } |
Sonuç Ekranı: Aşağıda görüldüğü gibi sonuç yazısı custom pipe’da belirtilen’30’ karakter ile sınırlandırılmıştır.
Custom Pipe 2 Değişime Zorlamak (Önemli):
Filter.pipe.ts: Aşağıdaki pipe’da girilen data, başlangış harfi parametre olarak belirtilmiş ise ilgili harf ile başlayan işler “item.work”‘e göre filitreleme işlemine tabi tutulmuştur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import {Pipe} from 'angular2/core'; @Pipe({ name:"filter" }) export class FilterPipe { transform(value,args:string[]){ var filterKey=(args && args[0]) ?args[0]:''; if(value) { return value.filter((item)=>item.work.startsWith(filterKey)); } } } |
loop.component.ts:
- Aşağıdaki directive’de yapılacak işler “*ngFor” ile dönülüp ekrana basılmaktadır. Pipe olarak “| filter:’b” yazılmıştır. Yani ekrana yazılacak işler b ile başlıyan işler olacaktır.
- Sayfaya “import {FilterPipe}” ilgili dosya yolu gösterilir.
- @Component içerisine property olarak “pipes:[FilterPipe]” eklenmiştir. Böylece ilgili pipe render sırasında tanımlanabilecektir.
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 |
import {Component,Input,Output,EventEmitter} from 'angular2/core' import {FilterPipe} from './filter.pipe' @Component({ selector: 'loop', template:` <style> .completed{ text-decoration:line-through; } </style> <ul> <li *ngFor="#job of toDos | filter:'b'"> <span [ngClass]="job.state">{{job.work}}</span> <button type="button" (click)=addList(job)>Bitti</button> </li> </ul> `, pipes:[FilterPipe] }) export class LoopComponent{ @Input() toDos; @Output() done=new EventEmitter(); doneList=[]; addList(item){ item.state="completed"; this.doneList.push(item.work); this.done.emit({DoneList:this.doneList}); console.log(this.doneList); } } |
Önemli: Şimdi bu durumda, içinde gezilen “toDos[]” dizisine her bir yeni eleman eklendiğinde malesef pipe bundan etkilenmez ve hiç bir kayıt ekrana basılmaz. Yani Pipe toDos[] dizisi içindeki değişimi dinlememektedir. Bu durum, AngularJs 1’e göre performans arttırma amaçlı yapılmış bir iştir. Bu durumuda Pipe’ın yeni data girişini algılaması ve değişimin zorlanması için, “toDos[]” dizisinin bir eşleniğinin çıkarılması ve bu yeni dizinin içerisinde “Pipe” işlemi yapılması gerekmektedir.
Aşağıdaki AppComponent sınıfında “this.toDos=[…this.toDos,toDo]” şeklinde ilgili “toDos” dizisinin bir eşleniği çıkarılmış ve yeni item “toDo” diziye eklenmiştir. Böylece ilgili yeni diziye göre Pipe filitreleme işlemini, var olan değişimi algılayıp yapabilmiştir.
app.component.ts: Önceki makaledeki örnek burada filter özelliği de eklenerek daha da geliştirilmiş ve Custom Filter’ın dizide olan değişiklikten etkilenmesi, dizinin yeni eşleniğinin olışturulması ile mümkün kılınmış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 60 61 62 63 64 65 |
import {Component} from 'angular2/core'; import {LoopComponent} from './loop.component'; @Component({ selector: 'my-app', directives:[LoopComponent], template:` <form (submit)="changeText()"> <b>Yapılacak İşler:</b> <input type="text" [(ngModel)]="doText"/> {{doText}} <loop [toDos]="toDos" (done)="doneJobs($event)"></loop> <hr> <b>Biten İşler:</b> <ul> <li *ngFor="#dn of doneJob"> {{dn}} </li> </ul> </form> ` }) export class AppComponent{ toDos=[]; doText:string=""; doneJob; changeText() { if(this.doText!=""){ console.clear(); var toDo=new ToDo(); toDo.state="start"; toDo.work=this.doText; this.toDos=[...this.toDos,toDo]; //this.toDos.push(toDo); this.toDos.forEach(job => { console.log(job.work); }); this.doText=""; } } doneJobs($event) { this.doneJob=$event.DoneList; console.log("Biten işler:"+JSON.stringify($event)); } } export class ToDo { private _work : string; public get work() : string { return this._work; } public set work(v : string) { this._work = v; } private _state : string; public get state() : string { return this._state; } public set state(v : string) { this._state = v; } } |
ngStyle: Modelden gelen koşula göre ilgili css’in değişmesi sağlanır. Aşağıdaki örnekte “styleType” modelinin değerine göre ekrana basılan button sitili değişmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template:` <button [ngStyle]="{ backgroundColor: styleType=='Wild' ? 'green' : 'blue', color: styleType=='Wild' ? 'yellow': 'white', fontWeight: styleType=='Wild' ? 'bold': 'normal' }" >Gönder</button> ` }) export class AppComponent{ styleType="Wild" } |
Genel Bir Örnek: Aşağıdaki örnekde konu başlıkları ve tıklandığında detayları gözüken bir blog sayfası yazılmıştır. Amaç bir html element’e “[ngClass]” ile belli bir modele bağlı olarak sitil tanımlamak ve yine aynı model’e göre “*ngIf” ile ilgili “<ng-content>“‘in gösterilmesini ya da gizlenmesini sağlamaktır.
BlogComponent.ts: Öncelikle aşağıdaki BlogCompenent directive’i tanımlanır.
- “BlogComponent” sınıfında “isExpanded” değişkeni, akordion şeklinde ilgili title tıklanınca detayın açılıp kapanmasını sağlamaktadır.
- @Component altında ilgili css’ler “styles:” property’si ile tanımlanmıştır.
- “title” directive içine “input” olarak tanımlanmıştır. Yani directive’in kullanılacağı yerde, title bilgisi parametre olarak dışardan verilecektir.
- “<ng-content>” ile, ilgili directive yani blog içerisine yazılacak metinin container’ı tanımlanmaktadır.
- “[ngClass]” ile title divine ilgili bootstrap css’i “isExpanded” değişkenine göre farklı atanmaktadır.
- “div” içerisine yazlacak “<ng-content>“‘in görünüp görünmeyeceği “*ngIf” ile yine “isExpanded” değişkenine bağ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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
import {Component,Input} from 'angular2/core'; @Component({ selector: 'blog', styles: [` .blog { border: 1px solid #ccc; border-radius: 2px; } .blog .blog-title { padding: 20px; font-weight: bold; } .blog .blog-title:hover{ background: #f0f0f0; cursor: pointer; } .blog .blog-content { padding: 20px; } `], template:` <div class="blog"> <div class="blog-title" (click)="toggle()"> {{ title }} <i class="pull-right glyphicon" [ngClass]=" { 'glyphicon-chevron-down': !isExpanded, 'glyphicon-chevron-up': isExpanded }"> </i> </div> <div *ngIf="isExpanded" class="blog-content"> <ng-content></ng-content> </div> </div> ` }) export class BlogComponent{ isExpanded=false; @Input() title: string; toggle(){ this.isExpanded = !this.isExpanded; } } |
app.component.ts: Blog yazılarının içine yazılacağı “BlogComponent” directive’i “import” ile sayfaya tanımlanmakta ve 3 blog yazısına ait title ve detay bilgileri, aşağıda görüldüğü gibi yazılmaktadır..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import {Component} from 'angular2/core'; import {BlogComponent} from './BlogComponent'; @Component({ selector: 'my-app', directives:[BlogComponent], template:` <blog title="Angular2 Konu:ngStill"> ngStill ile alakalı Güzel bir örnek. </blog> <blog title="Angular2 Konu:ngClass"> Bootstarp css'leri model'e bağlı atama. </blog> <blog title="Angular2 Konu:*ngif"> Belirli bir koşula göre ilgili elementi gösterme </blog> ` }) export class AppComponent{ } |
Böylece geldik bir makalenin daha sonuna. Yeni bir angular 2 makalesinde 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) …
Bu örnekleriniz tanıtımlarınız için çok teşekkür ederim. Bir çok konularda sizin yaptığınız örneklere, yazılarınıza bakıyorum.
çok teşekkürler devamını merakla bekliyorum
Ben teşekkür ederim Erhan. Devamı da var. Bloğumdan aşağıdaki linklerden erişebilirsiniz.
İyi çalışmalar.
Hey mate, I’m trying to do debugging with vscode with angular2-seed, could you share you github proejct code and launch.json files. Would appreciate really! Love your work here on the blog.
Hi Piyush,
Thank you for your appreciation. I spend lots of time for my blog.
Here is the source code : http://www.borakasmer.com/projects/angular2_project.rar
Good Days..