קודקודייל
  • קודקודייל
  • מי אתם קודקודייל?
  • קורסים בחינם
  • צרו קשר
  • בניית אתרים
    • וורדפרס
  • נגישות אתרים
  • כל הקטגוריות
    • אנגולר
    • HTML
    • CSS
    • Javascript
    • Typescript
    • NodeJs
    • בלוקציין
  • קודקודייל
  • מי אתם קודקודייל?
  • קורסים בחינם
  • צרו קשר
  • בניית אתרים
    • וורדפרס
  • נגישות אתרים
  • כל הקטגוריות
    • אנגולר
    • HTML
    • CSS
    • Javascript
    • Typescript
    • NodeJs
    • בלוקציין
קודקודייל
  • קודקודייל
  • מי אתם קודקודייל?
  • קורסים בחינם
  • צרו קשר
  • בניית אתרים
    • וורדפרס
  • נגישות אתרים
  • כל הקטגוריות
    • אנגולר
    • HTML
    • CSS
    • Javascript
    • Typescript
    • NodeJs
    • בלוקציין
  • קודקודייל
  • מי אתם קודקודייל?
  • קורסים בחינם
  • צרו קשר
  • בניית אתרים
    • וורדפרס
  • נגישות אתרים
  • כל הקטגוריות
    • אנגולר
    • HTML
    • CSS
    • Javascript
    • Typescript
    • NodeJs
    • בלוקציין
ראשי ♦ Typescript ♦ מדריך angular standalone component חלק 2

מדריך angular standalone component חלק 2

עידן יצחקי 20 בינואר 2024 אין תגובות

אחרי שראינו lazy loading component בעזרת הראוט, ניצור עוד דף ועוד רכיבים, נחבר אותם העזרת שירות ונעבור על עוד מספר נקודות קטנות בדרך.

תחילה ניצור רכיב חדש, נפתח את ה-CMD בספריה PAGES ונריץ את הפקודה הבאה

C:\my-standalone-project\src\app\pages>ng g c about

נוסיף לראוט שלנו את הדף החדש שיצרנו

import { Routes } from '@angular/router';

export const routes: Routes = [
    {
        path: '', loadComponent: () => import('./pages/home/home.component').then(p => p.HomeComponent)
    },
    {
        path: 'about', loadComponent: () => import('./pages/about/about.component').then(p => p.AboutComponent)
    }
];

כשהפרויקט רץ, נגלוש לכתובת: http://localhost:4200/about

ונראה שאכן אנחנו מצליחים להגיע לדף שיצרנו.

כדאי שיהיה לנו יותר קל להבחין בדף שאנחנו נמצאים נעשה שינויים בדף הבית ובדף אודות כך:

<h1>home works!</h1>
<a routerLink="about">About</a>
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';

@Component({
  selector: 'app-home',
  standalone: true,
  imports: [RouterModule], // added
  templateUrl: './home.component.html',
  styleUrl: './home.component.scss'
})
export class HomeComponent {

}
<h1>about works!</h1>
<a routerLink="/">Home</a>
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';

@Component({
  selector: 'app-about',
  standalone: true,
  imports: [RouterModule], // added
  templateUrl: './about.component.html',
  styleUrl: './about.component.scss'
})
export class AboutComponent {

}

עכשיו שיש לנו קצת תוכן, נמחק מהקובץ הראשי את התוכן המיותר שיש בו

<router-outlet></router-outlet>

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

בשלב הזה, נוסיף 2 רכיבים, אחד יתארח בדף הבית והשני בדף אודות. אחרי זה נחבר אותם בשירות אחד לשני.

נפתח CMD בספרית components ונריץ את הפקודות הבאות:

C:\my-standalone-project\src\app\components>ng g c name-input
C:\my-standalone-project\src\app\components>ng g c show-name

ברכיב name-input נבצע את השינויים הבאים

<div class="name-input">
    <h2>Who am I?</h2>
    <form [formGroup]="form">
        <label>
            <span>Full name</span>
            <input type="text" formControlName="fullName">
        </label>
        <button type="button" (click)="onSaveName()">Save</button>
    </form>
</div>
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';

@Component({
  selector: 'app-name-input',
  standalone: true,
  imports: [ReactiveFormsModule],
  templateUrl: './name-input.component.html',
  styleUrl: './name-input.component.scss'
})
export class NameInputComponent implements OnInit {
  form: FormGroup = new FormGroup({});
  constructor() { }
  ngOnInit(): void {
    this.form = new FormGroup({
      fullName: new FormControl('')
    })
  }
  onSaveName() {
    console.log(this.form.value);
  }
}

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

נוסיף את הרכיב לדף הבית

<h1>home works!</h1>
<a routerLink="about">About</a>
<div>
    <app-name-input></app-name-input>
</div>
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { NameInputComponent } from '../../components/name-input/name-input.component';

@Component({
  selector: 'app-home',
  standalone: true,
  imports: [RouterModule, NameInputComponent], // added
  templateUrl: './home.component.html',
  styleUrl: './home.component.scss'
})
export class HomeComponent {

}

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

הרכיב הבא שנשנה יהיה show-name

<div class="show-name">
    <h2>My name is.... {{fullName}}</h2>
</div>
import { Component } from '@angular/core';

@Component({
  selector: 'app-show-name',
  standalone: true,
  imports: [],
  templateUrl: './show-name.component.html',
  styleUrl: './show-name.component.scss'
})
export class ShowNameComponent {
  fullName: string = '';
}

וכמובן שנחבר אותו לדף אודות

<h1>about works!</h1>
<a routerLink="/">Home</a>
<div>
    <app-show-name></app-show-name>
</div>
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { ShowNameComponent } from '../../components/show-name/show-name.component';

@Component({
  selector: 'app-about',
  standalone: true,
  imports: [RouterModule,ShowNameComponent],
  templateUrl: './about.component.html',
  styleUrl: './about.component.scss'
})
export class AboutComponent {

}

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

זה הזמן לחבר אותם, ונעשה את זה בעזרת שירות (service).

ניצור בספרית APP ספריה בשם services ובתוכה נריץ את הפקודה הבאה

C:\my-standalone-project\src\app\services>ng g s information

נכנס לקובץ החדש שנוצר ונערוך אותו כך

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

@Injectable({
  providedIn: 'root'
})
export class InformationService {

  private fullNameInfo = new BehaviorSubject('');
  public fullNameInfo$ = this.fullNameInfo.asObservable();

  constructor() { }

  setFullNameInfo(data: string) {
    this.fullNameInfo.next(data);
  }

}

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

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

אנחנו שומרים עליו בסוד כדאי שלא ישכתבו אותו מבחוץ. מחצינים משתנה נוסף שמשקף את הערך שיש במשתנה הסודי שלנו.

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

עכשיו לחיבורים 😁.

תחילה הרכיב שכותב

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { InformationService } from '../../services/information.service';

@Component({
  selector: 'app-name-input',
  standalone: true,
  imports: [ReactiveFormsModule],
  templateUrl: './name-input.component.html',
  styleUrl: './name-input.component.scss'
})
export class NameInputComponent implements OnInit {
  form: FormGroup = new FormGroup({});
  constructor(private informationService: InformationService) { }
  ngOnInit(): void {
    this.form = new FormGroup({
      fullName: new FormControl('')
    })
  }
  onSaveName() {
    this.informationService.setFullNameInfo(this.form.value.fullName);
  }
}

נעדכן גם את הרכיב שקורא

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

@Component({
  selector: 'app-show-name',
  standalone: true,
  imports: [],
  templateUrl: './show-name.component.html',
  styleUrl: './show-name.component.scss'
})
export class ShowNameComponent implements OnInit {
  fullName: string = '';
  constructor(private informationService: InformationService) { }
  ngOnInit(): void {
    this.informationService.fullNameInfo$.subscribe(info => {
      this.fullName = info
    })
  }
}

לאחר ששמרנו, נלך לדף הבית, נכתוב משהו ונלחץ על שמירה.

נעבור לדף אודות ושם נראה את מה שכתבנו נוסף להמשך המשפט.

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

import { Component, OnDestroy, OnInit } from '@angular/core';
import { InformationService } from '../../services/information.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-show-name',
  standalone: true,
  imports: [],
  templateUrl: './show-name.component.html',
  styleUrl: './show-name.component.scss'
})
export class ShowNameComponent implements OnInit, OnDestroy {
  fullName: string = '';
  info$ = new Subscription;
  constructor(private informationService: InformationService) { }
  ngOnInit(): void {
    this.info$ = this.informationService.fullNameInfo$.subscribe(info => {
      this.fullName = info
    })
  }
  ngOnDestroy(): void {
    this.info$.unsubscribe();
  }
}

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

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

import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { InformationService } from '../../services/information.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-name-input',
  standalone: true,
  imports: [ReactiveFormsModule],
  templateUrl: './name-input.component.html',
  styleUrl: './name-input.component.scss'
})
export class NameInputComponent implements OnInit, OnDestroy {
  form: FormGroup = new FormGroup({});
  info$ = new Subscription;
  fullname: string = '';
  constructor(private informationService: InformationService) { }
  ngOnInit(): void {
    this.info$ = this.informationService.fullNameInfo$.subscribe(info => {
      this.fullname = info;
    })
    this.form = new FormGroup({
      fullName: new FormControl(this.fullname)
    })
  }
  onSaveName() {
    this.informationService.setFullNameInfo(this.form.value.fullName);
  }
  ngOnDestroy(): void {
    this.info$.unsubscribe();
  }
}

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

דבר אחרון לפני סיום, כאשר נרצה לחבר לשירות שלנו קריאה לשרת (HTTP) , למרות שהכל נראה תקין ולא נראה שיש שגיאות

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class InformationService {

  private fullNameInfo = new BehaviorSubject('');
  public fullNameInfo$ = this.fullNameInfo.asObservable();

  constructor(private http: HttpClient) { }

  setFullNameInfo(data: string) {
    this.fullNameInfo.next(data);
  }
  updateDB() {
    this.http.post('/', '').subscribe(data => {

    })
  }
}

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

ERROR NullInjectorError: R3InjectorError(Standalone[_HomeComponent])[_InformationService -> _InformationService -> _InformationService -> _HttpClient -> _HttpClient]: 
  NullInjectorError: No provider for _HttpClient!

איך לתקן את זה? זוכרים שבחלק הראשון אמרתי שנחזור לקובץ config…

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [provideRouter(routes), provideHttpClient()]
};

אנחנו מספקים את HTTPCLIENT באופן גלובלי באפליקציה ולכן גם השגיאה יורדת והאתר חוזר לפעול כרגיל

🤯 נראה לי שלצעדים הראשונים ב-standalone זה מספיק, בהצלחה ✌️

פוסטים קשורים:

מדריך angular standalone component חלק 1 תמונת אווירה של חצים לכל הכיווניםבניה של טופס דינמי על פי מידע מהשרת באנגולר אפשרויותAngular nested routes מדריך אנגולגר טופס ריאקטיבי שיעור 2מדריך אנגולר | reactive forms – היכרות בסיסית עם AbstractControl
angular מדריך אנגולר

אודות המחבר

עידן יצחקי להציג את כל הפוסטים של עידן יצחקי


« פוסט קודם
פוסט הבא »

השארת תגובה

ביטול

חיפוש באתר
בחירת העורכים
29 בדצמבר 2023 עידן יצחקי

שדה טקסט עשיר עם תמונות

אתם הולכים להיות מופתעים עד כמה HTML יכול להיות חכם ולבצע משהו כל כך מורכב, שאם אנחנו היינו רוצים ליצור

1 באוקטובר 2021 עידן יצחקי

איך למשוך דינמית favicon של אתרים אחרים ב-JS

בפוסט זה נראה איך אפשר על פי לינקים בדף למשוך את ה-favicon מהדומיין שלהם באופן דינמי, בדיקה של תקינות התמונה

פופולרי
Javascript functions – היכרות עם סוגי פונקציות
Javascript
21 בדצמבר 2024 אין תגובות
Nested routing in angular standalone component
Typescript
15 בנובמבר 2024 תגובה אחת
בחרו לפי תגיות
angular blockchain css ethers express front-end fullstack GQL html javascript next js nextjs nodejs react hooks reactjs solidity webgl אנגולר בלוקציין וורדפרס לימודי אנגולר לימודי וורדפרס לימוד ריאקט מדריך front-end מדריך GQL מדריך אנגולר מדריך וורדפרס מדריך חינם react מדריך ריאקט מפתח בלוק מפתח בלוקציין מתכנת front-end מתכנת בלוקציין מתכנת פרונט סולידיטי קורס front end קורס fullstack קורס nextjs קורס אנגולר קורס בלוקציין קורס בלוקציין בחינם קורס סולידיטי קורס ריאקט קורס תכנות קורס תכנות בחינם
סינון על פי קטגוריות
CSS fullstack HTML IIS Javascript nodeJs SEO Typescript אנגולר בלוקציין בניית אתרים וורדפרס חיפוש עבודה כלים נוספים כללי נגישות קורסים ריאקט תלת מימד תקלות ופתרונות
צור קשר
כל הזכויות שמורות לקודקודייל
ליצירת קשר: @ קודקודייל
גלילה לראש העמוד