Rxjs ऑब्जर्वर / ऑब्जर्वेबल + कैशिंग + सब्सक्रिप्शन का उपयोग करके कैशेबल HTTP रिस्पॉन्स डेटा
नीचे कोड देखें
* अस्वीकरण: मैं rxjs के लिए नया हूं, इसलिए ध्यान रखें कि मैं अवलोकन / पर्यवेक्षक दृष्टिकोण का दुरुपयोग कर सकता हूं। मेरा समाधान विशुद्ध रूप से अन्य समाधानों का एक समूह है जो मैंने पाया, और एक सरल अच्छी तरह से दस्तावेजी समाधान खोजने में विफल होने का परिणाम है। इस प्रकार मैं अपना पूरा कोड समाधान प्रदान कर रहा हूं (जैसा कि मैंने पाया होगा) उम्मीद में कि यह दूसरों की मदद करता है।
* ध्यान दें, यह दृष्टिकोण GoogleFirebaseObservables पर आधारित है। दुर्भाग्य से मेरे पास हुड के नीचे जो कुछ भी था उसे दोहराने के लिए उचित अनुभव / समय का अभाव है। लेकिन कुछ कैश-सक्षम डेटा तक एसिंक्रोनस पहुंच प्रदान करने का एक सरल तरीका निम्नलिखित है।
स्थिति : एक 'उत्पाद-सूची' घटक को उत्पादों की सूची प्रदर्शित करने का काम सौंपा गया है। साइट कुछ मेनू बटन के साथ एक एकल-पृष्ठ वेब ऐप है जो पृष्ठ पर प्रदर्शित उत्पादों को 'फ़िल्टर' करेगी।
समाधान : घटक एक सेवा पद्धति के लिए "सबस्क्राइब" करता है। सेवा पद्धति उत्पाद वस्तुओं की एक सरणी देती है, जो घटक सदस्यता कॉलबैक के माध्यम से पहुंचता है। सेवा पद्धति अपनी गतिविधि को एक नए बनाए गए ऑब्ज़र्वर में लपेटती है और पर्यवेक्षक को लौटा देती है। इस प्रेक्षक के अंदर, यह कैश्ड डेटा खोजता है और इसे सब्सक्राइबर (कंपोनेंट) को वापस भेजता है और रिटर्न देता है। अन्यथा यह डेटा को पुनः प्राप्त करने के लिए http कॉल जारी करता है, प्रतिक्रिया के लिए सबस्क्राइब करता है, जहाँ आप उस डेटा (जैसे डेटा को अपने मॉडल में मैप कर सकते हैं) को प्रोसेस कर सकते हैं और फिर ग्राहक को डेटा वापस दे सकते हैं।
कोड
उत्पाद-list.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { ProductService } from '../../../services/product.service';
import { Product, ProductResponse } from '../../../models/Product';
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.scss']
})
export class ProductListComponent implements OnInit {
products: Product[];
constructor(
private productService: ProductService
) { }
ngOnInit() {
console.log('product-list init...');
this.productService.getProducts().subscribe(products => {
console.log('product-list received updated products');
this.products = products;
});
}
}
product.service.ts
import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable, Observer } from 'rxjs';
import 'rxjs/add/operator/map';
import { Product, ProductResponse } from '../models/Product';
@Injectable()
export class ProductService {
products: Product[];
constructor(
private http:Http
) {
console.log('product service init. calling http to get products...');
}
getProducts():Observable<Product[]>{
//wrap getProducts around an Observable to make it async.
let productsObservable$ = Observable.create((observer: Observer<Product[]>) => {
//return products if it was previously fetched
if(this.products){
console.log('## returning existing products');
observer.next(this.products);
return observer.complete();
}
//Fetch products from REST API
console.log('** products do not yet exist; fetching from rest api...');
let headers = new Headers();
this.http.get('http://localhost:3000/products/', {headers: headers})
.map(res => res.json()).subscribe((response:ProductResponse) => {
console.log('productResponse: ', response);
let productlist = Product.fromJsonList(response.products); //convert service observable to product[]
this.products = productlist;
observer.next(productlist);
});
});
return productsObservable$;
}
}
product.ts (मॉडल)
export interface ProductResponse {
success: boolean;
msg: string;
products: Product[];
}
export class Product {
product_id: number;
sku: string;
product_title: string;
..etc...
constructor(product_id: number,
sku: string,
product_title: string,
...etc...
){
//typescript will not autoassign the formal parameters to related properties for exported classes.
this.product_id = product_id;
this.sku = sku;
this.product_title = product_title;
...etc...
}
//Class method to convert products within http response to pure array of Product objects.
//Caller: product.service:getProducts()
static fromJsonList(products:any): Product[] {
let mappedArray = products.map(Product.fromJson);
return mappedArray;
}
//add more parameters depending on your database entries and constructor
static fromJson({
product_id,
sku,
product_title,
...etc...
}): Product {
return new Product(
product_id,
sku,
product_title,
...etc...
);
}
}
जब मैं Chrome में पेज लोड करता हूं, तो मैं जो आउटपुट देखता हूं, उसका एक नमूना यहां दिया गया है। ध्यान दें कि प्रारंभिक भार पर, उत्पादों को http (मेरे नोड बाकी सेवा पर कॉल करें), जो स्थानीय स्तर पर पोर्ट 3000 पर चल रहा है) से लिया जाता है। जब मैं उत्पादों के 'फ़िल्टर किए गए' दृश्य पर नेविगेट करने के लिए क्लिक करता हूं, तो उत्पाद कैश में पाए जाते हैं।
मेरा Chrome लॉग (कंसोल):
core.es5.js:2925 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
app.component.ts:19 app.component url: /products
product.service.ts:15 product service init. calling http to get products...
product-list.component.ts:18 product-list init...
product.service.ts:29 ** products do not yet exist; fetching from rest api...
product.service.ts:33 productResponse: {success: true, msg: "Products found", products: Array(23)}
product-list.component.ts:20 product-list received updated products
... [उत्पादों को फ़िल्टर करने के लिए एक मेनू बटन पर क्लिक किया] ...
app.component.ts:19 app.component url: /products/chocolatechip
product-list.component.ts:18 product-list init...
product.service.ts:24 ## returning existing products
product-list.component.ts:20 product-list received updated products
निष्कर्ष: यह सबसे आसान तरीका है जो मैंने (अभी तक) कैचवेबल http प्रतिक्रिया डेटा को लागू करने के लिए पाया है। मेरे कोणीय ऐप में, हर बार जब मैं उत्पादों के एक अलग दृश्य पर नेविगेट करता हूं, तो उत्पाद-सूची घटक पुनः लोड होता है। ProductService एक साझा उदाहरण प्रतीत होता है, इसलिए ProductService में 'उत्पादों: उत्पाद [] के स्थानीय कैश को नेविगेशन के दौरान बरकरार रखा जाता है, और बाद में "GetProducts ()" कॉल किए गए मूल्य को वापस कर देता है। एक अंतिम नोट, मैंने टिप्पणियों के बारे में पढ़ा है कि जब आप 'मेमोरी लीक' को रोकने के लिए पर्यवेक्षक / सदस्यता को बंद करने की आवश्यकता होती है। मैंने इसे यहाँ शामिल नहीं किया है, लेकिन इसे ध्यान में रखना कुछ है।