AngularJS 2 Nedir? Bölüm 2
Selamlar,
Bugün önceki makalede anlatılan AngularJS2 konusuna kaldığımız yerden örnekler ile devam edeceğiz.
Property Binding:
Aşağıda görüldüğü gibi img kaynağının farklı bağlanış şekilleri görülmektedir. 3’ü de aynı işi ve tek yönlü yani one way binding olarak bağlanmıştır. Kısaca modelde yani datada olan değişiklik Html Element’e yansır iken, elementde olan değişiklik modele yansımaz.
- img src=”{{ imgUrl }}”
- img [src]=”imgUrl”
- img bind-src=”imgUrl”
Aynı şekilde <h1> elementine aşağıdaki gibi one way binding yapılmıştır. Bunun için “[textContent]” property’si kullanılmıştır.
- <h1><font color=red> {{ title }}</font> </h1>
- <h1 [textContent]=”title”></h1>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template:<h1><font color=red> {{ title }}</font> </h1> <h1 [textContent]="title"></h1> <img src="{{ imgUrl }}"/> <img [src]="imgUrl"/> <img bind-src="imgUrl"/> ` }) export class AppComponent{ title="Bora Kasmer AngularJs 2 Blog"; imgUrl="http://www.borakasmer.com/wp-content/uploads/2014/09/me.png" } |
Class Binding: Css özelliği model’e bağlanılarak, modelin ‘[class.Active]=isActive’ değeri ile button’un active veya pasif olması sağlanır. Kısaca belli bir koşula göre css’i model’e bağlıyarak değiştirebiliriz.
1 2 3 4 5 6 7 8 9 10 11 12 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template:` <button class="btn btn-primary" [class.Active]="isActive">Gönder</button> ` }) export class AppComponent{ isActive=true; } |
Event Binding : Aşağıdaki örnekte “(click)” event’inde “writeText()” methodu çağrılmıştır. Input’un [value] özelliğine “txtValue” değişkeni atanmıştır. İlgili AppComponent sınıfı içinde ‘Bora KASMER’ olarak tanımlı “txtValue“, one way binding olduğu için textbox’ın içine ilgili isimin yazılmasına karşın, textbox’ın içeriğinin değiştirilmesi durumunda model bundan etkilenmez. Kısacası console.log’a her zaman ‘Bora KASMER’ yazılır. Ayrıca ilgili ‘$event‘ parametre ile methoda() gönderilmiştir.
Not: AngularJS2’de Eventler “( )” parantez ile propertyler “[ ]” köşeli parantezler ile tanımlanırlar.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template: ` <input type="text" [value]="txtValue"/> <button (click)="writeText($event)">Gönder</button> ` }) export class AppComponent { txtValue="Bora KASMER"; writeText(event) { console.log(this.txtValue+event); } } |
Two Way Binding: Aşağıdaki örnekde normalde kullanılmaması gereken uzun bir yol kullanılmıştır. <input> elementin “(input)” eventine “txtValue=$event.target.value” ile, text içerisinde yapılan her işlemin “txtValue“‘a da yansıtılması sağlanmıştır. Kısacası basılan her karakter modeli etkileyeceği için, bu modeli kullanan heryer bu değişimden etkilenir. Böylece çift taraflı bağlantı yani two way binding sağlanmış olunur.
Bu işlemin yani two way binding işleminin kısa yolu için <input type=”text” [(ngModel)]=”txtValue”/> kullanılır. Böylece hem event hem property tek seferde bind edilmiş olunur.
Two way binding “[( )]” sembolleri arasında yapılır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template: ` <!--<input type="text" [value]="txtValue" (input)="txtValue = $event.target.value"/>--> <input type="text" [(ngModel)]="txtValue"/> <button (click)="writeText($event)">Gönder</button> Isim: {{txtValue}} ` }) export class AppComponent { txtValue="Bora KASMER"; writeText(event) { console.log(this.txtValue+event); } } |
Genel Örnek: Aşağıdaki örnekte yıldız tıklanıldığı zaman içi dolu, tekrar tıklanıldığı zaman içinin boş olması sağlanmıştır. [class.glyphicon-star] class’ı “!isFavorite” modeline bağlanmıştır. Yani Class Binding işlemi yapılmıştır. “(click)” eventinde “onClick()” methodu çağrılıp ilgili “isFavorite” değişkeni, var olan değernin tersi değerine atanmıştır. Böylece ilgili yıldızın için dolup sonra tekrar boşalmaktadır. Bu örnekle şimdiye kadar anlatılan “class-binding” ve “event-binding” konularına genel bir örnek verilmiştir.
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:` <i class="glyphicon" [class.glyphicon-star-empty]="!isFavorite" [class.glyphicon-star]="isFavorite" (click)="onClick()"> </i> ` }) export class AppComponent { isFavorite=false; onClick(){ this.isFavorite=!this.isFavorite; } } |
Genel Örnek 2: Aşağıdaki örnekde yapılacak işler “toDos[]” dizisine doldurulmaktadır. Formun “(submit)” eventinde “changeText()” methodu çağrılmaktadır. “Input” element 2 way binding şeklinde “[(ngModel)]” ile “doText“‘e bağlanmıştır. “changeText()” event’inde “toDos[]” dizisine, “doText” değeri atılır. Böylece “*ngFor” ile dönülen “toDos[]” dizisi içindeki elemanlar “<ul>” elementi içine basılı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 |
import {Component} from 'angular2/core'; @Component({ selector: 'my-app', template:` <form (submit)="changeText()"> <b>Yapılacak İşler:</b> <input type="text" [(ngModel)]="doText"/> {{doText}} <ul> <li *ngFor="#job of toDos"> {{job}} </li> </ul> </form> ` }) export class AppComponent{ toDos=[]; doText:string=""; changeText() { if(this.doText!=""){ console.clear(); this.toDos.push(this.doText); this.toDos.forEach(job => { console.log(job); }); this.doText=""; } } } |
@Input() ile Data Gönderme : Burada amaç tanımlanan bir directive’e parametre gönderebilmektir. Örneğin aşağıdaki örnekte “<loop>” directive’ine yapılacak işlerin dönüldüğü “toDos[]” dizisi parametre olarak verilmektedir. “<loop>” directive içinde ilgili değişken “@Input()” ile alınmaktadır. Ayrıca bu işlemin yapılabilmesi için, sayfanın başında “import (Input)”‘ kütüpahanesinin de dahil edilmesi gerekmektedir.
app.component.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 |
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"></loop> </form> ` }) export class AppComponent{ toDos=[]; doText:string=""; changeText() { if(this.doText!=""){ console.clear(); this.toDos.push(this.doText); this.toDos.forEach(job => { console.log(job); }); this.doText=""; } } } |
loop.componenet.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import {Component,Input} from 'angular2/core' @Component({ selector: 'loop', template:` <ul> <li *ngFor="#job of toDos"> {{job}} </li> </ul> ` }) export class LoopComponent{ @Input() toDos; } |
@Output ile Directive’e Gelen Datayı Geri Gönderme : Burada amaç, kullanılan directive’den parent’a bir bildirim geri döndürmektir. Aşağıdaki örnekte “<loop>” directive’inde işlerin yanına bir “Bitti” buttonu konmuş ve tamamlanan işlerin geri dönülmesi sağlanmıştır. Bunun için “done” adında output parametresi dönen bir event, “EventEmitter()” ile yaratılmış ve ilgili liste “DoneList” adında geri dönülmüştür.
@Output() done=new EventEmitter()
loop.componenet.ts(2): Sayfaya import ile “Output” ve “EventEmitter” eklenmiştir. Ayrıca “Bitti” button’u tıklanınca “addList()” methodu çağrılıp, tamamlanan adım yeni yaratılan “doneList[]” dizisine eklenmiş ve “done()” event’i “this.done.emit()” ile trigger edilerek gönderilmiştir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import {Component,Input,Output,EventEmitter} from 'angular2/core' @Component({ selector: 'loop', template:` <ul> <li *ngFor="#job of toDos"> {{job}} <button type="button" (click)=addList(job)>Bitti</button> </li> </ul> ` }) export class LoopComponent{ @Input() toDos; @Output() done=new EventEmitter(); doneList=[]; addList(item){ this.doneList.push(item); this.done.emit({DoneList:this.doneList}); console.log(this.doneList); } } |
app.component.ts(2): Biten işlerin listelendiği yeni bir “*ngFor” yazılmış ve <loop>’dan gelen tamamlanmış işler listelenmiştir. Bunun için yeni bir “doneJobs()” methodu yazılmış ve tetiklenen “(done)” eventinden sonra gelen “$event” objesi ile çağrılmıştır. Burada gelen tamamlanmış liste local “doneJobs[]” dizisine atılıp listelenmesi 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 36 37 38 39 40 41 42 |
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(); this.toDos.push(this.doText); this.toDos.forEach(job => { console.log(job); }); this.doText=""; } } doneJobs($event) { this.doneJob=$event.DoneList; console.log("Biten işler:"+JSON.stringify($event)); } } |
Böylece bir directive nasıl parametre gönderileceğini @Input() ve ilgili directiveden de nasıl değer alabileceğimizi @Output ile hep beraber gördük.
Şimdi de son örneğimizde tamamlanan işlerin üstünü çizelim. Ve kodlarımızı buna göre modify edelim.
app.component.ts(3): Aşağıda görüldüğü gibi öncelikle yapılacak işlerin üstünü çizebilmek için:
- “ToDo” adında yeni bir sınıf yapılmış, “state” ve “work” adında 2 property tanımlanmıştır. “state”: tanımlanacak css’e karşılık gelen modeldir.
- “toDos[ ]” dizisine artık yapılan string iş değil de bu yeni “ToDo” class’ı “push()” edilmektedir. En başta “state” property’si “start” olarak tanımlanmıştır.
- “<loop>” directive’ine, ilgili @Input() olarak “toDos[]” yani yaratılan “ToDo” sınıfları dizisi dönülmektedir.
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 |
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.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; } } |
loop.componenet.ts(3): Aşağıda görüldüğü gibi yapılacak işlerin üstünü çizebilmek için:
- “.complete” adında bir css tanımlanmıştır. Burada amaç gelen “ToDo” sınıfına ait “state” propertysine göre ilgili “<span>“‘a bu tanımlı css’i atayabilmektir.
- İlgili span’ın css’ine model ‘[ngClass]=”job.state”‘ ile tanımlanmaktadır. Yapılacak iş “{{job.work}}” ile yazılmaktadır.
- Bitti button’u tıklandığı zaman çağrılan “addList()” methodunda yapılan işin “state“‘i “completed” olarak atanmakta ve ilgli “<span>”‘ın css’i de yukarıda tanımlandığı gibi değiştirilmektedir. Böylece de yapılan işin üstü çizilmektedir.
- Eğer state ==”completed” ise demek, üstü çizili ve yapılmış listesindedir. O zaman tüm bu işlemleri geri almak için, state’e start değeri atanır. Böylece üstü çizili işlemlerin çizgisi kaldırılır. “item.state=item.state==”start”?”completed”:”start”;“
- Ayrıca “completed”‘den ==> “start” durumuna getirilen işler, yapılan işler listesinden kaldırılı yani “splice” ile geri alını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 |
import {Component,Input,Output,EventEmitter} from 'angular2/core' @Component({ selector: 'loop', template:` <style> .completed{ text-decoration:line-through; } </style> <ul> <li *ngFor="#job of toDos"> <span [ngClass]="job.state">{{job.work}}</span> <button type="button" (click)=addList(job)>Bitti</button> </li> </ul> ` }) export class LoopComponent{ @Input() toDos; @Output() done=new EventEmitter(); doneList=[]; addList(item){ item.state=item.state=="start"?"completed":"start"; if(item.state=="completed") { this.doneList.push(item.work); } else { var index =this.doneList.indexOf(item); this.doneList.splice(index, 1); } this.done.emit({DoneList:this.doneList}); console.log(this.doneList); } } |
Böylece geldik bir makalenin daha sonuna. Önümüzdeki makalelerde AngularJS 2 konusuna kaldığı yerden devam edeceğiz.
Hoşçakalın.
Kaynaklar : https://angular.io/, https://egghead.io, Mosh Hamedani(Angular 2 with TypeScript for Beginners The Pragmatic Guide) …
abi selam;
abi uygulamalar için eline sağlık, fakat kodları uygular iken aşagıdaki exception ile karşılaşıyorum google’da da cevap bulamadım sana sorayım dedim :).
EXCEPTION: Template parse errors:
Can’t bind to ‘toDos’ since it isn’t a known native property (”
][toDos]=”toDos” (done)=”doneJobs($event)”>
Biten İşler:
“): AppComponent@26:14
Selamlar Fırat,
Öncelikle teşekkürler Fırat. Diyorki :) “toDos[]” tanımlı bir property gibi durmuyor. Yani tip uyuşmazlığı var diyor. Yazdığın kodları bana mail atarsan daha sağlıklı cevap verebilirim.
Makaledeki kodlar çalışıyor çünkü.
İyi çalışamalar.
Hocam selamlar,
Angular2 için süper bir yazı dizisi olmuş gerçekten elinize sağlık ,
Teşekkürler.
Çok teşekkür ederim Cihan.
AngularJS 2 makale seriniz gerçekten güzel olmuş hocam teşekkürler. Derli toplu bir başlangıç oldu
Teşekkürler Ekin,
İşine yaradı ise ne mutlu bana :)
İyi çalışmalar.