شروع به کار با AngularJS 2.0 و TypeScript - قسمت هشتم - دریافت اطلاعات از سرور
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: ده دقیقه

اغلب برنامه‌های AngularJS 2.0، اطلاعات خود را از طریق پروتکل HTTP، از سرور دریافت می‌کنند. برنامه یک درخواست Get را صادر کرده و سپس سرور پاسخ مناسبی را ارائه می‌دهد.


مقدمه‌ای بر RxJS

اگر به پیشنیازهای نصب AngularJS 2.0 در قسمت اول این سری دقت کرده باشید، یکی از موارد آن، RxJS است:
"dependencies": {
    "rxjs": "5.0.0-beta.2"
 },
یک Observable، آرایه‌ای است که اعضای آن به صورت غیر همزمان (asynchronously) در طول زمان دریافت می‌شوند. برای مثال پس از شروع یک عملیات async، ابتدا عنصر اول آرایه دریافت می‌شود، پس از مدتی عنصر دوم و در آخر عنصر سوم آن. به همین جهت از Observable‌ها برای مدیریت داده‌های async مانند دریافت اطلاعات از یک وب سرور، استفاده می‌شود.
قرار است Observableها به ES 2016 یا نگارش پس از ES 6 اضافه شوند و یکی از پیشنهادات آن هستند. اما هم اکنون AngularJS 2.0 از این امکان، توسط یک کتابخانه‌ی ثالث، به نام reactive extensions یا Rx، استفاده می‌کند. از RxJS در سرویس HTTP و همچنین مدیریت سیستم رخدادهای AngularJS 2.0 استفاده می‌شود. Observableها امکانی را فراهم می‌کنند تا به ازای دریافت هر اطلاعات async از سرور، بتوان توسط رخداد‌هایی از وقوع آن‌ها مطلع شد.

در نگارش قبلی AngularJS از Promises برای مدیریت اعمال غیرهمزمان استفاده می‌شد. Observableها تفاوت‌های قابل ملاحظه‌ای با Promises دارند:
- یک Promise تنها یک مقدار، یا خطا را بر می‌گرداند؛ اما یک Observable چندین مقدار را در طول یک بازه‌ی زمانی باز می‌گرداند.
- برخلاف Promises، می‌توان عملیات یک Observable را لغو کرد.
- Observableها از عملگرهایی مانند map، reduce، filter و غیره نیز پشتیبانی می‌کنند.

البته باید عنوان کرد که هنوز هم می‌توان از Promises در صورت تمایل در AngularJS 2.0 نیز استفاده کرد.


تنظیمات اولیه‌ی کار با RxJS در AngularJS 2.0

برای استفاده از RxJS در AngularJS 2.0، مراحلی مانند افزودن مدخل اسکریپت http.dev.js، ثبت پروایدر HTTP و importهای لازم، باید طی شوند که در ادامه آن‌ها را بررسی خواهیم کرد:
الف) سرویس HTTP جزئی از angular2/core نیست. به همین جهت مدخل اسکریپت متناظر با آن، باید به صفحه‌ی اصلی سایت اضافه شود که این مورد، در قسمت اول بررسی پیشنیازهای نصب AngularJS 2.0 صورت گرفته‌است:
 <!-- Required for http -->
<script src="~/node_modules/angular2/bundles/http.dev.js"></script>
این تعریف در فایل Views\Shared\_Layout.cshtml (و یا index.html) پروژه‌ی جاری موجود است. همچنین در این صفحه، مدخل Rx.js نیز ذکر شده‌است.

ب) اکنون فایل app.component.ts را گشوده و سرویس HTTP را به آن اضافه می‌کنیم. با نحوه‌ی ثبت سرویس‌ها در قسمت قبل آشنا شدیم:
import { Component } from 'angular2/core';
import { HTTP_PROVIDERS } from 'angular2/http';
import 'rxjs/Rx';   // Load all features
 
import { ProductListComponent } from './products/product-list.component';
import { ProductService } from './products/product.service';
 
@Component({
    selector: 'pm-app',
    template:`
    <div><h1>{{pageTitle}}</h1>
        <pm-products></pm-products>
    </div>
    `,
    directives: [ProductListComponent],
    providers: [
        ProductService,
        HTTP_PROVIDERS
    ]
})
export class AppComponent {
    pageTitle: string = "DNT AngularJS 2.0 APP";
}
از آنجائیکه می‌خواهیم سرویس HTTP، در تمام کامپوننت‌های برنامه در دسترس باشد، آن‌را در بالاترین سطح سلسه مراتب کامپوننت‌های موجود، یا همان کامپوننت ریشه‌ی سایت، ثبت و معرفی می‌کنیم. بنابراین سرویس توکار HTTP یا HTTP_PROVIDERS به لیست پروایدرها، اضافه شده‌است.

ج) پس از آن نیاز است importهای متناظر نیز به ابتدای ماژول فعلی، جهت شناسایی این سرویس و همچنین امکانات rx.js اضافه شوند.
تعریف 'import 'rxjs/Rx به این شکل، به module loader اعلام می‌کند که این کتابخانه را بارگذاری کن، اما چیزی را import نکن. هنگامیکه این کتابخانه بارگذاری می‌شود، کدهای جاوا اسکریپتی آن اجرا شده و سبب می‌شوند که عملگرهای ویژه‌ی Observable آن مانند map و filter نیز در دسترس برنامه قرار گیرند.


ساخت یک سرویس سمت سرور بازگشت لیست محصولات به صورت JSON

چون در ادامه می‌خواهیم لیست محصولات را از سرور دریافت کنیم، برنامه‌ی ASP.NET MVC فعلی را اندکی تغییر می‌دهیم تا این لیست را به صورت JSON بازگشت دهد.
بنابراین ابتدا کلاس مدل محصولات را به نحو ذیل به پوشه‌ی Models اضافه کرده:
namespace MVC5Angular2.Models
{
    public class Product
    {
        public int ProductId { set; get; }
        public string ProductName { set; get; }
        public string ProductCode { set; get; }
        public string ReleaseDate { set; get; }
        public decimal Price { set; get; }
        public string Description { set; get; }
        public double StarRating { set; get; }
        public string ImageUrl { set; get; }
    }
}
و سپس اکشن متد Products، لیست محصولات فرضی این سرویس را بازگشت می‌دهد:
using System.Collections.Generic;
using System.Text;
using System.Web.Mvc;
using MVC5Angular2.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
 
namespace MVC5Angular2.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {
            return View();
        }
 
        public ActionResult Products()
        {
            var products = new List<Product>
            {
               new Product
               {
                    ProductId= 2,
                    ProductName= "Garden Cart",
                    ProductCode= "GDN-0023",
                    ReleaseDate= "March 18, 2016",
                    Description= "15 gallon capacity rolling garden cart",
                    Price= (decimal) 32.99,
                    StarRating= 4.2,
                    ImageUrl= "app/assets/images/garden_cart.png"
               },
               new Product
               {
                    ProductId= 5,
                    ProductName= "Hammer",
                    ProductCode= "TBX-0048",
                    ReleaseDate= "May 21, 2016",
                    Description= "Curved claw steel hammer",
                    Price= (decimal) 8.9,
                    StarRating= 4.8,
                    ImageUrl= "app/assets/images/rejon_Hammer.png"
               }
            };
 
            return new ContentResult
            {
                Content = JsonConvert.SerializeObject(products, new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                }),
                ContentType = "application/json",
                ContentEncoding = Encoding.UTF8
            };
        }
    }
}
در اینجا از JSON.NET جهت بازگشت camel case نام خواص مورد نیاز در سمت کاربر، استفاده شده‌است.
برای مطالعه‌ی بیشتر:
«استفاده از JSON.NET در ASP.NET MVC»
«تنظیمات و نکات کاربردی کتابخانه‌ی JSON.NET»

به این ترتیب، آدرس http://localhost:2222/home/products، خروجی JSON سرویس لیست محصولات را در مثال جاری، ارائه می‌دهد.


ارسال یک درخواست HTTP به سرور توسط AngularJS 2.0

اکنون پس از تنظیمات ثبت و معرفی سرویس HTTP و همچنین برپایی یک سرویس سمت سرور ارائه‌ی لیست محصولات، می‌خواهیم سرویس ProductService را که در قسمت قبل ایجاد کردیم (فایل product.service.ts)، جهت دریافت لیست محصولات از سمت سرور، تغییر دهیم:
import { Injectable } from 'angular2/core';
import { IProduct } from './product';
import { Http, Response } from 'angular2/http';
import { Observable } from 'rxjs/Observable';
 
@Injectable()
export class ProductService {
    private _productUrl = '/home/products';
 
    constructor(private _http: Http) { }
 
    getProducts(): Observable<IProduct[]> {
        return this._http.get(this._productUrl)
                         .map((response: Response) => <IProduct[]>response.json())
                         .do(data => console.log("All: " + JSON.stringify(data)))
                         .catch(this.handleError);
    }
 
    private handleError(error: Response) {
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }
}
از آنجائیکه این سرویس دارای یک وابستگی تزریق شده‌است، ذکر ()Injectable@، پیش از تعریف نام کلاس، ضروری است.
در سازنده‌ی کلاس ProductService، کار تزریق وابستگی سرویس Http انجام شده‌است. به این ترتیب با استفاده از متغیر خصوصی http_، می‌توان در کلاس جاری به امکانات این سرویس دسترسی یافت (همان «تزریق سرویس‌ها به کامپوننت‌ها» در قسمت قبل).
سپس متد get آن، یک درخواست HTTP از نوع GET را به آدرس مشخص شده‌ی در متغیر productUrl_ ارسال می‌کند (یا همان سرویس سمت سرور برنامه).
سرویس Http و همچنین شیء Response آن در ماژول‌های Http و Response قرار دارند که در ابتدای صفحه import شده‌اند.

متد http get یک Observable را بازگشت می‌دهد که در نهایت خروجی این متد نیز به همان <[]Observable<IProduct، تنظیم شده‌است. Observable یک شیء جنریک است و در اینجا نوع آن، آرایه‌ای از محصولات درنظر گرفته شده‌است.
اکنون که امضای این متد تغییر یافته است (پیش از این صرفا یک آرایه‌ی ساده از محصولات بود)، استفاده کننده (در کلاس ProductListComponent) باید به تغییرات آن از طریق متد subscribe گوش فرا دهد.
فعلا در کلاس جاری، پس از پایان کار دریافت اطلاعات از سرور، اطلاعات نهایی در متد map در دسترس قرار می‌گیرد (که یکی از عملگرهای RxJs است). کار متد map، اصطلاحا projection است. این متد، هر عضو دریافتی از خروجی سرور را به فرمتی جدید نگاشت می‌کند.
هر درخواست HTTP، در اصل یک عملیات async است. یعنی در اینجا توالی که در اختیار Observable ما قرار می‌گیرد، تنها یک المان دارد که همان شیء HTTP Response است.
بنابراین کار متد map فوق، تبدیل شیء خروجی از سرور، به آرایه‌ای از محصولات است.
در اینجا یک سری کدهای مدیریت استثناءها را نیز در صورت بروز مشکلی می‌توان تعریف کرد. برای مثال در اینجا متد catch، کار پردازش خطاهای رخ داده را انجام می‌دهد.
از متد do جهت لاگ کردن عملیات رخ داده و داده‌های دریافتی در کنسول developer tools مرورگرها استفاده شده‌است.

یک نکته:
اگر خروجی JSON از سرور، برای مثال داخل خاصیتی به نام data محصور شده بود، بجای ()response.json می‌بایستی از response.json().data استفاده می‌شد.


گوش فرا دادن به Observable دریافتی از سرور

تا اینجا یک درخواست HTTP GET را به سمت سرور ارسال کردیم و خروجی آن به صورت Observable در اختیار ما است. اکنون نیاز است کدهای ProductListComponent را جهت گوش فرا دادن به این Observable تغییر دهیم. برای این منظور فایل product-list.component.ts را گشوده و تغییرات ذیل را به آن اعمال کنید:
errorMessage: string;
ngOnInit(): void {
    //console.log('In OnInit');
    this._productService.getProducts()
                        .subscribe(
                              products => this.products = products,
                              error => this.errorMessage = <any>error);
}
در کلاس ProductListComponent، در متد ngOnInit که در آن کار آغاز و مقدار دهی وابستگی‌های کامپوننت انجام می‌شود، متد ()productService.getProducts_ فراخوانی شده‌است. این متد یک Observable را بر می‌گرداند. بنابراین برای پردازش نتیجه‌ی آن نیاز است متد subscribe را در ادامه‌ی آن، زنجیر وار ذکر کرد.
اولین پارامتر متد subscribe، کار دریافت نتایج حاصل را به عهده دارد. برای مثال اگر حاصل عملیات در طی سه مرحله صورت گیرد، سه بار نتیجه‌ی دریافتی را می‌توان در اینجا پردازش کرد. البته همانطور که عنوان شد، یک عملیات غیرهمزمان HTTP، تنها در طی یک مرحله، HTTP Response را دریافت می‌کند؛ بنابراین، پارامتر اول متد subscribe نیز تنها یکبار اجرا می‌شود. در اینجا فرصت خواهیم داشت تا آرایه‌ی دریافتی حاصل از متد map قسمت قبل را به خاصیت عمومی products کلاس جاری نسبت دهیم.
پارامتر دوم متد subscribe در صورت شکست عملیات فراخوانی می‌شود. در اینجا حاصل آن به خاصیت جدید errorMessage نسبت داده شده‌است.


اکنون برنامه را مجددا اجرا کنید، هنوز باید لیست محصولات، مانند قبل نمایش داده شود.


یک نکته
اگر برنامه را اجرا کردید و خروجی مشاهده نشد، به کنسول developer tools مرورگر مراجعه کنید؛ احتمالا خطای ذیل در آن درج شده‌است:
 EXCEPTION: No provider for Http!
به این معنا که پروایدر HTTP یا همان HTTP_PROVIDERS، جایی معرفی نشده‌است. البته مشکلی از این لحاظ در برنامه وجود ندارد و این پروایدر در بالاترین سطح ممکن و در فایل app.component.ts ثبت شده‌است. مشکل اینجا است که مرورگر، فایل قدیمی http://localhost:2222/app/app.component.js را کش کرده‌است (به همراه تمام اسکریپت‌های دیگر) و این فایل قدیمی، فاقد تعریف سرویس HTTP است. بنابراین با حذف کش مرورگر و دریافت فایل‌های js جدید، مشکل برطرف خواهد شد.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: MVC5Angular2.part8.zip


خلاصه‌ی بحث

برای کار با سرور و ارسال درخواست‌های HTTP، ابتدا نیاز است مدخل تعریف http.dev.js به index.html اضافه شود و سپس HTTP_PROVIDERS را در بالاترین سطح کامپوننت‌های تعریف شده، ثبت و معرفی کرد. پس از آن نیاز است RxJs را نیز import کرد. در ادامه، سرویس دریافت لیست محصولات، وابستگی سرویس HTTP را توسط سازنده‌ی خود دریافت کرده و از آن برای صدور یک فرمان HTTP GET استفاده می‌کند. سپس با استفاده از متد map، کار نگاشت شیء Response دریافتی، به فرمت مناسب مدنظر، صورت می‌گیرد.
در ادامه هر کلاسی که نیاز دارد با این کلاس سرویس دریافت اطلاعات کار کند، متد subscribe را فراخوانی کرده و نتیجه‌ی عملیات را پردازش می‌کند.
  • #
    ‫۸ سال و ۵ ماه قبل، سه‌شنبه ۱۴ اردیبهشت ۱۳۹۵، ساعت ۱۹:۰۹
    به روز رسانی: ارتقاء به نگارش «2.0.0rc.0 » 
    جزئیات این مورد و تغییرات مداخل ابتدایی، به همراه فایل main.ts جدید را در نظرات قسمت اول مطالعه بفرمائید. 
  • #
    ‫۸ سال و ۴ ماه قبل، پنجشنبه ۱۶ اردیبهشت ۱۳۹۵، ساعت ۰۵:۴۹
    چند نکته‌ی تکمیلی
    - اگر با به روز رسانی وابستگی‌ها، خطای «Invalid module name in augmentation, module '../../Observable' cannot be found» را دریافت کردید، چند نگارش پایین‌تر rxjs را نیز امتحان کنید.
    به علاوه مطمئن شوید که تعاریف typings مناسب را در فایل main.ts ذکر کرده‌اید:
    /// <reference path="../typings/es6-shim.d.ts" />
    
    import { bootstrap } from '@angular/platform-browser-dynamic';
    - با تغییرات نگارش RC، دیگر نیازی به ذکر http.dev.js در فایل index.html نیست. این مدخل به صورت خودکار توسط systemjs.config.js اضافه می‌شود:
     <script src="~/systemjs.config.js"></script>
    • #
      ‫۸ سال و ۴ ماه قبل، چهارشنبه ۲۲ اردیبهشت ۱۳۹۵، ساعت ۱۷:۳۸
      راه حلی برای رفع مشکل «module '../../Observable' cannot be found» در ویژوال استودیو (نیاز به نصب نگارش جدید TypeScript را دارد).
  • #
    ‫۸ سال و ۳ ماه قبل، پنجشنبه ۱۰ تیر ۱۳۹۵، ساعت ۱۵:۳۹
    به روز رسانی
    اگر به روز رسانی سوم VS 2015 را نصب کرده‌اید، برای کار با rxjs نیاز به تعویض فایل typescriptServices.js را خواهید داشت. اطلاعات بیشتر
  • #
    ‫۸ سال و ۲ ماه قبل، چهارشنبه ۲۳ تیر ۱۳۹۵، ساعت ۱۷:۳۸
    من به جای Controller از apiController استفاده کردم اما وقتی خطای زیر را میده:
    JSON.parse: unexpected character at line 1 column 1 of the JSON data

    • #
      ‫۸ سال و ۲ ماه قبل، چهارشنبه ۲۳ تیر ۱۳۹۵، ساعت ۱۷:۵۹
      - سمت سرور آن مهم نیست (اگر آدرس آن‌را که مستقیما باز می‌کنید، خروجی JSON را مشاهده می‌کنید).
      - هر زمانیکه خطای syntax error را دریافت کردید یعنی تنظیمات ابتدایی AngularJS 2.0 شما اشتباه و یا ناقص است.
      - این مطالب به روز شده‌اند. نیاز هست توضیحات ذیل هر مطلب را جهت به روز رسانی هر قسمت دنبال کنید.
      - و یا ... تمام این توضیحات به صورت یکجا به پروژه‌ی « MVC5Angular2 » اعمال شده‌اند. نیاز است فایل به فایل و سطر به سطر کدهای خود را با این پروژه تطبیق دهید.
      • #
        ‫۸ سال و ۲ ماه قبل، چهارشنبه ۲۳ تیر ۱۳۹۵، ساعت ۱۸:۲۵
        ممنون از جوابتون.بله من با تغییرات جدید مثال خودم را نوشتم.
        من در فایل  Global.asax کد زیر را نوشتم و مشکلم حل شد:
         GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
         
        • #
          ‫۸ سال و ۲ ماه قبل، چهارشنبه ۲۳ تیر ۱۳۹۵، ساعت ۱۸:۴۲
          نیازی به اینکار نیست (اگر Content-Type درخواست هم تنظیم شود). علت آن‌را در مطلب «شروع به کار با AngularJS 2.0 و TypeScript - قسمت دهم - کار با فرم‌ها - قسمت اول» توضیح دادم:
          «... نکته‌ی مهم اینجا است که content type پیش فرض ارسالی متد post آن، plain text است و در این حالت ASP.NET MVC شیء JSON دریافتی از کلاینت را پردازش نخواهد کرد. بنابراین نیاز است تا هدر content type را به صورت صریحی در اینجا ذکر نمود؛ در غیراینصورت در سمت سرور، شاهد نال بودن مقادیر دریافتی از کاربران خواهیم بود...» 
  • #
    ‫۸ سال و ۲ ماه قبل، دوشنبه ۲۸ تیر ۱۳۹۵، ساعت ۱۶:۳۶
    من تغییرات RC 4 را اعمال کردم .الان مشکلی که دارم در متد ngOnInit متدی که از سرویس اطلاعات را دریافت می‌کند صدا زده شده(loadMenu)و در این متد متغیر menus مقداردهی شده اما برای خواندن از آن متغیر مقدار آن undefined  می‌باشد.البته متغیر در اجرای اول undefined است ولی با زدن دکمه F5 متغیر مقدار می‌گیرد. کش مرورگر هم پاک کردم اما مشکل حل نشد.کسی با این مشکل برخورد کرده؟
    export class MenuComponent implements OnInit, AfterViewInit {
        menus: IMenu[];
      constructor(private _menuService: MenuService) {
      }
     ngOnInit(): void {
            this.loadMenu();
            alert(this.menus);// menus is undefined 
        }
    • #
      ‫۸ سال و ۲ ماه قبل، دوشنبه ۲۸ تیر ۱۳۹۵، ساعت ۱۶:۵۳
      کدهای loadMenu را ذکر نکردید ولی به احتمال زیاد حاوی قسمت subscribe که در متن توضیح داده شد، نیست. در اینجا هست که پس از پایان کار موفقیت آمیز سرویس، اطلاعات را دریافت می‌کنید و نه اینکه بلافاصله پس از فرخوانی سرویسی می‌شود از آن استفاده کرد (سطر بعدی، بدون توقف اجرا می‌شود و این فراخوانی‌ها async هستند؛ به همین جهت هست که پیام تعریف نشده بودن مقدار آن‌را دریافت می‌کنید).
      • #
        ‫۸ سال و ۲ ماه قبل، دوشنبه ۲۸ تیر ۱۳۹۵، ساعت ۱۷:۱۳
        ممنون از جوابتون اما من در loadMenu قسمت subscribe را دارم .
        loadMenu(): void {
                  this._menuService.getMenu(this.subSystemId).subscribe(
                      menus  => { this.menus = menus  ; },
                    error => this.errorMessage = <any>error);
              
            }
        • #
          ‫۸ سال و ۲ ماه قبل، دوشنبه ۲۸ تیر ۱۳۹۵، ساعت ۱۷:۱۹
          - روش کار به این صورت است. ابتدا یک درخواست HTTP به سرور ارسال می‌شود. سپس تمام سطرهای بعدی، یک به یک اجرا می‌شوند. در آخر زمانیکه کار درخواست HTTP پایان یافت و از طرف سرور پاسخی ارائه شد، آنگاه متد subscribe فراخوانی می‌شود.
          - یعنی کدهای بعدی، بلافاصله اجرا می‌شوند.
          - نتیجه درخواست HTTP در متد subscribe در آینده‌ای نزدیک بازگشت داده می‌شود و هیچ ترتیب خاصی را نمی‌توان برای آن قائل شد.
          - بنابراین فراخوانی loadMenu و بلافاصله دسترسی به نتیجه‌ی آن، حاصلی ندارد؛ چون هنوز subscribe آن نتیجه‌ای را از طرف سرور دریافت نکرده و سطر بعدی، بلافاصله اجرا شده‌است.
          - سطر loadMenu، یک سطر blocking نیست و async است.
  • #
    ‫۷ سال و ۹ ماه قبل، یکشنبه ۱۴ آذر ۱۳۹۵، ساعت ۰۲:۲۲
    این مسئله کش رو در یک محیط عملیاتی چطور میشه رفع کرد.
    برای مثال یک سیستمی دارم که آن را تغییر میدهم ولی کاربران به دلیل مشکل کش به مشکل برخورد خواهند کرد.
  • #
    ‫۷ سال و ۵ ماه قبل، یکشنبه ۱۳ فروردین ۱۳۹۶، ساعت ۰۵:۰۰
    در صورتی که در map کردن اسم خصوصیت‌ها با اسامی که توسط json دریافت نکنیم یکی نباشه، عملیات نگاشت رو چطوری میشه انجام داد؟ آیا باید در قسمت subscribe خودمون عملیات Deserialize کردن رو دستی انجام بدیم؟

    آیا عدم subscribe کردن داخل از سرویس به دلیل این هست که observer مربوطه async هست و اگر داخل بنویسیم این قابلیت ادامه پیدا کردن کد رو از دست میدیم درسته؟میخواستم ببینم منظورتون رو درست متوجه شدم یا خیر
    • #
      ‫۷ سال و ۵ ماه قبل، یکشنبه ۱۳ فروردین ۱۳۹۶، ساعت ۰۵:۳۱
      - خواص را از شیء json دریافت و دستی نگاشت کنید:
      export class Book {
          constructor(
              public id,
              public title:string,
              public pages:Array
          ){}
      }
      
      return this._http.get('getBook/1')
          .map(function(res){
              var data = res.json();
              return new Book(data.id, data.title, data.pages);
          })
      - این مورد بیشتر بحث طراحی سرویس‌ها و جداسازی وظایف هست (و یک best practice). می‌توانید کلا کلاس سرویس را حذف کنید و تمام عملیات مرتبط را داخل همان کامپوننت هم مدیریت کنید. اما در +Angular2، مرسوم است کار طراحی لایه کار با HTTP، در یک کلاس سرویس مجزا انجام شود و استفاده کننده‌ها در کامپوننت‌ها، مشترک آن شوند.
  • #
    ‫۶ سال و ۱۱ ماه قبل، پنجشنبه ۲۷ مهر ۱۳۹۶، ساعت ۲۲:۳۹
    من یه لیست از مدل را در MVC6 به انگیولار بازگشت میدهم و در دریافت مشکلی ندارم ولی موردی که هست این هست که قاعده نام فیلدها را تغییر میدهد مثلا به جای FirstName مقدار جیسون شامل فیلد firstName است که در قاعده جیسون تعریف شده است و بنابراین باعث میشود که در مدل بازگشتی تایپ اسکریپت که من همه فیلدها را دقیقا مشابه Net Core. تعریف کردم قرار نگیرد و در استفاده باید بنویسم firstName نه FirstName.
    چگونه میشود این قاعده را از بین برد و دقیقا همانند مدل‌ها این نامگذاری انجام شود؟
  • #
    ‫۶ سال و ۳ ماه قبل، پنجشنبه ۳ خرداد ۱۳۹۷، ساعت ۲۰:۴۲
    با سلام. در یک پروژه Angular 5 داده‌های ComboBox‌ها باید در سمت کلاینت کش شوند. بنده در ngOnInit مربوط به app.component عملیات دریافت این داده‌ها را با http.get انجام میدهم و داده‌ها در یک پروپرتی Observable کش می‌شوند. حالا در فرم هایی که به این داده‌ها نیاز دارم در متد ngOnInit اقدام به دریافت داده‌ها از کش میکنم اما هنوز داده‌ها دریافت نشده اند (مشکل همزمانی).
    همچنین بنده lifecycle Angular رو بررسی کردم. از ngAfterContentInit هم برای دریافت داده‌ها در فرم‌ها استفاده کردم اما باز هم موقع اجرای این متد(ngAfterContentInit   ) هنور متد subscribe مربوط به http.get اجرا نشده است.
     لطفا در صورت امکان راهنمایی کنید. با تشکر
    • #
      ‫۶ سال و ۳ ماه قبل، جمعه ۴ خرداد ۱۳۹۷، ساعت ۰۰:۱۴
      - محل کش کردن اطلاعات، سرویس‌ها هستند که طول عمر singleton دارند. یک سرویس را طراحی کنید که در سازنده‌ی آن اطلاعات مورد نظر را دریافت کند. سپس این سرویس پس از دریافت اطلاعات، به تمام کامپوننت‌های مشترک به آن با استفاده از BehaviorSubject اطلاع رسانی کند.
      - همچنین اگر اطلاعاتی قرار است درست در لحظه‌ی آغاز برنامه واکشی شود، روش کار آن در مطلب « مدیریت اعمال آغازین در برنامه‌های Angular » بحث شده‌است.