שיעור 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() {
 }

}

 

שיעור 17 ב-ionic, שימוש ב toggleButton

כחלק מרכיבי ה-CSS של ionic , יש גם toggle button, כפתור דו מצבי נחמד.

בקוד הבא אפשר לראות :

  • שימוש בתגית ion-toggle, כדי לשים כפתור דו מצבי על המסך.
  • שימוש ב-[checked] על מנת לקשור אליו משתנה\פונקציה כדי שערכו ישמר.
  • על הדרך , אך ללא קשר, השתמשתי ב- ion-grid – שמאוד דומה לבוטסטראפ, וב-ion-label שמאפשר לשים תויות פשוטות ונחמדות.
<ion-content padding>
 <ion-grid>
 <ion-row>
 <ion-col>
 <ion-label>
 רקע שונה
 </ion-label>
 </ion-col>
 <ion-col>
 <ion-toggle 
 (ionChange)="onToggle($event)" 
 [checked]="checkAltBackground()" ></ion-toggle>
 </ion-col>
 </ion-row>
 </ion-grid>
</ion-content>

 

שיעור 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");

 }
 }

 }

 

שיעור 16 ב-ionic – הוספת תפריט צד, שימוש ב MenuController

  • הוספת תפריט צד בנוסף לטאבים, היא מהלך מעט מורכב
  • אציין אותו שלב אחר שלב, ולבסוף אביא את הקוד
  • בתוך app.html נוסיף תגית ion-menu, ובתוכו את הכפתורים הרלוונטים.
  • התגית ion-menu צריכה לבוא עם הגדרה שאומרת לה "היכן להחליף את העמודים" , כדי להגדיר זאת
    • נוסיף לתגית ion-nav סימון רגיל של תבנית אנגולר, כלומר למשל #nav
    • ולתגית ion-menu נוסיף הגדרה [content]="nav"
  • כדי לתת מראה אחיד בתוך התפריט, נשתמש בתגית ion-list, כאשר לכל אחד מהכפתורים נוסיף הגדרת ion-item
  • כמובן צריך להוסיף אירוע click לכל אחד מהכפתורים ב app.component.ts
  • כדי לשלוט בתוך האירוע בעמוד שיוצג, שהוא למעשה עמוד ה-root,
    נשאלת השאלה – איך נקבע את עמוד ה-root ?
    הרי בשלב זה , אנחנו בתוך הקומפוננט הראשון, ה- app.html, אז אנחנו עדין לא יכולים להזריק את NavController, כיוון שהוא עדין לא נוצר ( למרות שיש לו דווקא מתודה נחמדה של setRoot שהייתה יכולה לעזור לנו).
    אז כדי לתת פתרון אחר למטרה שלנו להחליף את עמוד ה-root , אנחנו נשתמש בפונקציה של אנגולר שנקראת ViewChild@,  זו שיטה באנגולר שבה אפשר לגשת לתבנית מסויימת, אחרי שהיא נוצרה, במקרה שלנו, אנחנו ניגש לתפריט אחרי שהוא נוצר, ושם כמובן, נוכל לגשת ל-NavController ולהשתמש במתודה שתאפשר לנו  להגדיר את ה-root.
    כלומר זהו פתרון עוקף שיאפשר לנו להשתמש ב-nav controller.
    הפתרון הזה מתואר בדוקמונטציה בקישור הזה.
  • אחרי שהמשתמש לוחץ על כפתור, אזי אנחנו צריכים לסגור את התפריט, לצורך כך נשתמש באובייקט MenuController, ספציפית במתודה שלו close.
  • כדי להוסיף בעמודים השונים (pages) את סימן התפריט, נוסיף כפתור , עם icon מובנה של ionic שנקרא menu.
  • את הכפתור ב-html, כדאי לעטוף בתגית של ionic שמיועדת לסידור של כפתורים בשורה. היא נקראת ion-buttons, ואפשר להוסיף לה את המאפיין start או end כדי להחליט האם הכפתור ישב בצד ימין או שמאל.
  • כדי להקפיץ את התפריט, נזריק לקלאס הרלוונטי את MenuController , ונשתמש במתודה שלו שנקראת open.
  • אך זה יכול להיות מעצבן מאוד, לו נצטרך בכל עמוד להוסיף את הכפתור, וליצור מתודה עבורו, לצורך כך ישנו קיצור דרך : להוסיף לכפתור התפריט את ההגדרה menuToggle . ואז לא צריך ליצור מתודה, ולייבא וכו'…
---- app.html file -----------------

<ion-menu [content]="nav" >
 <ion-header>
 <ion-toolbar>
 <ion-title>Menu</ion-title>
 </ion-toolbar>
 </ion-header>
 <ion-content>
 <ion-list>
 <button (click)="onLoad(tabsPage)" ion-item>
 <ion-icon name="quote" item-left></ion-icon>
 Quotes
 </button>
 <button ion-item (click)="onLoad(settingsPage)">
 <ion-icon name="settings" item-left></ion-icon>
 Settings
 </button>
 </ion-list>
 </ion-content>
</ion-menu>

<ion-nav [root]="tabsPage" #nav ></ion-nav>



------- app.component.ts file ---------------------

import { Component, ViewChild } from '@angular/core';
import { Platform, NavController, MenuController } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { TabsPage } from './../pages/tabs/tabs';
import { SettingsPage } from './../pages/settings/settings';

@Component({
 templateUrl: 'app.html'
})
export class MyApp {
 //rootPage:any = TabsPage;
 tabsPage:any = TabsPage;
 settingsPage:any = SettingsPage;
 @ViewChild('nav') nav:NavController;

 constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen
 ,private mnuCtrl:MenuController) {
 platform.ready().then(() => {
 // Okay, so the platform is ready and our plugins are available.
 // Here you can do any higher level native things you might need.1
 statusBar.styleDefault();
 splashScreen.hide();
 });
 }

 onLoad(page:any) {
 this.nav.setRoot(page);
 this.mnuCtrl.close();
 }
}

--------- בכל דף שבו מעוניינים בתפריט נוסיף משהו דומה -------------


<ion-header>

 <ion-navbar>
 <ion-buttons end >
 <button ion-buton menuToggle >
 <ion-icon name="menu"></ion-icon>
 </button>
 </ion-buttons>
 <ion-title>favorites</ion-title>
 </ion-navbar>

</ion-header>

 

שיעור 15 ב-ionic – יכולת slide מובנית לפריטי רשימה

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

כדי לעשות זאת, אנחנו צריכים לעטוף את אלמנט ion-item, באלמנט ion-item-sliding.

במידה ונרצה להכניס כפתורים וכדומה שמופיעים רק בעת ה-slide, נכניס אותם בתוך ion-item-options.

אז המבנה הבסיסי הוא :

  • ion-list
    • ion-item-sliding — בדרך כלל עם *ngFor
      • ion-item
      • ion-item-options

להלן דוגמא פשוטה :

<ion-header>

 <ion-navbar>
 <ion-title>favorites</ion-title>
 </ion-navbar>

</ion-header>


<ion-content padding>
 <ion-list>
 <ion-item-sliding *ngFor="let quote of quotes">
 <ion-item 
 (click)="onViewQuote(quote)"
 >
 <h2>{{quote.person}}</h2> 
 <p>{{quote.text}}</p>
 </ion-item>
 <ion-item-options>
 <button
 ion-button
 color="danger"
 (click)="onRemoveFromFavorites(quote)">
 <ion-icon name="trash"
 
 >Delete</ion-icon>
 </button>
 </ion-item-options>
 </ion-item-sliding>
 </ion-list>
</ion-content>

 

שיעור 14 ב- ionic – חלון קופץ Modal

כדי להציג חלון קופץ, מה שנקרא Modal, נעשה כך :

  • נייבא את ModalController
  • נוסיף לקונסטרקטור משתנה מסוג ModalController
  • בפונקציה המתאימה, נקרא  למתודה create של ModalController, ונעביר לה כפרמטר את הקלאס של page שאנחנו רוצים להציג כחלון קופץ.
  • וכדי להציג, נשתמש במתודה present.

המחשה –

בדוגמא הבאה, הדף שאני מציג בתור חלון קופץ, נקרא QuotePage :

import { Component } from '@angular/core';
import { IonicPage, ModalController} from 'ionic-angular';
import { QuoteService } from './../../services/quote.service';
import { Quote } from './../../data/quote.interface';
import { QuotePage } from './../quote/quote';

@IonicPage()
@Component({
 selector: 'page-favorites',
 templateUrl: 'favorites.html',
})
export class FavoritesPage {
 quotes:Quote[];

 constructor(private quotesService:QuoteService,
 private modalCtrl:ModalController) {
 }

 ionViewDidLoad() {
 
 }
 ionViewWillEnter(){
 this.quotes = this.quotesService.getFavoriteQuotes();
 }

 onViewQuote(quote:Quote) {
 const modal = this.modalCtrl.create(QuotePage);
 modal.present();
 }


}

 

אלא שיש בעיה קטנה …

אם נציץ בתצוגת mobile, בחלון הקופץ שבנינו, נראה שאנחנו לא יכולים לצאת ממנו.

כדי ליצור פונקציה שסוגרת, עם אירוע, וכו', נשתמש במחלקה של ionic שאחראית על ה-View המוצג ברגע זה, מחלקה זו נקראת ViewController.

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

המתודה שנשתמש בה היא dismiss, וכשמה כן היא – היא פשוט סוגרת את ה-view האקטיבי. (צריך להיזהר לא להפעיל אותה על root page 🙂 )

------ on the html file ------------


 <button ion-button color="danger"
 (click)="onClose()"
 >Close</button>

------ on the TS file --------------


import { Component } from '@angular/core';
import { IonicPage, ViewController } from 'ionic-angular';


@IonicPage()
@Component({
 selector: 'page-quote',
 templateUrl: 'quote.html',
})
export class QuotePage {
 constructor(private viewCtrl:ViewController) {}

 onClose() {
 this.viewCtrl.dismiss();
 }

}

איך להעביר מידע לחלון הקופץ ?

  • את המידע אנחנו מעבירים בפרמטר השני של יצירת האובייקט .
  • ואנחנו שולפים את המידע ( בעמוד הנפרד של החלון הקופץ )  דרך אובייקט navParams שאותו כבר הכרנו באחד השיעורים הקודמים
  • נקודה מעניינת לשים לב, היא שאני שולף את המידע באירוע המיוחד של ionic שנקרא ionViewDidLoad , והאירוע הזה מתרחש כל פעם מחדש, ולא נעשה לו cache.
העברת המידע בפרמטר השני



onViewQuote(quote:Quote) {

constmodal=this.modalCtrl.create(QuotePage,quote);

modal.present();

}

שליפת המידע בקלאס של הדף חלון שקופץ
ionViewDidLoad(){this.person=this.navParams.get('person');
this.text=this.navParams.get('text');
}

 העברת מידע מהחלון הקופץ, בחזרה אל החלון שהקפיץ אותו

  •  כדי לבצע זאת, נעביר פרמטר במתודה dismiss שסוגרת את החלון הקופץ
  • כדי לשלוף את הפרמטר שהעברנו , בחלון שהקפיץ , "נאזין" לאירוע הסגירה של ה-modal, באמצעות onDidDismiss, ושם נגדיר callback שמקבל פרמטר , וזהו הפרמטר שהעברנו מהחלון הקופץ.
  • חשוב לזכור ! העמוד שמתחת ל-modal לא מתרענן לאחר שה-modal נסגר, זאת אומרת שאם ביצענו דרך ה-modal שינוי כלשהוא שאמור להשפיע על הדף שמתחתיו – אז צריך לדאוג לבצע את השינוי (או לרענן את הדף).
----- on the modal page TS file -------

onClose(remove = false) {
 
 this.viewCtrl.dismiss(remove);
 
 
 }
 
 
----- on the under-laying page TS file -----
 onViewQuote(quote:Quote) {
 const modal = this.modalCtrl.create(QuotePage,quote);
 modal.present();
 modal.onDidDismiss((remove:boolean) =>{
 if(remove) {
 this.quotesService.removeQuoteFromFavorites(quote);
 }
 
 } );
 }

 

מילה על view hooks

שיעור 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";

}

שיעור 13 ב-ionic – הודעות למסך alert

ב-ionic יש רכיב מובנה של alert, כדי לעבוד איתו :

  • נזריק לקונסטרקטור משתנה מסוג AlertController
private alertCtrl:AlertController
  • אם עורך הקוד לא השלים לבד , אז לוודא שיש יבוא import של – AlertController
  • בפונקציה שבה אנחנו רוצים להקפיץ את ההודעה, ניצור אובייקט מסוג AlertController  בתוך משתנה, כאשר מעבירים פנימה פרמטרים של ההודעה הקופצת.
    למשל
const alert = this.alertCtrl.create({
title : "Hi", subTitle : "mooo", message:"bzzzz"});

alert.present();

  • אם נרצה להוסיף כפתורים להודעה הקופצת, אז נוסיף מערך של כפתורים
const alert = this.alertCtrl.create({
title : "Hi", subTitle : "mooo", message:"bzzzz"
,buttons : ['Ok']});

alert.present();


אם נרצה להעביר כפתורים, עם יותר שליטה בפרמטרים, אפשר להעביר אובייקטים, לדוגמא :

const alert = this.alertCtrl.create({

title:"fff",

subTitle:"sdfsdf"

,message: "sdfdfssdf",

buttons: [

{ text: 'Ok',

handler: () => {

console.log('ok');

}},

{

text:'cancel',

handler: () => {

console.log('cancel');

}

}

]

});

 

alert.present();


אפשר להוסיף לאחד מהאובייקטים של הכפתורים, מאפיין role=cancel, מה שזה יגרום הוא , שגם אם מישהו לחץ על איזור אחר בדף, כדי לסגור את ההודעה הקופצת, אבל לא לחץ על כפתור ה-cancel שלנו, אז בכל מקרה האירוע handler שהגדרנו עבור יציאה – יופעל.