שיעור 23 באנגולר ( angular ) – העברת מידע לתוך קומפוננטה

במקרים בהם המשתנים נמצאים בקומפוננטה עליונה בהירככיה, ובתוכה מקוננת קומפוננטה אחרת (או יותר) , אז נרצה להעביר את המידע מאחת לשניה.

עושים זאת באמצעות הפקודה Input@

כלומר צריך להצהיר בתוך הקומפוננטה המקבלת – שמשתנה מסוים מיועד להגיע, ואז אנגולר תדע להעביר אותו מהקומפוננט מעליו.

דוגמא – יש פה 2 קבצים, בקובץ העליון, אני מעביר משתנה בשם question

ובקובץ השני, הפנימי יותר, אני מקבל אותו עם Input@.

------------- First component ----------------
<app-question *ngFor="let question of questions" [question]="question" ></app-question>


-------------- Seconed Component TS file-------------
import { Question } from './../../models/Question';
import { Component, OnInit,Input } from '@angular/core';


@Component({
 selector: 'app-question',
 templateUrl: './question.component.html',
 styleUrls: ['./question.component.css']
})
export class QuestionComponent implements OnInit {

@Input('question') question:Question;

constructor() { }

ngOnInit() {
 }

}

 

שיעור 22 באנגולר ( angular ) – שימוש ב- router

באגנולר, כמו בפרימוורקים אחרים, router הוא הרכיב שדואג לניווט .

כדי להשתמש בו נבצע את השלבים הבאים :

  • נוודא שישנה תגית base
  • נייבא את ה- router ב- app.module.ts
  • נגדיר מערך של ניתובים
  • נוסיף למערך imports, את המערך של הניתובים, דרך המתודה שנקראת forRoot()
  • בתוך app.component.html נוסיף תגית router-outlet
  • ונקשר בתוך הקומפוננוטות במקומות הנחוצים – באמצעות הוספת המאפיין routerLink לתגית ה- a
--- app.module.ts --------
...
...
import { RouterModule,Routes } from '@angular/router';
...
...
import { Home3Component } from './components/home3/home3.component';

const appRoutes: Routes = [
 { path: '', component: Home3Component},
 { path : 'about', component: AboutComponent},
 { path: 'user/:id', component: UserDetailsComponent}
];
...
...
...
imports: [
 BrowserModule,
 FormsModule,
 HttpModule,
 RouterModule.forRoot(appRoutes)
 ],
 

--- app.component.html -------
...
...

<router-outlet></router-outlet>
...
...
---- navbar.component.html ------
 <li class="nav-item active">
 <a class="nav-link" href="#" routerLink="/" >Home <span class="sr-only">(current)</span></a>
 </li>
 <li class="nav-item">
 <a class="nav-link" href="#" routerLink="/about">Link</a>
 </li>

ניתובים (כתובת URL ) עם פרמטר

  • ניתן להוסיף ניתובים עם פרמטרים ב-syntax הבא:    blabla/:myParam
  • כדי לקבל את הכתובות , נייבא אל תוך הקומפוננט את
    Router,ActivatedRoute,Params
  • ובנוסף נזריק ( DI ) בקונסטרקטור את Router,ActivatedRoute
  • כדי שנוכל לקבל את הפרמטר מה-URL, צריכים לרשום = subscribe  את הפרמטר בתוך "צופה"  = observable.

 

---- in app.module.ts routes array ----

const appRoutes: Routes = [
 { path: '', component: Home3Component},
 { path : 'about', component: AboutComponent},
 { path: 'user/:id', component: UserDetails3Component}
];

--- in the component -----
import { Component, OnInit } from '@angular/core';
import { Router,ActivatedRoute,Params } from '@angular/router';

@Component({
 selector: 'app-user-details-3',
 template: `
 <h1> This is User number {{id}}.</h1>
 `,
 
})
export class UserDetails3Component implements OnInit {

 id:number;

 constructor(
 private route:ActivatedRoute,
 private router:Router
 ) 
 {

 this.route.params.subscribe((params:Params) => {
 this.id = params.id;
 });
 }

 ngOnInit() {} 



}

שיעור 21 באנגולר (angular) – קריאות http

קריאת Get באנגולר, והבסיס לקריאות http

כדי להשתמש ברכיב http של אנגולר, צריך קודם כל לייבא אותו ולהגדיר אותו בקובץ app.module.ts

import { HttpModule } from '@angular/http';

...
...
imports: [
 BrowserModule,
 FormsModule,
 HttpModule,
 RouterModule.forRoot(appRoutes)
 ],

שלב נוסף – הוא בתוך ה- service, להזריק אותו אל הקונסטרטור (וכמובן לייבא אותו ).

(במידה וזה service חדש שעכשיו נוצר, אז כמובן לייבא אותו ב–app.module.ts, ולהכניס אותו למערך ה- providers ).

ואז ב- service, נשתמש במודול http כדי לבצע קריאה, ולמפות את התוצאות ל-json.

כדי למפות את התוצאות צריך לייבא חלק של rxjs, שנקרא map.

התוצאה הסופית נראית כך :

---- The Service file -----

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';


@Injectable()
export class Get2Service {

 apiUrl:string = 'https://jsonplaceholder.typicode.com/users';

 constructor(public http:Http) { }

 getUsers(){
 return this.http.get(this.apiUrl)
 .map(response => response.json());
 }


}


----- The component file ----------

import { Component, OnInit } from '@angular/core';
import { Get2Service } from './../../services/get2.service';

@Component({
 selector: 'app-useget2',
 template: `
 
 <h1>list of users</h1>
 <div *ngFor="let user of users">
 <ul>
 <li>{{user.name}}</li>
 <li>{{user.email}}</li>
 <li>{{user.id}}</li>
 </ul>
 <hr>
 </div>
 
 `
})
export class Useget2Component implements OnInit {

 users:any[];

 constructor( public getService:Get2Service ) {

 this.getService.getUsers().subscribe(users => {
 //console.log(users);
 this.users = users;
 })

 }



 ngOnInit() {
 }

}

קריאת POST באנגולר

בדוגמא הבאה, לקחתי את הדוגמא הקודמת והוספתי לה

  • ב- service התווספה פונקציה שנקראת addUser ומבצעת קריאת POST.
  • ב-component התווסף טופס להוספת יוזרים, שממופה עם ngModel אל רשימת היוזרים, ואל משתנה חדש בשם יוזר ( אובייקט עם 3 מאפיינים).
  • לטופס יש פונקציה שמטפלת ב-submit שלו, שמבצעת גם קריאה ל-service.
---------- The Service File ------------------

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';


@Injectable()
export class Get2Service {

 apiUrl:string = 'https://jsonplaceholder.typicode.com/users';

 constructor(public http:Http) { }

 getUsers(){
 return this.http.get(this.apiUrl)
 .map(response => response.json());
 }

 addUser(user) {
 return this.http.post(this.apiUrl,user).map(response => response.json());
 }


}
--------------- The component file -------------

import { Component, OnInit } from '@angular/core';
import { Get2Service } from './../../services/get2.service';

@Component({
 selector: 'app-useget2',
 template: `
 
 <h1>list of users</h1>
 <form (submit)="onSubmit()">
 <div class="form-group">
 <label>Name:</label>
 <input type="text" name="name" [(ngModel)]="user.name" class="form-control">
 </div>
 <div class="form-group">
 <label>Email:</label>
 <input type="text" name="email" [(ngModel)]="user.email" class="form-control">
 </div>
 <div class="form-group">
 <label>Phone:</label>
 <input type="text" name="phone" [(ngModel)]="user.phone" class="form-control">
 </div>
 <input type="submit" value="click to submit" class="btn btn-success">
 </form>
 <hr>
 <div *ngFor="let user of users">
 <ul>
 <li>{{user.name}}</li>
 <li>{{user.email}}</li>
 <li>{{user.id}}</li>
 </ul>
 <hr>
 </div>
 
 `
})
export class Useget2Component implements OnInit {

 users:any[];
 user = {name: '',
email:'',phone:''};

 constructor( public getService:Get2Service ) {

 this.getService.getUsers().subscribe(users => {
 //console.log(users);
 this.users = users;
 })

 }

 onSubmit(){
 this.getService.addUser(this.user).subscribe(user=> {
 console.log(user);
 this.users.unshift(user);
 });
 }

 ngOnInit() {
 }

}

קריאת Delete  + PUT  באנגולר

המשך הדוגמא שמובאת למעלה – הוספתי כעת גם קריאות put+delete שמוצמדות לכפתורים Edit/Delete.

(הכפתור edit , מעדכן את המודל, וכיוון שהטופס קשור ל- ngModel אז באופן אוטומטי, הטופס מכיל את תוכן המודל).

----- The Service File --------

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';


@Injectable()
export class Get2Service {

 apiUrl:string = 'https://jsonplaceholder.typicode.com/users';

 constructor(public http:Http) { }

 getUsers(){
 return this.http.get(this.apiUrl)
 .map(response => response.json());
 }

 addUser(user) {
 return this.http.post(this.apiUrl,user).map(response => response.json());
 }

 deleteUser(id) {
 return this.http.delete(this.apiUrl + "/" + id).map(response => response.json());
 }

 updateUser(user) {
 return this.http.put(this.apiUrl + '/' + user.id,user).map(response => response.json());
 }

}


---- The Component file -----------
import { Component, OnInit } from '@angular/core';
import { Get2Service } from './../../services/get2.service';

@Component({
 selector: 'app-useget2',
 template: `
 
 <h1>list of users</h1>
 <form (submit)="onSubmit(isEdit)">
 <div class="form-group">
 <label>Name:</label>
 <input type="text" name="name" [(ngModel)]="user.name" class="form-control">
 </div>
 <div class="form-group">
 <label>Email:</label>
 <input type="text" name="email" [(ngModel)]="user.email" class="form-control">
 </div>
 <div class="form-group">
 <label>Phone:</label>
 <input type="text" name="phone" [(ngModel)]="user.phone" class="form-control">
 </div>
 <input type="submit" value="click to submit" class="btn btn-success">
 </form>
 <hr>
 <div *ngFor="let user of users">
 <ul>
 <li>{{user.name}}</li>
 <li>{{user.email}}</li>
 <li>{{user.id}}</li>
 </ul>
 <br>
 <button (click)="onDeleteClick(user.id)" class="button btn-danger btn-sm">Delete</button>
 <button (click)="onEditClick(user) " class="button btn-primary btn-sm">Edit</button>
 <hr>
 </div>
 
 `
})
export class Useget2Component implements OnInit {

 users:any[];
 user = {name: '',
email:'',phone:''};
 isEdit:boolean = false;

 constructor( public getService:Get2Service ) {

 this.getService.getUsers().subscribe(users => {
 //console.log(users);
 this.users = users;
 })

 }

 onSubmit(isEdit){
 if (isEdit) {
 this.getService.updateUser(this.user).subscribe(user=> {
 console.log(user);
 for(let i = 0; i< this.users.length ; i++ ){
 if (this.users[i].id == user.id) {
 this.users.splice(i,1);
 
 }
 }
 this.users.unshift(user);
 });
 } else {

 this.getService.addUser(this.user).subscribe(user=> {
 console.log(user);
 this.users.unshift(user);
 });
 }
 }

 ngOnInit() {
 }


 onDeleteClick(id) {
 console.log(id);
 this.getService.deleteUser(id).subscribe(response=> {
 console.log(response);
 for(let i = 0;i< this.users.length; i++) {
 if(this.users[i].id == id) {
 this.users.splice(i,1);
 }
 }
 });
 }

 onEditClick(user) {
 this.isEdit = true;
 this.user = user;
 }
}

 

שיעור 20 באנגולר ( angular) – שימוש ב – obseravables

מהו Observable ?

  • במקור זהו Design Pattern מקובל ( הסבר מוויקיפדיה  )  שיש לו מימושים בהרבה מאוד שפות , כמו שאפשר לראות באתר http://reactivex.io/languages.html 
  • הרעיון של תבנית התיכנות הזו, הוא שיש לנו אובייקט מסוים, שנגדיר אותו בתור "הנושא", ובנוסף אליו אנחנו מגדירים "צופים" שכל הזמן מסתכלים\עוקבים\צופים על הנושא, ברגע שמשהו בנושא משתנה ( בעגה המקצועית – יש שינוי של State , של מצב )
    אז כל הצופים רואים את השינוי באופן אוטומטי.
  • למה זה טוב ?
    • זה לא מצריך להסתבך עם callbacks
    • זה מאפשר לפתוח "ערוץ מידע" קבוע לכל מיני חיבורים למקורות מידע ( דאטאבייס, API, וכדומה ) כך שברגע ש-"נרשמנו" בתור "צופים" על הנושא, אז מרגע זה, אנחנו משוחררים מלבדוק כל הזמן את המצב של הנושא, אלא רק הגדרנו במקום מסוים, מה קורה כאשר הנושא משנה מצב (state), ומשם ואילך – הטיפול הוא באמצעות ה"צופה" שהגדרנו .

המחשה – Observable

  • ניצור service
  • נייבא פנימה גם את Observable מתוך rxjs/Observable
  • ניצור משתנה שיכיל את המידע, מסוג Observable, ונשתמש ב-syntax של <> כדי להצהיר על הסוג הספציפי שיחזור.
    המשתנה הזה, הוא ה-"צופה", כלומר הוא יכיל פונקציה שתדאג לדווח לנו בכל פעם שיש שינוי ב-state של המידע.
  • ניצור פונקציה שמחזירה את המידע
    • בתוך הפונקציה נשים בתוך המשתנה  מסוג Observable שלנו, אובייקט חדש, מסוג Observable, עם פונקציה שמחזירה מידע
    • לצורך הדוגמא בלבד, נשתמש ב-setTimeout, כדי להחזיר מידע חדש כל X זמן, ובעצם להדגים בזה, כיצד ה"צופה" מרגיש שהמידע השתנה, ומוסיף אותו לסט הנתונים.
  • בקומפוננט
    • נייבא את ה-Service שיצרנו
    • ניצור משתנה שיקבל את התוכן
    • ונרשום פקודה, ש-"נרשמת" לצפיה, בפונקציה של ה-service שמחזירה את הצופה.
    • מה שיקרה הוא שהצופה יחזיר כל פעם מידע ברצף
      כלומר בעצם יצרנו אפשרות ליצור רצף של מידע שמגיע.
--- The service file -----

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';


@Injectable()

export class BasicService {
 data:Observable<Array<number>>;

 constructor() {
 }

 getData() {
 this.data = new Observable(observer => {
 setTimeout(()=> {
 observer.next(1);
 },1000);
 setTimeout(()=> {
 observer.next(2);
 },2000);
 setTimeout(()=> {
 observer.next(3);
 },3000);
 setTimeout(()=> {
 observer.next(4);
 },4000);
 setTimeout(()=> {
 observer.complete();
 },5000);
 });

 return this.data;
 }
 
}



----- the Component file -------
import { Component, OnInit } from '@angular/core';
import { BasicService } from './../../services/basicService2/basic.service';


@Component({
 selector: 'app-use-observable2',
 template: `
 <h1>Observable Example</h1>
 <ul>
 <li *ngFor="let i of data">
 {{ i }}
 </li>
 </ul>
 
 `
})
export class UseObservable2Component implements OnInit {

 data:any[] = [];

 constructor(public basicService:BasicService) {
 this.basicService.getData().subscribe(returnedData => {
 console.log(returnedData);
 this.data.push(returnedData);
 });
 }

 ngOnInit() {
 }

}

שיעור 19 באנגולר – Services

מהו Service באנגולר ?

  • סרויס הוא סוג של קלאס שמאפשר להשתמש במידע בתוך קומפוננטות רבות.
    • מה שמאפשר לשמור את הקופוננט נקי ורזה, ולא להתעסק בו בקריאות למידע.
    • וגם מאפשר לא לחזור על אותן קריאות למידע שוב ושוב מכל קומפוננט. ( DRY – אל תחזור על עצמך ).

איך יוצרים service באנגולר ?

  • ניצור מחלקה חדשה, מקובל לשים services בתיקיה שנקראת services
  • כדי ה- service שלנו יוכל להיות מוזרק לקומפוננטות ( Depency Injection ) , אז אנחנו צריכים לעשות import   של Injectable , שמאפשר למחלקה להיות מוזרקת בהמשך.
  • ובסופו של דבר, נרשום את ה- service ברשימת הספקים הקיימים, שנמצאת במערך ngModule
  • אם עשינו את כל אלו – נוכל להזריק ולהשתמש ב- service בכל קומפוננטה שנרצה.

איך יוצרים service באמצעות כלי שורת הפקודה angular cli ?

  • נקליד :
ng g service MY_SERVICE_NAME

דוגמא בסיסית ל-service באנגולר

  • בקטעי קוד הבאים רואים service פשוט שמחזיר מערך של מידע.
  • ה-service נרשם כספק במערך ה-providers בקובץ app.module.ts ( וכמובן מיובא שם )
  • ה- service מוזרק לתוך קומפוננט ( וכמובן מיובא שם )  בקונסטרקטור
  • המידע מה-service עובר למשתנה בקומפוננט, ומוצג על המסך עם לולאה של אנגולר.
---------- the service file --------------
import { Injectable } from '@angular/core';

@Injectable()

export class BasicService {
 users:string[];

 constructor() {
 this.users = ["Bubu","Koko","Moko"];
 }

 getUsers(){
 return this.users;
 }
}


---------- app.module.ts -----------------

...
...
import { BasicService } from './services/basicService2/basic.service';

...
...
providers: [
 ...
 ...
 
 BasicService
 ],

---- קובץ הקומפוננט --------------------

import { Component, OnInit } from '@angular/core';
import { BasicService } from './../../services/basicService2/basic.service';

@Component({
 selector: 'app-just-another-component',
 template:` 
 
 <h1>Hi</h1>
 <ul>
 <li *ngFor="let user of users">
 {{ user}}
 </li>
 </ul>
 
 `
})
export class JustAnotherComponentComponent implements OnInit {

 users:string[];

 constructor(public basicService:BasicService ) { 

 this.users = this.basicService.getUsers();

 }

 ngOnInit() {
 }

}

 

שיעור 18 באנגולר (angular) – טפסים, ngModel, ואירועי מקלדת

  • בפוסט הזה אני רוצה להדגים יכולת חשובה של אנגולר – כיצד לטפל בטפסים.
  • לפני שאני מציג את הטפסים, נציג המחשה קטנה של אירועי מקלדת, כי את אותו רעיון אני אציג אחר כך עם הטפסים.
  • הרעיון הוא להציג את הקלט המוקלד, תוך כדי הקלדה.

המחשה של אירועי מקלדת באנגולר

הקוד הבא מציג את הטקסט המוקלד בשדה, תוך כדי הקלדה.

הוא משתמש באירוע keyup, וב-data binding על מנת לעשות זאת.

import { Component } from '@angular/core';

@Component({
 selector: 'app-keyup2',
 template: `
 <h1> keyup demo</h1>
 <input type="text"
 (keyup)="changeText($event)">
 <hr>
 <h1>Your Text is : {{ text }}</h1>
 
 
 `
})
export class Keyup2Component {
 text:string = '';

 changeText(event) {
 this.text = event.target.value;
 }
}

טפסים ושימוש ב-ngModel באנגולר

  • הדרך הקודמת שהצגתי הייתה מעט גולמית, היות וממש טיפלנו באירוע המקלדת
  • יש דרך יותר אלגנטית לעשות זאת, אם נרתום לטובתינו את מודל הטפסים של אנגולר.
  • בקוד הבא, אני מייבא את ngModel ( גם ב app.module.ts, וגם בקלאס של הקומפוננט שלי )
  • לאחר מכן , בכל שדה של טופס שאני יוצר, אני קושר אליו משתנה מסויים במחלקה באמצעות [(ngModel)]
  • וכך אנחנו נהנים מ-data binding ל-2 הכיוונים.
---- in app.module.ts file -----------

import {FormsModule } from '@angular/forms';
...
...
 imports: [
 BrowserModule,
 FormsModule,
 HttpModule,
 RouterModule.forRoot(appRoutes)
 ],

 
---- in my component ts file -------------------
import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-ngmodel22',
 template:`
 <h1> ng model demo</h1>

 <form>
 <label>your name : </label> 
 <input type="text" name="name" [(ngModel)]="name">

 <br><br>
 <label>your age : </label> 
 <input type="text" name="age" [(ngModel)]="age">
 <br><br>
 <input type="submit" value="submit">
 </form>
 
 <hr>
 <h1>Your Name : {{name}}</h1>
 <h1>Your Age : {{age }}</h1>
 `
})
export class Ngmodel22Component implements OnInit {

 name:string = 'Eyal';
 age:number = 20;

 constructor() { }

 ngOnInit() {
 }

}

אירוע של Sumbit עבור טופס

  • בדוגמא הזו ניתן לראות שאירוע ה-submit מטופל בתוספת קטנה בתגית ה–form שמפנה אל פונקציה בקלאס.
  • אומנם בדוגמא הנוכחית, התוכן לא נשלח לשום מקום, אלא רק מתווסף אל רשימה בתחתית המסך.
import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-formss2',
 template:`
 <form (submit)="onSubmit()">
 <div class="form-group">
 <label>Name</label>
 <input type="text" class="form-control" 
 [(ngModel)]="name" name="name">
 </div>
 <input type="submit" class="btn btn-success" value="Submit">
 </form>
 <hr>
 <ul class="list-group">
 <li class="list-group-item"
 *ngFor="let user of users">{{ user}}</li>
 </ul>
 
 
 `
})

export class Formss2Component implements OnInit {

 name:string = '';
 users:string[] = ['Bubu','Momo','Koko'];
 constructor() { }

 ngOnInit() {
 }

 onSubmit(){
 // console.log(this.name);
 this.users.push(this.name);
 this.name = '';
 }
}

שימוש בטפסים מבוססי תבנית באנגולר + וולידציה של טפסים באנגולר

בטופס הבא צריך לשים לב לכמה נקודות:

    • בכל שדה הגדרנו את השיוך ל ngModel
    • וגם הגדרנו עבורו id שמפנה ל ngModel
    • וגם הגדרנו בראש הטופס #f  עבור הטופס כולו – שמוצמד ל ngForm
  • בנוגע לוולידציה :
    • הגדרנו div מיוחדים עם הודעות השגיאה, שבאמצעות ngIf* יודעים להגיב לשגיאות.
  • בנוגע לפעולת ה-submit של הטופס, קיבלנו אובייקט שמכיל 2 משתנים,משתנה אחד הוא ערך בוליאני – האם הוולידציה עברה או לא, ומשתנה שני מכיל אובייקט עם תוכן הטופס.
 import { Component, OnInit } from '@angular/core';

 @Component({
 selector: 'app-forms-model33',
 template:`
 <form novalidate #f="ngForm" (ngSubmit)="onSubmit(f)">
 <div class="form-group">
 <label>Name</label>
 <input class="form-control" type="text" [(ngModel)]="user.name"
 name="name"
 #userName="ngModel"
 minlength="2"
 required
 >
 </div>
 <div *ngIf="userName.errors?.required && userName.touched" class="alert alert-danger">שם נדרש</div>
 <div *ngIf="userName.errors?.minlength && userName.touched" class="alert alert-danger">לפחות 2 אותיות נדרשות</div>
 <div class="form-group">
 <label>Email</label>
 <input class="form-control" type="text" [(ngModel)]="user.email"
 name="email"
 #userEmail="ngModel"
 
 required
 >
 <div *ngIf="userEmail.errors?.required && userEmail.touched" class="alert alert-danger">אימייל נדרש</div>
 
 </div>
 <div class="form-group">
 <label>Phone</label>
 <input class="form-control" type="text" [(ngModel)]="user.phone"
 name="phone"
 #userPhone="ngModel"
 minlength="10"
 >
 <div *ngIf="userPhone.errors?.minlength && userPhone.touched" class="alert alert-danger">טלפון של 10 ספרות לפחות </div>
 
 </div>

 <input type="submit" value="Submit" class="btn btn-success">
 </form>
 
 
 `
 })
 export class FormsModel33Component implements OnInit {
 
 user = {name: '' , email: '' , phone : 0 };

 constructor() { }

 ngOnInit() {
 }
 
 onSubmit({value,valid}) {
 if(valid){
 console.log(value);
 }else{
 console.log("Form is invalid");

 }
 }

 }

 

שיעור 17 באנגולר (angular) – שינוי מאפיינים

דוגמא 1 – כפתור שגורם לטקסט להשתנות

נניח ויש לנו משתנה שתוכנו מוצג על המסך. ואנחנו רוצים לשנות אותו כתגובה למשהו שהמשתמש עשה.

הדוגמא הראשונה מראה כפתור שבלחיצה עליו משנה את הטקסט.

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-properties2',
 template:`
 <h1>hi</h1>
 <button (click)="changeValue()">Change Value</button>
 <h1>{{text}}</h1>
 `
})
export class Properties2Component implements OnInit {
 text:string = "Hello world";

 constructor() { }

 ngOnInit() {
 }

 changeValue() {
 this.text = "Goodbye";
 }

}

דוגמא 2 – קטע שמוסתר בעקבות לחיצה

בדוגמא הזו, הפונקציה משנה משתנה של המחלקה, ובעקבות כך div שלם מוסתר , כי מוצמד אליו ngIf .

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-properties2',
 template:`
 <h1>hi</h1>
 <button (click)="changeValue()">Change Value</button>
 <div *ngIf="value">
 <h1>{{text}}</h1>
 </div>
 `
})
export class Properties2Component implements OnInit {
 text:string = "Hello world";
 value:boolean = true;

 constructor() { }

 ngOnInit() {
 }

 changeValue() {
 this.value = false;
 //this.text = "Goodbye";
 }

}

דוגמא 3 – לבנות div שנפתח ונסגר בלחיצה

אם נעשה שינוי קטן מאוד בפונקציה, נוכל לגרום לכך, שהמשתנה value ששולט בתצוגת ה-div, כל פעם יחליף את ערכו בלחיצה.

התוצאה של זה היא שבכל לחיצה ה-div יוצג\יוסתר, ויצרנו למעשה  toggle button .

changeValue() {

this.value=!this.value;

//this.text = "Goodbye";

}

שיעור 16 באנגולר – אירועים של העכבר

אנגולר מאפשרת להגיב לאירועים של העכבר\מקלדת, ובפוסט הזה נראה איך מגיבים לאירועי עכבר.

התגובה לאירועים תמיד מתחילה בכתיבת שם האירוע בתוך סוגרים, למשל (click) ואחרי כן הסימן שווה (=) ואז שם הפונקציה, ובמידת הצורך גם פרמטרים.

אירוע לחיצה על העכבר – אנגולר

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-mouseevents2',
 template: `
 <h1>Hi</h1>
 <button (click)="fireEvent('Hi')">Click Me</button>
 
 `
})
export class Mouseevents2Component implements OnInit {

 constructor() { }

 fireEvent(msg) {
 console.log(msg);
 }

 ngOnInit() {
 }

}

העברת אוביקט האירוע לפונקציה

אפשר להעביר גם את האירוע עצמו, ולקבל המון מידע.

  • כדי להעביר את אובייקט האירוע עצמו, נרשום בפרמטר הראשון משתנה שמתחיל בדולר
  •  ניקח לדוגמא 2 מאפיינים מעניינים מתוך אוביקט האירוע – את ה- id, של האלמנט שלחצו עליו, ואת סוג האלמנט.
import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-mouseevents2',
 template: `
 <h1>Hi</h1>
 <button 
 id="FirstButton"

 (click)="fireEvent($event,'Hi')">Click Me</button>
 
 `
})
export class Mouseevents2Component implements OnInit {

 constructor() { }

 fireEvent(event,msg) {
 console.log(event.target.id);
 console.log(event.type);
 }

 ngOnInit() {
 }

}

אירוע mouseover

האירוע הבא מתרחש כאשר עוברים עם העכבר על אלמנט

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-mouseevents2',
 template: `
 <h1>Hi</h1>
 <button 
 id="FirstButton"

 (click)="fireEvent($event,'Hi')">Click Me</button>
 <br>
 <button
 (mouseover)="fireAfterMouseover($event)">pass the mouse here</button>
 
 


 `
})
export class Mouseevents2Component implements OnInit {

 constructor() { }

 fireEvent(event,msg) {
 console.log(event.target.id);
 console.log(event.type);
 }

 fireAfterMouseover(event) {
 console.log(event.type);
 }

 ngOnInit() {
 }

}

אירועי עכבר נוספים

אירועים נוספים אפשרים :

  • mousedown – כאשר לוחצים ומחזיקים את העכבר
  • mouseup – כאשר משחררים את לחיצת העכבר
  • dblclick – לחיצה כפולה
  • drag  – כאשר מסמנים ואז מנסים לגרור את הקטע המסומן
  • dragover – כאשר מסמנים ואז מנסים לגרור משהו מעל האלמנט הנוכחי.

 

שיעור 15 באנגולר (angular) – שימוש ב-pipes

המונח pipes באנגולר מתאר תבניות שאפשר להלביש על אלמנטי קטנים של טקסט, וכך לשנות אותם. למשל לעצב תאריך, להפוך מילה שלמה באנגלית לאותיות גדולות\קטנות, וכדומה.

ניתן ליצור גם pipes חדשים לבד, הדוגמאות כאן מראות את אלו שכלולים כבר באנגולר.

דוגמא 1 – pipe שמעצב תאריך

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-pipes2',
 template: `
 
 <h1>Pipes 2</h1>
 <p>His birthday is on {{birth | date }}.</p>
 
 `
})
export class Pipes2Component implements OnInit {

 birth:Date = new Date(1980,7,8);

 constructor() { }

 ngOnInit() {
 }

}

יש pipes שיכולים גם לקבל פרמטרים, אם נניח שנרצה לעצב את התאריך בצורה שמקובלת בישראל, נעשה זאת לפי הדוגמא הבאה.

דוגמא 2  – עיצוב תאריך ב- dd/mm/yyyy

<p>His birthday is on {{birth | date:"dd/MM/yyyy" }}.</p>

מספר דוגמאות ל-pipes יחד

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-pipes2',
 template: `
 
 <h1>Pipes 2</h1>
 <p>His birthday is on {{birth | date }}.</p>
 <p>His birthday is on {{birth | date:"dd/MM/yyyy" }}.</p>
 <p>He was born at {{birth | date:"yyyy" }}.</p>
 <p>pipes of uppercase {{ 'cats' | uppercase}}</p>
 <p>pipes of lowercase {{ 'CATS' | uppercase}}</p>
 <p>pipe of currency {{total | currency:"NIS":1 }}</p>
 <p>fee is {{ fee | percent }}</p>
 
 
 
 `
})
export class Pipes2Component implements OnInit {

 birth:Date = new Date(1980,7,8);
 total:number = 459;
 fee:number = 0.7;

 constructor() { }

 ngOnInit() {
 }

}

שיעור 14 באנגולר (angular) – שליטה בתצוגה עם ngClass \ ngStyle

בדוגמאות הבאות, אציג 2 מאפיינים חשובים לטיפול בעיצוב :  ngClass+ngStyle.

בשתי המקרים, אני אתן דוגמא לשימוש ללא המאפיין, ודוגמא שכוללת אותו.

הגדרה באנגולר של css class שמופעל רק אם משתנה הוא true

נניח ואנחנו רוצים שאלמנט יקבל עיצוב מסוים, רק אם משתנה בוליאני הוא אמת.

לצורך כך, נרשום מאפיין של angular, שקושר את ה-css class, אל המשתנה.

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-ngclass2',
 template: `
 <h1>Hello World</h1>
 <h4 [class.special]="isSpecial" >Special Sentence</h4>
 
 
 `,
 styles: [
 ` .special {
 color: yellow
 }
 `
 ]
})
export class Ngclass2Component implements OnInit {

 isSpecial = false;
 canSave = true;

 constructor() { }

 ngOnInit() {
 }

}



השמת מספר קלאסים יחד על אלמנט באנגולר באמצעות ngClass

בדוגמת קוד הבאה, אנחנו נותנים מאפיין שמכיל אוביקט, ובאובייקט יש מספר קלאסים יחד, והם מוחלים יחד על האלמנט.

  • שימו לב לשימוש ב-ngClass
  • שימו לב להפעלה של הפונקציה שממלאת את האוביקט , ואני קורא לה בקונסטרקטור.

 

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-ngclass2',
 template: `
 <h1>Hello World</h1>
 <h4 [class.special]="isSpecial" >Special Sentence</h4>
 <h4 [ngClass]="currentClasses">Saveable and Special div</h4>
 
 `,
 styles: [
 ` .special {
 color: green
 }
 .saveable {
 text-transform: uppercase;
 }
 `
 ]
})
export class Ngclass2Component implements OnInit {

 isSpecial = true;
 canSave = true;

 currentClasses = {};

 constructor() { 
 this.setCurrentClasses();
 }

 ngOnInit() {
 }

 setCurrentClasses(){
 this.currentClasses = {
 saveable: this.canSave,
 special: this.isSpecial
 }
 }
}

 

הפעלה של עיצוב באמצעות משתנה

בדוגמא הבאה, אנחנו קובעים את גודל הפונט, לפי משתנה מסוים במחלקה.

שימו לב ל-syntax, שבו למעשה כל משפט התנאי הוא בתוך הגרשיים.

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-ngstyle2',
 template: `
 
 <h1> ng style</h1>
 <div [style.font-size]="isSpecial ? '40px' : '8px'">Font size depends on isSpecial</div>
 `
})
export class Ngstyle2Component implements OnInit {

 isSpecial:boolean = true;
 canSave:boolean = true;

 constructor() { }

 ngOnInit() {
 }

}

הפעלה של מספר עיצובים יחד באמצעות ngStyle

בדוגמת הבאה, אני קובע מספר הגדרות CSS יחד, ומחיל אותם בתור אובייקט, על אלמנט מסוים.

  • שימוש לב לשימוש במאפיין ngStyle
  • שימו לב להפעלה של הפונקציה שממלאת את האובייקט ומופעלת מהקונסטרקטור.
import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-ngstyle2',
 template: `
 
 <h1> ng style</h1>
 <div [style.font-size]="isSpecial ? '40px' : '8px'">Font size depends on isSpecial</div>
 
 <div [ngStyle]="currentStyles">One More DIV</div>
 `
})
export class Ngstyle2Component implements OnInit {

 isSpecial:boolean = true;
 canSave:boolean = true;
 currentStyles = {};


 constructor() { 
 this.setCurrentStyles();
 }

 setCurrentStyles(){
 this.currentStyles = {
 'font-style': this.canSave ? 'italic' : 'normal',
 'font-size': this.isSpecial ? '24px' : '12px'
 }
 }

 ngOnInit() {
 }

}