تزریق سرویس‌ها (Service) درون یکدیگر در انگولار

16 آبان 1397
angular-di-services

همانطور که در فصل گذشته مشاهده کردید سرویس‌ها را به صورت کامل مطرح و مورد بررسی قرار دادیم. حال در این بخش قصد داریم مبحث سرویس‌ها را تکمیل کرده و به نحوه‌ی تزریق سرویس‌ها درون یکدیگر بپردازیم.

ادامه مثال فصل گذشته

برای مطالعه‌ی این بخش حتما و حتما فصل گذشته را بررسی بفرمایید.

در صورتیکه فایل app.module.ts‌ را باز کنید متوجه خواهید شد که یک عبارت تحت عنوان provider درون این کلاس که به عنوان اصلی‌ترین و بالاترین کلاس ممکن در نرم‌افزار شناخته می‌شود، قرار گرفته است.

حال می‌خواهیم provider های موجود در کلاس new-account.component.ts و account.component.ts را حذف کرده و به فایل app.module.ts انتقال دهیم تا سرویس‌ها درون تمام کامپوننت‌ها در دسترس باشند. بنابراین درون فایل app.module.ts‌ تغییرات زیر را خواهیم داشت:

import {BrowserModule} from '@angular/platform-browser';
import {HttpModule} from '@angular/http';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';

import {AppComponent} from './app.component';
import { AccountComponent } from './account/account.component';
import { NewAccountComponent } from './new-account/new-account.component';
import {AccountsService} from "./accounts.service";
import {LoggingService} from "./logging.service";



@NgModule({
    declarations: [
        AppComponent,
        AccountComponent,
        NewAccountComponent,

    ],
    imports: [
        BrowserModule,
        HttpModule,
        FormsModule
    ],
    providers: [AccountsService, LoggingService],
    bootstrap: [AppComponent]
})
export class AppModule {
}

حال می‌خواهیم از سرویس LoggingService درون سرویس AccountsService استفاده کنیم. به عبارت دیگر می‌خواهیم یک سرویس را درون سرویس دیگری تزریق کرده و مورد استفاده قرار دهیم.

بنابراین دستورهای this.loggingService را از هر دو کامپوننت account و new-account‌ حذف می‌کنیم. پس فایل new-account.component.ts‌ به صورت زیر خواهد بود:

import {Component, OnInit} from '@angular/core';
import {LoggingService} from '../logging.service'
import {AccountsService} from "../accounts.service";

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

    constructor(private loggingService: LoggingService, private accountsService: AccountsService) {
    }

    ngOnInit() {
    }

    onCreateAccount(accountName: string, accountStatus: string) {
        this.accountsService.addAccount(accountName, accountStatus);
        // this.loggingService.logStatusChanged(accountStatus);
    }

}

و همچنین فایل account.component.ts نیز به صورت زیر تغییر می‌کند:

import {Component, Input, OnInit} from '@angular/core';
import {LoggingService} from "../logging.service";
import {AccountsService} from "../accounts.service";

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

    @Input() account: { name: string, status: string }
    @Input() id: number;


    constructor(private loggingService: LoggingService, private  accountsService: AccountsService) {
    }

    ngOnInit() {
    }

    onSetTo(status: string) {
        this.accountsService.updateStatus(this.id, status);
        // this.loggingService.logStatusChanged(status);
    }

}

خب حالا نوبت به آن رسیده است که سرویس LoggingService را به AccountsService تزریق کنیم.

بنابراین فایل AccountsService را باز کرده و دستورات زیر را درون آن قرار می‌دهیم که مشابه استفاده از یک سرویس درون یک سازنده‌ی پیش‌فرض و در نهایت فراخوانی متد مربوطه است:

import {LoggingService} from "./logging.service";
export class AccountsService{

    accounts = [
        {
            name: 'حساب کابری مدیر کل',
            status: 'فعال'
        },
        {
            name: 'اکانت تست',
            status: 'غیرفعال'
        },
        {
            name: 'حساب کاربری مخفی',
            status: 'مخفی'
        }
    ];

    constructor(private loggingService: LoggingService){

    }

    addAccount(name: string, status:string){
        this.accounts.push({name: name, status: status});
        this.loggingService.logStatusChanged(status);
    }

    updateStatus(id: number, status:string){
        this.accounts[id].status = status;
        this.loggingService.logStatusChanged(status);
    }

}

در صورتیکه نرم‌افزار خود را در آدرس http://localhost:4200 تست کنید درون کنسول یک خطا مشاهده خواهید کرد که همه‌ی پارامترها درون این سرویس استفاده نشده است. حال برای برطرف این خطا باید یک مفسر و دکوراتور به نام Injectable@‌ استفاده خواهیم کرد.

مفسر Injectable@ در انگولار

مفسر یا دکوراتور Injectable‌ برای تزریق یک سرویس درون دیگری مورد استفاده قرار می‌گیرد. بنابراین فایل accounts.service.ts را باز کرده و تغییرات را به صورت زیر اعمال خواهیم کرد:

import {LoggingService} from "./logging.service";
import {Injectable} from "@angular/core";

@Injectable()
export class AccountsService{

    accounts = [
        {
            name: 'حساب کابری مدیر کل',
            status: 'فعال'
        },
        {
            name: 'اکانت تست',
            status: 'غیرفعال'
        },
        {
            name: 'حساب کاربری مخفی',
            status: 'مخفی'
        }
    ];

    constructor(private loggingService: LoggingService){

    }

    addAccount(name: string, status:string){
        this.accounts.push({name: name, status: status});
        this.loggingService.logStatusChanged(status);
    }

    updateStatus(id: number, status:string){
        this.accounts[id].status = status;
        this.loggingService.logStatusChanged(status);
    }

}

بسیار عالی خطا برطرف شد و هم اکنون تمام قسمت‌ها به صورت کامل در دسترس می‌باشد.

برای بهینه‌ کردن یک نرم‌افزار آخرین مرحله را انجام می‌دهیم. اگر فایل app.component.html را باز کنید ملاحظه خواهید کرد که درون هر دو کامپوننت app-new-account و app-account دو event به مرحله‌ی بالاتر یعنی کامپوننت مادر ارسال می‌شوند.

در حالیکه متدهای پاسخی موردنظر درون کامپوننت‌های فرزند وجود ندارند بلکه آنها را به سرویس‌ها انتقال داده‌ایم. حال برای دسترسی به این اطلاعات باید فایل app.component.html را به صورت زیر ویرایش کنیم:

<div class="container" dir="rtl" style="margin-top: 30px;">
    <div class="row">
        <div class="col-xs-12">
            <app-new-account></app-new-account>
        </div>
    </div>
    <hr>
    <app-account
            *ngFor="let acc of accounts; let i= index"
            [id]="i"
            [account]="acc"
    >
    </app-account>
</div>

سپس یک متد برای پاسخ رویدادها درون accounts.service.ts ایجاد می‌کنیم:

import {LoggingService} from "./logging.service";
import {EventEmitter, Injectable} from "@angular/core";

@Injectable()
export class AccountsService{

    accounts = [
        {
            name: 'حساب کابری مدیر کل',
            status: 'فعال'
        },
        {
            name: 'اکانت تست',
            status: 'غیرفعال'
        },
        {
            name: 'حساب کاربری مخفی',
            status: 'مخفی'
        }
    ];

    constructor(private loggingService: LoggingService){

    }

    statusUpdated = new EventEmitter<string>();

    addAccount(name: string, status:string){
        this.accounts.push({name: name, status: status});
        this.loggingService.logStatusChanged(status);
    }

    updateStatus(id: number, status:string){
        this.accounts[id].status = status;
        this.loggingService.logStatusChanged(status);
    }

}

در نتیجه برای استفاده از این ویژگی فایل account.component.ts را باز کرده و ویرایش زیر را انجام می‌دهیم:

import {Component, Input, OnInit} from '@angular/core';
import {LoggingService} from "../logging.service";
import {AccountsService} from "../accounts.service";

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

    @Input() account: { name: string, status: string }
    @Input() id: number;


    constructor(private loggingService: LoggingService, private  accountsService: AccountsService) {
    }

    ngOnInit() {
    }

    onSetTo(status: string) {
        this.accountsService.updateStatus(this.id, status);
        this.accountsService.statusUpdated.emit(status);
        // this.loggingService.logStatusChanged(status);
    }

}

بسیار عالی با اینکار در واقع تغییرات به سرویس accounts.services.ts توسط یک رویداد یا فشردن یک دکمه اتفاق می‌افتد.

بسیار عالی به شما عزیزان مجددا تبریک می‌گوییم. مبحث مربوط به سرویس‌ها به صورت کامل در فصل بعدی پوشش داده شد و امیدواریم که مورد پسند شما عزیزان واقع شده باشد. در فصل بعدی به آموزش مباحث مربوط به Routing می‌پردازیم. با ما همراه باشید.

توجه: دوستان عزیز آموزش ویدیویی انگولار 6 از مقدماتی تا پیشرفته به زبان فارسی را می‌توانید با کلیک روی اینجا یاد بگیرید.

دوره آموزش انگولار به زبان فارسی + پروژه ساخت فروشگاه اینترنتی

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان انگولار توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

حمیدرضارضایی
21 اسفند 1396
سلام واقعا از آموزش های فوق العاده تون سپاسگذارم فقط یه نکته کوچیک توی کدها وجود دارده فایل new-account.component.ts‌ سطر دومش یک کاراکتر ; کم داره که به من ایراد میگیره اگه اصلاح کنید ممنون میشم چون دوستانی که کدها را عینا کپی می کنند با مشکل مواجه نشوند.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.