איך להוסיף xsi nil בשפת c# עבור nodes של XML

בחלק מהמקומות שבהם משתמשים ב-XML, יש דרישה לעיתים, שענפים (=שדות) ריקים , יופיעו עם ה-attribute

 xsi:nil="true"

כדי להוסיף אותו כאשר עושים סיריליזציה לאובייקט קיים ( ולא משתמשים ב- XmlWriter כדי לכתוב ענף אחרי ענף , אלא עושים סיריליזציה )

אז כדי ליצור מצב שמתווסף ה-attribute הזה

צריך לעשות 2 דברים :

  1. לוודא שיש לו הגדרה של IsNullable
 [XmlElement(ElementName = "Koko", IsNullable = true)]
public string Koko;

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

 

myObject.myVar = null;

 

בהצלחה.

מאפייני CSS בנושא מיקום – float, position, ועוד

סיכום של נושאים חשובים לעניין מיקום ב-CSS

  • חשוב להכיר טוב את מודל התיבה
  • המאפיין float = ציפה, קובע לאן האלמנט יצוף בתוך המיכל (קונטיינר) שלו.
    • כלומר, float:left – אז האלמנט יצוף שמאלה בתוך המיכל שלו
    • מה שקורה לשאר האלמנטים במיכל – הוא שהם "מאפשרים לאלמנט" לצוף – כלומר מסתדרים סביבו.
    • למשל – אם נשים טקסט, יחד עם תמונה, בתוך אותו div
      והתמונה תהיה עם float
      אז הטקסט יסתדר לצידה מעצמו.
  • סידור של רשימה תבליטים (li) לרוחב
    • ברגע שמחילים על רשימה את המאפיין display:inline-block, אז התבליטים (=נקודות) מסתדרות לרוחב ולא לגובה.
    • אם רוצים לקבוע את הגודל של כל אלמנט ברשימה, אפשר עם box-sizing: 40% לדוגמא.
  • סידור אלמנטים בתור "טבלה"
    • כדאי להכיר שקיימת גם אפשרות שנקראת display:table, ואז כל אחד מהאלמנטים בתוך ה"טבלה", צריך להיות עם display:table-cell.
      מה שזה גורם הוא – שהאלמנטים מוצגים כמו ב-tr/td/ וכו'
  • המאפיין position 
    • כאשר מגדירים משהו בתור position:relative, זו הגדרת ברירת המחדל שלו, מה שאומר שאם נוסיף לו למשל left:20px אז הוא יזוז 20 פיקסלים מהמקום שבו הוא היה אמור להיות.
    • לעומת זאת אם נגדיר position:absolute, זה יגרום למיקום אבסולטי ביחס למיכל ( קונטיינר) שלו.
  • המאפיין overflow – מאפשר לקבוע מה קורה לאלמנטים בתוך המיכל, שחורגים מגודל המיכל.
    למשל אם יש לי div פנימי שמוכל בתוך div חיצוני.
    והרוחב של הפנימי חורג מהרוחב של החיצוני.
    אז אם נאמר ב-css של ה-div החיצוני, את ההגדרה הבאה :
overflow: hidden;

אז כל התוכן של ה-div הפנימי שחורג מהחיצוני, יוסתר.

  • מאפיין margin – יכול גם להיות שלילי.
  • אנימציות פשוטות – אפשרי לעשות באמצעות
transition: all 0.5s;

 

מודל התיבה ב- CSS (סיכום)

  • ב-CSS יש בגדול 2 סוגי אלמנטים : inline / block
    • block – תופס כברירת מחדל את כל רוחב השורה
    • inline – תופס רק את הקטע המסויים שבתוך השורה, ולא פותח שורה חדשה.
      • לדוגמא p הוא block
  • כל אלמנט בלוק מכיל:
    • תוכן  , שאת הגודל שלו קובעים עם height+width וברירת המחדל – רוחב מלא, גובה מלא
    • ריפוד padding – זה גבול פנימי בתוך האלמנט שבתוכו אין כלום ( כדי להבדיל את האלמנט, מאלמנטים אחרים בתוך המיכל).
    • גבול border  – מצויר מסביב לאלמנט – כלומר מגדיל אותו
    • שוליים  margin  –  זה קובע את הרווח בין האלמנט הזה, לאלמנטים אחרים.
      • כלומר שוליים של 0 גורמות לאלמנטים להיות צמודים אחד לשני.
      • בנוסף – לאלמנטים יש ברירות מחדל, והן לא תמיד אפס.
  • כלומר בברירת המחדל – אלמנט לא תופס רק את הגודל של התוכן שלו, אלא יותר מזה, כי יש גם תוספות לריפוד, לגבול, ולשוליים שלו.
  • כדי להקל על עצמנו, אפשר להגדיר את המאפיין
box-sizing: border-box;

זה גורם לגודל של הריפוד + הגבול – להיחשב בתוך האלמנט. (השוליים עדין נשארים מחוץ לאלמנט).

  • כל אלמנט , יש לו הגדרה ברירת מחדל לגבי צורת התצוגה שלו, כלומר האם הוא נחשב block או inline
    • למשל בנוגע לאלמנט פיסקה p, ברירת המחדל היא שהוא block
    • אם רוצים לשנות זאת, עושים את זה באמצעות המאפיין display
display:inline;
  • הסבר הערכים השונים :
    • display: inline – הדפדפן מתעלם מהרוחב מהגובה של האלמנט, ומסדר אותם כאילו הם טקסט בתוך שורה .
    • display:inline-block – הדפדפן מתייחס לאלמנט כאילו הוא בלוק , אבל בתוך שורה, כלומר הוא כן מתייחס לגובה ולרוחב, אבל בתוך שורה, ואם ישאר מקום לעוד אלמנטים – אז גם הם יכנסו בתוך השורה.
      צריך לזכור – שבמצב כזה, הדפדפן מתייחס גם לירידת שורה בתוך קוד ה-html. זאת אומרת שירידת שורה =שווה= רווח בתצוגה על המסך.
    • display:block – כלומר תתיחס כמו בלוק, שתופס שורה שלמה
  • בנוגע להגדרות רוחב\גובה :
    • בפיקסלים – ברור לנו.
    • באחוזים – הכוונה אחוז מתוך המיכל שלו

 

 

סלקטורים ב-CSS ( סיכום )

לפעמים אני חוזר על חומרים בסיסיים לעצמי. החלטתי לחזור קצת על CSS Selectors, כי ביום-יום אני פחות מתעסק עם זה (כל החיתוכים ל-html נשלחים לחו"ל).

  • ב-CSS יש מספר אפשרויות לבחור את האלמנטים בדף.
  • האפשרויות האלו נקראות Selectors.
  • והן משמשות אותנו גם ב-JS כדי לבחור אלמנטים בדף.

סיכום מקוצר של Css Selectors

  • id ——– #bubu
  • class ———.myClass
  • Descendant ——- p a li
  • state —— input:foucs
  • excat hirarcy – li:nth-child(2n

קדימות ב-CSS

לפי הסדר הבא : inline style > id > classes > elements

סוגי Css Selectors

  • לפי id של האלמנט – מתחיל בסימן סולמית

המחשה :

#myId {
bla...
bla...
}
  • לפי class  – מתחיל בסימן נקודה

המחשה :

.myClass {
bla...
bla...

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

המחשה  –  רק תגיות a עם הקלאס bubu  שנמצאות בתוך פיסקה (p) – רק הן יבחרו.

p a .bubu {
bla
bla...

  • לפי מצב האלמנט (hover… ) – מסומן בסימן נקודתיים :

המחשה :

input:focus { 
dsfsd
sdf

  • לפי רמת היררכיה מדוייקת בעץ – משתמשים במילים קבועות כמו first-child , או לחלופין בפקודת ה-CSS nth-child עם מספר הרמה בהיררכיה בתוך סוגרים

המחשה :

.myClass:nth-child(2n) {
bla..
bla..
}

li:first-child {
bla..
bla...
}

 

כללי קדימויות ב-CSS

  • הקדימות ב-CSS היא לפי הדירוג הבא :
    • תגית style בתוך ה-HTML
    • אחריה CSS שעוסקים ב- #id
    • אחריה CSS עבור קלאסים
    • ואחריה CSS עבור אלמנטים רגילים.

גיבוי , ושיחזור מגיבוי של MariaDb / MySql

בפוסט הזה, אציג בקצרה גיבוי ושיחזור של DB של mysql .

 

גיבוי mysql \ MariaDb

יש כלי cli שנקרא mysqldump ,

השימוש בו פשוט מאוד,

mysqldump --user MY_USER_NAME MY_DATABASE_NAME > MY_BACKUP_FILE_NAME.sql
  •  שימו לב שבאפשרות הבסיסית, אין את משפט ה- Create Database
  • בנוסף, אם אתם משתמשים בו על Windows, אז כדאי לשים לב לגודל האותיות, כיוון שהתקנת ברירת המחדל במערכות Windows, היא כאשר כל האותיות בשמות הטבלאות \ DB – הם קטנות, ובלינוקס…זה מהותי.

שיחזור מגיבוי MySql \ MariaDB

  • לכלי ה-cli הרגיל של mysql\mariadb , יש אפשרות  לקבל קבצים בתור קלט (כמו כל תוכנת cli נורמלית)
  • רק …צריך לודא שהקובץ מכיל את ה-use המתאים לדאטאבייס שאתם רוצים.
  • ובמידה ויוצרים DB , אז את משפט ה-Create  המתאים.

השימוש :

mysql -u MY_USER_NAME < MY_IMPORTED_FILE_NAME.sql

 

הערה כללית :

  • כמובן במידה והיוזר שאיתו אתם ניגשים דורש סיסמא, אזי הוסיפו את האפשרות הבאה
-pPASSWORD

שימו לב שהסיסמא "דבוקה" לתגית ה-p.

בהצלחה

יכולות מספור ומעבר עמודים של wkhtmltopdf

יצירת PDF באתר אינטרנט

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

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

אני כבר כמה שנים משתמש בכלי צד שרת שנקרא wkhtmltopdf.

ההתקנה על windows קלה ביותר.

ההתקנה על linux , עם עברית – עשויה להיות מורכבת, ולא פשוטה כלל.

אחרי שהכלי מותקן על השרת ועובד, השימוש בו מאוד פשוט, זהו למעשה דפדפן שרת פקודה, שמאפשר להדפיס כל עמוד html, לקובץ PDF, עם יכולות עימוד טובות.

כמובן , שצריך לבצע התאמות CSS וכו',

בפוסט הזה אראה 2 יכולות שלו בנוגע למעבר עמוד, ובנוגע למיספור:

מעברי עמוד ב- wkhtmltopdf

  • יש אנשים שפשוט ידאגו שכל העמודים יהיו בגודל של A4, וגם זו שיטה.
  • אני פחות אוהב, ולכן אני מגדיר 3 קלאסים של CSS ומשתמש בהם לפי הצורך.
  • אין צורך לשים את זה ב-media של print, כי זה פשוט לא יעבוד.
.keep-together {

    page-break-inside: avoid;

}

.break-before {

    page-break-before: always;

}

.break-after {

    page-break-after: always;

}

מספרי עמודים ב-wkhtmltopdf

  • אני מדגים את מספרי העמודים בהנחה שיש לכם עמוד \ route נפרד עבור ה- footer
  • אבל…זה אפשרי כמובן לשלב בעמוד של ה-content העיקרי.
  • הרעיון פשוט – מגדירים פונקצית JS שמעבירה את העמודים
  • בתגית ה- body  – נפעיל אותה
  • ואז במקום שנרצה נשים את הערכים הרלוונטים עבור עמוד…מתוך….
<script>
  function subst() {
      var vars = {};
      var query_strings_from_url = document.location.search.substring(1).split('&');
      for (var query_string in query_strings_from_url) {
          if (query_strings_from_url.hasOwnProperty(query_string)) {
              var temp_var = query_strings_from_url[query_string].split('=', 2);
              vars[temp_var[0]] = decodeURI(temp_var[1]);
          }
      }
      var css_selector_classes = ['page', 'frompage', 'topage', 'webpage', 'section', 'subsection', 'date', 'isodate', 'time', 'title', 'doctitle', 'sitepage', 'sitepages'];
      for (var css_class in css_selector_classes) {
          if (css_selector_classes.hasOwnProperty(css_class)) {
              var element = document.getElementsByClassName(css_selector_classes[css_class]);
              for (var j = 0; j < element.length; ++j) {
                  element[j].textContent = vars[css_selector_classes[css_class]];
              }
          }
      }
  }
</script>
<body  onload="subst()">

 

עמוד <span class="page"></span> מתוך <span class="topage"></span>

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

}