שיעור 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 – כאשר מסמנים ואז מנסים לגרור משהו מעל האלמנט הנוכחי.

 

שיעור 12 ב-ionic – רכיבי CSS של ionic – כרטיסים (cards) ורשת (grid)

בתוך ionic יש הרבה רכיבי CSS מובנים, אחד מהם הוא Cards, שמאפשר לעטוף בריבוע נאה כל מיני אלמנטים.

נדגים על לולאה שמציגה מערך כלשהוא :

<ion-cardpadding *ngFor="let quote of quoteGroup.quotes;let i = index">

<ion-card-header>

#{{ i+1 }}

</ion-card-header>

<ion-card-content>

{{quote.text}}

</ion-card-content>

</ion-card>

רכיבי CSS מובנים ב-IONIC – גריד, וכרטיס

בדומה ל- twiter bootstrap, ל- ionic , יש מערכת גריד, שמתאימה למובייל, וגם עיצובים שונים.

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

<ion-header>

 <ion-navbar>
 <ion-title>{{quoteGroup.category}}</ion-title>
 </ion-navbar>

</ion-header>


<ion-content padding>

 <ion-card padding *ngFor="let quote of quoteGroup.quotes;let i = index">
 <ion-card-header>
 #{{ i+1 }}
 </ion-card-header>
 <ion-card-content>
 <p> {{quote.text}}</p>
 <p>{{quote.person}}</p>
 </ion-card-content>
 <ion-row>
 <ion-col text-right>
 <button ion-button clear small
 (click)="onAddToFavorite(quote)"
 >Favorite</button>
 </ion-col>
 </ion-row>
 </ion-card>
 <ul>
 
 <li *ngFor="let singleQuote of quoteGroup.quotes">
 {{singleQuote.person}} : {{singleQuote.text}}
 </li>
 </ul>
 
</ion-content>

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

}

שיעור 11 ב-ionic, רשימות עם ion-list

ל-ionic יש הרבה רכיבי CSS מובנים, שמתאימים כמובן לאפליקציית מובייל.

רכיב הרשימה נקרא ion-list.

נניח ובקלאס יש לנו מערך כלשהוא של אובייקטים.

אז בדוגמת הקוד הבאה רואים שימוש ב ion-list :

<ion-list>

 

<button

ion-item

*ngFor="let quoteGroup of quoteCollection" (click)="bubu()"

[navPush]="quotesPage"

[navParams]="quoteGroup"

>

 

<ion-icon [name]="quoteGroup.icon"item-left></ion-icon>

<h2>{{quoteGroup.category | uppercase }}</h2>

<p>{{quoteGroup.quotes.length }} Quotes</p>

</button>

 

</ion-list>

ואם נרצה שהרשימה תקבל גם חיצים ללחיצה בצד ימין או שמאל, אז בקובץ ה-variables.scss נוסיף את

$item-md-detail-push-show: true;

$item-wp-detail-push-show: true;

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

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

}

שיעור 10 ב- ionic, שימוש בטאבים \ תפריט צד (המבורגר)

הסבר תיאורטי על המנגנון של טאבים ב-ionic.

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

המחשה – עמוד טאבים ב-Ionic.

הקוד של העמוד הבא, הוא קוד רגיל של angular component, כאשר יש בתוך התבנית תגית של ion-tabs ובתוכה 2 טאבים.

שימו לב אל ההגדרות של כל טאב :

  • ההגדרה [root] – מביאה את הדף מתוך משתנה שמופיע במחלקה.
  • ההגדרה tabTitle – קובעת את הטקסט שיופיע על הטאב
  • ההגדרה tabIcon קובעת את האיקון שיופיע, כאשר הוא נלקח מספרית האיקונים של ionic.

צריך לזכור כמובן להוסיף את העמוד אל app.module.ts, וגם להגדיר בתוך app.component.html , את העמוד בתור ה-root של האפליקציה.

 

import { Component } from '@angular/core';
import { FavoritesPage } from './../favorites/favorites';
import { LibraryPage } from './../library/library';

@Component({
 selector:'page-tabs',
 template:`
 <ion-tabs>
 <ion-tab [root]="favoritesPage" tabTitle="מועדפים" tabIcon="star"></ion-tab>
 <ion-tab [root]="libraryPage" tabTitle="ספריה" tabIcon="book"></ion-tab>
 </ion-tabs>
 `
})
export class TabsPage{

 favoritesPage = FavoritesPage;
 libraryPage = LibraryPage;
}

מהו הטאב הראשון שנטען ? – זהו פשוט הטאב שמופיע ראשון בקוד.

אפשר לשנות זאת באמצעות המאפיין selectedIndex שמופיע בדוקומנטציה.

 

 

לבצע migrations ב- ef core עבור class library

לעיתים אנחנו מחלקים פרויקט למספר פרויקטים קטנים.

והקונטקס וגם המודלים עשויים להיות שמורים דווקא בפרויקט שמוגדר כ class library

במקרה כזה, כדי ליצור לו migtrations נשתמש בפרמטר שמגדיר עבורו startap project אחר, שהוא הפרויקט שמשתמש ב-context , והוא פרויקט שאינו class library, אלא למשל console application או asp.net core api וכדומה.

זו הפקודה לדוגמא

dotnet ef migrations add -s "C:\Users\Eyal\Documents\Visual Studio 2017\Projects\RimonimProjects\rimonim\Api\Api.csproj" MyMigrationNameComeHere

חשוב שזה ירוץ מתיקית הפרוייקט הספציפי שמוגדר כ-class library.

 

וכדי להריץ גם כן מתוך תיקית הפרוייקט :

dotnet ef database update  -s "C:\Users\Eyal\Documents\Visual Studio 2017\Projects\RimonimProjects\rimonim\Api"

שיעור 9 ב- ionic, שליטה בעיצוב הדף

כדי לשלוט בעיצוב, ionic משתמשת בקובץ scss, עבור כל עמוד בנפרד.

כאשר, בנוהל הרגיל של scss, אפשר לשרשר הגדרות בהיררכיה מסויימת.

איך זה מתקמפל ?

בזמן שנריץ, אז ionic תאחד את כל קבצי ה-scss, אל קובץ css אחד גדול

  • מה נגזר מכך ?
    • שאם נשים הגדרת css מחוץ לסוגרים שקשורים לעמוד , אז הם יהיו למעשה הגדרת css כוללת, שתוחל על כלל העמודים.

המחשה

התוצאה של קטעי הקוד הבאים, תהיה תגית p בצבע רקע אדום , רק בתוך עמוד ה-users.

 --- In the HTML file -----
 
 <p>Hi Man</p>
 
 
 --- In the scss File ----
 page-users {
 p {
 background-color: red;
 }
}

הגדרות כלליות של תבנית העיצוב ב-ionic

תחת תיקית theme, נמצא קובץ variables , ובו יש הגדרות כלליות של הצבעים, אפשר לשנות ולראות

$colors: (
 primary: #848484,
 secondary: #32db64,
 danger: #f53d3d,
 light: #f4f4f4,
 dark: #222
);

 

שיעור 13 באנגולר (angular) – מספר שיטות ל- Data Binding

באנגולר יש מספר שיטות לבצע Data Binding, כלומר לקשור בין ערך של משתנה בקלאס ובין משהו שמוצג על המסך.

נראה 3 שיטות, כולן משיגות את אותה תוצאה בסופו של דבר :

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

@Component({
 selector: 'app-data-binding2',
 template: `
 <img src="{{ imageUrl }}">
 <img [src]="imageUrl" >
 <img bind-src="imageUrl">
 
 
 `
})
export class DataBinding2Component implements OnInit {

 imageUrl:string = 'http://lorempixel.com/400/200';

 constructor() { }

 ngOnInit() {
 }

}

איך לקשור את תוכן התגית ב-HTML, באמצעות אנגולר

ישנה אפשרות נוספת להחליט על התוכן, באמצעות המאפיין [textContent]

זה נראה כך, והתוצאה היא שהטקסט שמוצג בתוך ה-span, הוא תוכן המשתנה.

<h4>Image URL : <span [textContent]="imageUrl"></span></h4>

איך לבצע הדלקה\כיבוי של פרמטרים בוליאנים באמצעו אנגולר

לעיתים יש מאפיינים בוליאנים של תגיות, כמו

  • "האם התגית צריכה להיות מוצגת או מוסתרת?"
  • האם הכפתור צריך להיות מאופשר או חסום ללחיצה ?

לצורך כך , נגדיר משתנה בוליאני , ונשייך אותו למאפיין המתאים :

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

@Component({
 selector: 'app-data-binding2',
 template: `
 
 <p [hidden]="!postChanged">Remmber to Save this post.</p>
 <button [disabled]="!postChanged">Save Post</button>

 `
})
export class DataBinding2Component implements OnInit {

 postChanged:boolean = false;

 constructor() { }

 ngOnInit() {
 }

}

שיעור 8 ב- ionic – מחזור חיים של דף

לדף ב-ionic, יש אירועים שהוא מגיב אליהם.

האירועים האלו הם בנוסף לאירועים הרגילים שעוברים על כל angular component.

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

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

  • אירועים "רגילים" מחזירים כלום (כלומר void), ופשוט מתרחשים בזמן שצריך.
  • אירועים שמחזירים תשובה בוליאנית, או promise בוליאני, ובהם אפשר להגיב להתרחשות \ אי-התרחשות של האירוע.

דוגמא למימוש אירוע רגיל

למשל סוג האירוע שמתרחש כאשר הדף נטען לראשונה למערך.

כדי לממש אותו, פשוט נכתוב בקובץ ה-ts פונקציה שנקראת בשם של האירוע – והוא יקרה.

ionViewDidLoad() {

console.log('ionViewDidLoad UsersPage');

}

 

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

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

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

בדף users, מימשתי אירוע של  ionViewCanEnter, כאשר ה-תשובה הבוליאנית , חוזרת  אל הפונקציה שטענה את הדף אל תוך המערך – כלומר התשובה מוחזרת לפונקציה בדף  home.

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

------- On home.ts file ---
 onGoToNewPage() {
 this.navCtrl.push(UsersPage)
 .then ((msg) => msg ? console.log("can access") : console.log("not access"));
 }
 
------ On users.ts file ---
ionViewCanEnter(): boolean|Promise<boolean>{
 console.log('ionViewCanEnter');
 const rnd = Math.random();
 console.log(rnd);
 return rnd>0.5;
 }