ارسال داده بین کامپوننت‌ها (والد به فرزند و فرزند به والد) در انگولار

15 آبان 1397
angular-component-communication

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

شروع با یک مثال

برای اینکه تمرینی برای شما عزیزان شده باشد با یک مثال شروع می‌کنیم تا مروری به مباحث قبل داشته باشیم.

در این مثال دو فرم در اختیار خواهیم داشت که با کلیک کردن روی هر یک از دکمه‌های این فرم می‌خواهیم یک سرور به صفحه اضافه شود.

مثلا اگر روی دکمه‌ی «سرور داخلی» کلیک کردیم متن «سرور داخلی با موفقیت اضافه شد» چاپ شود و اگر روی دکمه‌ی سرور خارجی کلیک کردیم نیز متن «سرور خارجی با موفقیت اضافه شد» نمایش داده شود.

بنابراین یک پروژه‌ی جدید ایجاد کرده و سپس درون آن یک کامپوننت به نام servers با استفاده از دستور زیر تولید می‌کنیم:

ng g c servers

سپس برای رعایت ساختار تو در تو یک کامپوننت دیگر به نام server درون این کامپوننت به صورت زیر تعریف می‌کنیم:

ng g c servers/server

با اجرای این دستور یک پوشه به نام server درون این پوشه‌ی servers ایجاد می‌شود.

حال درون فایل server.component.ts که به عنوان کنترلر برنامه به حساب می‌آید کدهای زیر را لحاظ می‌کنیم:

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

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

    serverName: string = '';
    serverContent: string = '';
    serverList = [];


    constructor() {
    }


    ngOnInit() {
    }

    onCreateLocalServer() {
        this.serverList.push({
            name: this.serverName,
            content: this.serverContent
        });
    }

    onCreateExternalServer() {
        this.serverList.push({
            name: this.serverName,
            content: this.serverContent
        });
    }
}

با بررسی این فایل متوجه خواهید شد که دو متد به نام‌های onCreateLocalServer و onCreateExternalServer جهت پاسخ به فشردن هر یک از دکمه‌ها توسط کاربر، ایجاد کرده ایم و سپس درون آنها متغییرهای name و content را متناسب با آنچه از ngModel‌ در قالب HTML دریافت می‌کنیم قرار داده ایم.

نکته:‌ توجه داشته باشید که عبارت serverList‌ بدون نوع تعریف شده است، زیرا مقادیر درون آن به صورت یک جفت key و value‌ بوده که به عنوان شیء جاوا اسکریپت شناخته می‌شود.

به مثال زیر توجه کنید:

serverList = [{name: string = "roxo", content: string="این سرور در داخل کشور قرار دارد"}]

یک شیء جاوا اسکریپت ساخته شده که مقادیر آن به صورت key:value‌ هستند. بنابراین در فایل server.component.html نیز خواهیم داشت:

<div class="row">
    <div class="col-xs-12">
        <label for="name">نام سرور</label>
        <input type="text" id="name" class="form-control" [(ngModel)]="serverName">

        <label for="description">توضیحات سرور</label>
        <input type="text" id="description" class="form-control" [(ngModel)]="serverContent">
    </div>
</div>
<div class="row">
    <div class="col-xs-12">
        <button class="btn btn-primary" (click)="onCreateLocalServer()">سرور داخلی جدید</button>
        <button class="btn btn-primary" (click)="onCreateExternalServer()">سرور خارجی جدید</button>
    </div>
</div>
<div class="row">
    <hr>
    <div class="col-xs-12">
        <div class="panel panel-default" *ngFor="let server of serverList">
            <div class="panel-heading">{{server.name}}</div>
            <div class="panel-body">{{server.content}}</div>
        </div>
    </div>
</div>

در این فایل از مجموعه‌ی دستورهایی که از فصل ۱ تا کنون مطالعه کرده‌ایم استفاده شده است. روش انتقال داده به صورت two-way databinding (دو طرفه) می‌باشد و در نهایت با استفاده از دستور ngFor* برای هر مقدار موجود در serverList تکرار را انجام داده‌ایم.

از طرفی فایل servers.component.html را به صورت زیر ایجاد کرده‌ایم:

<app-server></app-server>

که در آن سکلتورهای فایل server.component.ts‌ در آن قرار دارد و خود این کامپوننت نیز در کامپوننت ریشه (مادر) app-root مورد استفاده قرار می‌گیرد بنابراین فایل app.component.html‌ به صورت زیر ویرایش می‌شود:

<div class="container" dir="rtl">
    <div class="row">
        <div class="col-xs-12">
            <app-servers></app-servers>
        </div>
    </div>
</div>

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

در واقع در این مثال یاد گرفتید که چگونه از یک کامپوننت درون کامپوننت والد استفاده کنید. یعنی کامپوننت server درون کامپوننت servers و در نهایت کامپوننت servers درون کامپوننت app استفاده شده است.

حال در ادامه به نحوه‌ی ارسال یک ویژگی (Property) و Event از یک کامپوننت فرزند به کامپوننت والد و بالعکس می‌پردازیم.

ارسال داده Property‌ از کامپوننت والد به فرزند

گاهی نیاز داریم که یک سری اطلاعات و داده‌ی پردازش شده را از کامپوننت والد به فرزند ارسال کنیم در این صورت باید آن ویژگی را به تگ سلکتور کامپوننت فرزند پیوست کرده و به صورت Property Binding یا به عبارت ساده تر با استفاده از علامت [ ] به کامپوننت والد منتقل کنیم.

تنها نکته‌ای که باید توجه کنید این است: در انگولار تمام ویژگی‌ها یا متغییرهایی که درون یک کامپوننت تعریف می‌شوند تنها درون همان کامپوننت در دسترس هستند و برای دسترسی به آنها در سایر کامپوننت‌های باید یک مفسر یا دکوراتور به نام Input@ تعریف شود.

بنابراین ساختار کلی این دستور به صورت زیر است:

@Input() initServer = []

در این حالت ویژگی initServer از کلاس کامپوننت‌های دیگر وارد این کامپوننت شده و قابل استفاده است.

توجه داشته باشید که این مفسر از طریق ماژول Input‌ در angular/core قابل استفاده است و باید حتما آن را در ابتدای کدنویسی خود فراخوانی کنید.

بنابراین برای تفهیم این بحث یک مثال کاربردی خدمت شما عزیزان ارائه می‌دهیم. مثال بالا را در نظر بگیرید.

حال فرض کنید یک متغییر را به صورت شیء درون کلاس فرزند serverComponent تعریف می‌کنیم و می‌خواهیم این متغییر را از کامپوننت والد یعنی serversComponent به این کامپوننت ارسال کنیم. در این صورت برای فایل server.component.ts‌ داریم:

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

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

    serverName: string = '';
    serverContent: string = '';
    serverList = [];

    @Input() initServer = {name: "روکسو", content:"این سرور باید از کامپوننت والد دریافت شود"};

    constructor() {
    }


    ngOnInit() {
    }

    onCreateLocalServer() {
        this.serverList.push({
            name: this.serverName,
            content: this.serverContent
        });
    }

    onCreateExternalServer() {
        this.serverList.push({
            name: this.serverName,
            content: this.serverContent
        });
    }
}

تنها یک خط به مجموعه ی کد مثال قبلی اضافه شد و آن تعریف یک متغییر یا ویژگی (Property) به نام initServer بود. حال در قالب HTML کامپوننت والد (servers.component.html) داریم:

<app-server [initServer]="changeServerList"></app-server>

سپس عبارت changeServerList را درون کامپوننت والد servers.component.ts به صورت زیر تعریف می‌کنیم:

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

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

  changeServerList ={name: "roxoChanges", content: "مکان این سرور تغییر کرده است"};
  constructor() { }

  ngOnInit() {
  }

}

در این مثال، ابتدا مقدار initServer‌ برابر یک سری عناوین مشخص بود ولی وقتی آن را در تگ app-server به عنوان یک ویژگی به کامپوننت server.component.ts ارسال کردیم، مقدار changeServerList جایگزین آن شد و در صفحه به نمایش گذاشته می‌شود. به این روش ارسال ویژگی یک کامپوننت والد به کامپوننت‌های فرزند گفته می‌شود.

همچنین گاهی شاید نیاز داشته باشیم تا یک ویژگی را با تغییر اسم و به صورت نام مستعار به کامپوننت فرزند ارسال کنیم در این صورت باید به مفسر و دکوراتور Input یک آرگومان ورودی به عنوان اسم مستعاری که مد نظر ماست، درج کنیم.

به عنوان فررض کنید می‌خواهیم به جای ویژگی initServer ویژگی با نام initSe برای ما بایند شود در اینصورت فایل sever.component.ts‌ به صورت زیر تغییر پیدا می‌کند:

    @Input('initS') initServer = {name: "روکسو", content:"این سرور باید از کامپوننت والد دریافت شود"};

همچنین در فایل servers.component.html‌ تغییرات زیر را لحاظ می‌کنیم:

<app-server [initS]="changeServerList"></app-server>

همانطور که ملاحظه کردید عنوان initS به جای initServer بایند شده است.

ارسال داده Property از نوع رویداد (event) از کامپوننت فرزند به والد

در بخش قبلی ملاحظه کردید که چگونه یک متغییر یا ویژگی را از کامپوننت والد به کامپوننت فرزند انتقال دادیم.

حال فرض کنید می‌خواهیم عکس این کار را انجام داده و اطلاعات را از کامپوننت فرزند به کامپوننت والد ارسال کنیم. در این حالت باید از رویدادها یا event ها بهره‌ ببریم.

یعنی باید یک ویژگی از نوع EventEmitter به صورت جنریک در کامپوننت فرزند تعریف کرده و سپس مقادیری که مد نظر ماست را به کامپوننت والد با رخ دادن یک رویداد ارسال کنیم به عبارت دیگر می‌خواهیم تغییراتی که در کامپوننت فرزند رخ می‌دهند را به کامپوننت والد اطلاع دهیم.

برای تعریف یک event یا رویداد دلخواه باید نام آن را درون () قرار داده و سپس متدی که می‌خواهیم به وقوع بپیوندد را مقابل آن یادداشت کنیم. جهت درک بیشتر این موضوع مثال قبلی را ادامه خواهیم داد.

فرض کنید می‌خواهیم هنگامیکه روی دکمه‌ی «سرور داخلی جدید» کلیک شد یک ویژگی یا متغییر به کامپوننت والد یعنی servers ارسال شود. در این حالت ابتدا باید در کامپوننت والد event ها را تعریف کنیم.

توجه داشته باشید که این event ها پس از کلیک کردن روی دکمه (که در کامپوننت فرزند است) رخ می‌دهند. بنابراین برای تعریف eventها در فایل servers.component.ts خواهیم داشت:

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

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

    changeServerList = {name: "roxoChanges", content: "مکان این سرور تغییر کرده است"};
    serverDataFromChild = [];

    constructor() {
    }

    ngOnInit() {
    }

    onLocalServerAdded(localServerData: {serverName: string, serverContent: string}) {
        this.serverDataFromChild.push({
            name: localServerData.serverName,
            content: localServerData.serverContent
        })
    }

    onExternalServerAdded(externalServerData: {serverName: string, serverContent: string}) {
        this.serverDataFromChild.push({
            name: externalServerData.serverName,
            content: externalServerData.serverContent
        })
    }
}

توجه داشته باشید در این کامپوننت دو متد به نام‌هایی که ملاحظه می‌کنید ایجاد کرده و مقادیری را به عنوان آرگومان به آنها ارسال می‌کنیم.

در واقع این متدها زمانی بکار گرفته می‌شود که eventهای مربوطه رخ دهند. این eventها را در قالب HTML کامپوننت servers به صورت زیر تعریف خواهیم کرد:

<app-server [initS]="changeServerList"
            (localServerCreated)="onLocalServerAdded($event)"
            (externalServerCreated)="onExternalServerAdded($event)"
            >
</app-server>

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

حال در مرحله‌ی بعدی باید دو رویداد یا event مربوطه را (localServerCreated و externalServerCreated) در فایل server.component.ts که به عنوان کامپوننت فرزند هستند و این اطلاعات را به کامپوننت والد انتقال می‌دهند، تعریف کنیم. بنابراین داریم:

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

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

    serverName: string = '';
    serverContent: string = '';
    serverList = [];

    @Input('initS') initServer = {name: "روکسو", content: "این سرور باید به کامپوننت والد ارسال شود"};

    @Output() localServerCreated = new EventEmitter<{ serverName: string, serverContent: string }>();
    @Output() externalServerCreated = new EventEmitter<{ serverName: string, serverContent: string }>()

    constructor() {
    }


    ngOnInit() {
    }

    onCreateLocalServer() {
        this.localServerCreated.emit({
            serverName: this.serverName,
            serverContent: this.serverContent
        });
    }

    onCreateExternalServer() {
        this.externalServerCreated.emit({
            serverName: this.serverName,
            serverContent: this.serverContent
        });
    }
}

در صورتیکه دقت کنید متوجه خواهید شد که برای خارج کردن یک ویژگی یا به عبارت دیگر برای ارسال یک ویژگی از کامپوننت فرزند به والد باید مفسر یا دکوراتوری تحت عنوان Output@ مشابه آنچه در Input@ بود تعریف کنیم.

پس مفسر Output به معنای خارج شدن این ویژگی و ارسال آن به کامپوننت والد و بالاتر است. همچنین چون این اطلاعات پس از رخ دادن یک رویداد ارسال خواهند شد، به عنوان یک شیء از کلاس EventEmitter و به صورت جنریک تعریف شده‌اند تا اطلاعات حاوی نام توضیحات سرور را به کامپوننت بالاتر ارسال کنند.

از طرفی درون متدهایی که به هنگام کلیک روی دکمه‌ها اجرا می‌شوند دستور emit را اعمال می‌کنیم. با استفاده از این دستور، اطلاعاتی که توسط فرم ارسال می‌شوند درون ویژگی‌های localServerCreated و externalServerCreated ذخیره و در نهایت به عنوان رویداد یا event به کامپوننت والد (servers) ارسال می‌شوند. در نتیجه اطلاعات به صورت کاملا منظم از کامپوننت فرزند به کامپوننت والد انتقال داده شدند.

همچنین مشابه آنچه در مفسر Input@ ملاحظه کردید در مفسر Output@ نیز می‌توان یک نام مستعار را به عنوان آرگومان ارسال کرد تا در طول برنامه از آن استفاده کنیم.

بنابراین در فایل server.component.ts داریم:

    @Output('exServerCreated') externalServerCreated = new EventEmitter<{ serverName: string, serverContent: string }>()

در نهایت درون فایل servers.component.html خواهیم داشت:

<app-server [initS]="changeServerList"
            (localServerCreated)="onLocalServerAdded($event)"
            (exServerCreated)="onExternalServerAdded($event)"
            >
</app-server>
<div class="row">
    <hr>
    <div class="col-xs-12">
        <div class="panel panel-default" *ngFor="let serverData of serverDataFromChild">
            <div class="panel-heading">{{serverData.name}}</div>
            <div class="panel-body">{{serverData.content}}</div>
        </div>
    </div>
</div>

در این مثال از یک نام مستعار برای معرفی ویژگی از نوع رویداد جهت ارسال داده از کامپوننت server به کامپوننت servers استفاده کرده‌ایم.

بسیار عالی! تا به اینجای کار با مفاهیم تخصصی مربوط به ارسال داده از سمت کامپوننت والد به فرزند و بالعکس (ارسال داده از سمت کامپوننت فرزند به والد) را فرا گرفتید. این آموزش یکی از مهم‌ترین مباحث می‌باشد که به شما عزیزان در صفحه‌بندی صفحات و سایر مباحث پیشرفته کمک شایانی می‌کند. در صورتیکه سوالی داشتید داخل نظرات وب سایت مطرح بفرمایید. با ما همراه باشید.

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

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

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

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

سید قاسم
14 اردیبهشت 1398
سلام و خسته نباشید من برنامه رو نوشتم اما مقدار پراپرتی که توی والد دارم توی خروجی نشون داده نمیشه اصلا معلوم نیست ک پر میشه یا نه چجوری باید دیباگش کنم و مقادیر رو چک کنم؟؟؟ ممنون میشم اگر از دوستان کسی راهنماییم کنه

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

سید قاسم
14 اردیبهشت 1398
دوستان serverDataFromChild در فایل servers.component.ts باید از نوع آرایه باشه تا مقداری ک از نوع آرایه از کامپوننت فرزند ارسال میشه رو بتونه دریافت کنه به این شکل: serverDataFromChild = [{}]; همچنین اگر از اسم مستعار استفاده میکنین باید توی servers.component.html هم از همون نام مستعار استفاده بشه

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

omid
18 خرداد 1397
سلام برام یه سوال بزرگ به وجود امده و تو سایت های ایرانی میگردم جواب شو پیدا نکردم درست و حسابی باشه فرق بین models و interface چیه؟!

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

روکسو
19 خرداد 1397
سلام در مدل ها شما یک کلاس تعریف می کنید در حالیکه درون اینترفیس ها می توانید تنها ویژگی ها را ایجاد نمایید.

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

سبحان
19 بهمن 1396
سلام من میخوام از کامپننت پدر یک نوع داده برای کامپوننت فرزند بفرستم تک کامپوننت فرزند رو باید حتما تو پدر بیارم؟؟؟من نمیخوام کامپوننت فرزند رو تو پدر نمایش بدم!!

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

سبحان
06 بهمن 1396
سلام من چن مدته اموزشاتونو میخونم واقعن جامع و کامل هستش چهار چوب رو کامل گفتید

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

مجتبی
18 آذر 1396
سلام . من خروجی شمارو نگرفتم . ارور دارم

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

زهرا
24 مهر 1396
این مطلب شما دارای ایراد است : @input: ارسال از والد به فرزند @output:ارسال از فرزند به والد شما @input را در دو جا این مطلب متناقض تعریف کردید با تشکر

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

روکسو
24 مهر 1396
با سلام و احترام این مقاله مجددا بازنویسی شد. با تشکر از پیام های کاربران گرامی.

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

پریا
23 مهر 1396
سلام و باتشکر از مقالات شما فصل های گذشته بسیار خوب توضیح داده شده اند اما در این قسمت ابتدا به جای اینکه بگید ارسال متغیر از والد به فرزند ، گفتید از فرزند به والد که باید چند جایی این رو تصحیح کنید. همچنین مبحث ارسال متغیر از فرزند به والد رو من اصلا متوجه نشدم و خروجی هم نداد بهم اگر براتون مقدوره این مبحث رو بیشتر باز کنید . با تشکر فراوان از زحمات شما

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

علی
24 شهریور 1396
سلام منم نتونستم خروجی شما بگیرم

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

داوود طاهرخانی
21 شهریور 1396
سلام خوبید ممنون به خاطر این اموزش خوب بود اما پیچیده توضیح دادید و برای هر بخش اجرای ان بخش را ارایه نکردید به خاطر همین من این قسمت رو خوب درک نکردم با یان که عینا به روش ذکر شده عمل کردم اما جواب نگرفتم.

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

فریاد
08 شهریور 1396
سلام ممنون بابت اموزش خوبتون. در این صفحه یعنی اموزش فصل 4 بخش 1 (در اولین اموزش و اولین خروجی)من کدهای شمارو دقیق زدم ولی خروجی نداشت و پر از ارور بود و برای اطمینان کدهای شمارو کامل کپی پیست کردم ولی همچنان فرقی نکرد . نمیدونم علتو . اگر ممکنه راهنمایی کنین

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

محمدرضا
14 مرداد 1396
سلام خیلی ممنون از زحمتاتون این مقاله خیلی مفید و خوب که زحمتشو کشیدین بعضی جاهاش نیاز به ویرایش داره یه بازنگری ریزی توش بکنین به نظرم موفق باشید

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

kasra
13 مرداد 1396
salam va khaste nabashid. khaheshan in maghale ro baznevisi konid benazare man ham bazi jahash moshkel dare. mamnoon

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

A
02 مرداد 1396
با سلام و سپاس از زحمات شما لطفا این مقاله را دوباره باز نویسی فرمایید به نظر بعضی جاها ابهام دارد پاینده باشید

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