কৌণিক 2 পরিষেবা থেকে পর্যবেক্ষণযোগ্য তৈরি করা এবং ফিরে আসা


132

এটি আরও একটি "সেরা অনুশীলন" প্রশ্ন। তিনজন খেলোয়াড় রয়েছে: ক Component, ক Serviceএবং ক ModelComponentকল করছে Serviceএকটি ডাটাবেস থেকে তথ্য পেতে। দ্যServiceব্যবহার করছে:

this.people = http.get('api/people.json').map(res => res.json());

to an an Observable

Componentশুধু সাবস্ক্রাইব পারে Observable:

    peopleService.people
        .subscribe(people => this.people = people);
      }

যাইহোক, আমি যা চাই তা হ'ল ডাটাবেস থেকে প্রাপ্ত তথ্য থেকে তৈরি হওয়া Serviceকোনও Array of Modelবস্তু Serviceফিরিয়ে আনা। আমি বুঝতে পেরেছি যে Componentসাবস্ক্রাইব পদ্ধতিতে কেবল এই অ্যারেটি তৈরি করতে পারে তবে আমি মনে করি যে পরিষেবাটি যদি এটি করে এবং এটি সরবরাহ করে তবে এটি পরিষ্কার হয়ে যাবে Component

কীভাবে Serviceসৃষ্টিটি নতুন তৈরি করতে পারে Observable, সেই অ্যারে ধারণ করে এবং এটি ফেরত দিতে পারে?

উত্তর:


158

আপডেট: 9/24/16 কৌনিক 2.0 স্থিতিশীল

এই প্রশ্নটি এখনও অনেক ট্র্যাফিক পায়, তাই, আমি এটি আপডেট করতে চেয়েছিলাম। আলফা, বিটা এবং R টি আরসি পরীক্ষার্থীর পরিবর্তনের উন্মাদতার সাথে আমি আমার এসও উত্তরগুলি স্থিতিশীল না হওয়া পর্যন্ত আপডেট করা বন্ধ করে দিয়েছি।

সাবজেক্টস এবং রিপ্লেসুবজেক্টগুলি ব্যবহারের জন্য এটি উপযুক্ত ক্ষেত্রে

আমি ব্যক্তিগতভাবে ব্যবহার করতে পছন্দ করি ReplaySubject(1)কারণ এটি সর্বশেষ সঞ্চিত মানটি পাস করার অনুমতি দেয় যখন নতুন গ্রাহকরা দেরি হলেও সংযুক্ত করে:

let project = new ReplaySubject(1);

//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result));

http.get('path/to/whatever/projects/1234').subscribe(result => {
    //push onto subject
    project.next(result));

    //add delayed subscription AFTER loaded
    setTimeout(()=> project.subscribe(result => console.log('Delayed Stream:', result)), 3000);
});

//Output
//Subscription Streaming: 1234
//*After load and delay*
//Delayed Stream: 1234

সুতরাং আমি যদি দেরীতে সংযুক্ত করি বা পরে লোড করা প্রয়োজন হয় তবে আমি সর্বদা সর্বশেষতম কলটি পেতে পারি এবং কলব্যাকটি অনুপস্থিত হওয়ার বিষয়ে চিন্তা করতে পারি না।

এটি আপনাকে নীচে চাপতে একই স্ট্রিমটি ব্যবহার করতে দেয়:

project.next(5678);
//output
//Subscription Streaming: 5678

তবে আপনি যদি 100% নিশ্চিত হন তবে আপনার কেবল একবার কল করা দরকার? উন্মুক্ত বিষয় এবং পর্যবেক্ষণযোগ্যগুলি ছেড়ে দেওয়া ভাল না তবে সর্বদা "" যদি তবে কি হয়? "

সেখানেই অ্যাসিঙ্কসুবজেক্ট আসবে।

let project = new AsyncSubject();

//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result),
                  err => console.log(err),
                  () => console.log('Completed'));

http.get('path/to/whatever/projects/1234').subscribe(result => {
    //push onto subject and complete
    project.next(result));
    project.complete();

    //add a subscription even though completed
    setTimeout(() => project.subscribe(project => console.log('Delayed Sub:', project)), 2000);
});

//Output
//Subscription Streaming: 1234
//Completed
//*After delay and completed*
//Delayed Sub: 1234

অসাধারণ! আমরা বিষয়টি বন্ধ করে দিলেও এটি এখনও লোড হওয়া শেষ জিনিসটির সাথে জবাব দিয়েছে।

আরেকটি বিষয় হ'ল আমরা কীভাবে সেই http কলটিতে সাবস্ক্রাইব করেছি এবং প্রতিক্রিয়াটি পরিচালনা করেছি। প্রতিক্রিয়াটি প্রক্রিয়া করতে মানচিত্রটি দুর্দান্ত।

public call = http.get(whatever).map(res => res.json())

কিন্তু আমাদের যদি এই কলগুলিতে বাসা বাঁধার দরকার হয়? হ্যাঁ আপনি একটি বিশেষ ফাংশন সহ বিষয়গুলি ব্যবহার করতে পারেন:

getThing() {
    resultSubject = new ReplaySubject(1);

    http.get('path').subscribe(result1 => {
        http.get('other/path/' + result1).get.subscribe(response2 => {
            http.get('another/' + response2).subscribe(res3 => resultSubject.next(res3))
        })
    })
    return resultSubject;
}
var myThing = getThing();

তবে এটি অনেক এবং এর অর্থ এটি করতে আপনার কোনও ফাংশন প্রয়োজন। ফ্ল্যাটম্যাপ প্রবেশ করুন :

var myThing = http.get('path').flatMap(result1 => 
                    http.get('other/' + result1).flatMap(response2 => 
                        http.get('another/' + response2)));

মিষ্টি, এটি varএমন একটি পর্যবেক্ষণযোগ্য যা চূড়ান্ত HTTP কল থেকে ডেটা পায় gets

ঠিক আছে দুর্দান্ত তবে আমি একটি কৌনিক 2 পরিষেবা চাই!

আমি আপনাকে পেয়েছি:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ReplaySubject } from 'rxjs';

@Injectable()
export class ProjectService {

  public activeProject:ReplaySubject<any> = new ReplaySubject(1);

  constructor(private http: Http) {}

  //load the project
  public load(projectId) {
    console.log('Loading Project:' + projectId, Date.now());
    this.http.get('/projects/' + projectId).subscribe(res => this.activeProject.next(res));
    return this.activeProject;
  }

 }

 //component

@Component({
    selector: 'nav',
    template: `<div>{{project?.name}}<a (click)="load('1234')">Load 1234</a></div>`
})
 export class navComponent implements OnInit {
    public project:any;

    constructor(private projectService:ProjectService) {}

    ngOnInit() {
        this.projectService.activeProject.subscribe(active => this.project = active);
    }

    public load(projectId:string) {
        this.projectService.load(projectId);
    }

 }

আমি পর্যবেক্ষক এবং পর্যবেক্ষণযোগ্যদের একটি বড় ভক্ত তাই আমি আশা করি এই আপডেটটি সাহায্য করবে!

আসল উত্তর

আমি এই একটি ব্যবহারের একটি ব্যবহার ক্ষেত্রে দেখা যায় পর্যবেক্ষণযোগ্য বিষয় বা ।Angular2EventEmitter

আপনার পরিষেবাতে আপনি এমন একটি তৈরি করেন EventEmitterযা আপনাকে এর উপর মানগুলিকে চাপতে দেয়। ইন আলফা 45 আপনার সাথে রুপান্তরিত করতে হবে toRx(), কিন্তু আমি জানি তারা যে পরিত্রাণ পেতে কাজ করছিল, তাই আলফা 46 আপনি কেবল আসতে সক্ষম হতে পারে EvenEmitter

class EventService {
  _emitter: EventEmitter = new EventEmitter();
  rxEmitter: any;
  constructor() {
    this.rxEmitter = this._emitter.toRx();
  }
  doSomething(data){
    this.rxEmitter.next(data);
  }
}

এই উপায় একক আছে EventEmitterআপনার বিভিন্ন পরিষেবা ফাংশনগুলিতে এখন এগিয়ে যেতে পারে এমন ।

আপনি যদি সরাসরি কোনও কল থেকে একটি পর্যবেক্ষণযোগ্য ফিরিয়ে দিতে চান তবে আপনি এই জাতীয় কিছু করতে পারেন:

myHttpCall(path) {
    return Observable.create(observer => {
        http.get(path).map(res => res.json()).subscribe((result) => {
            //do something with result. 
            var newResultArray = mySpecialArrayFunction(result);
            observer.next(newResultArray);
            //call complete if you want to close this stream (like a promise)
            observer.complete();
        });
    });
}

এটি আপনাকে উপাদানটিতে এটি করতে দেয়: peopleService.myHttpCall('path').subscribe(people => this.people = people);

এবং আপনার সেবার কল থেকে প্রাপ্ত ফলাফলগুলির সাথে গণ্ডগোল।

আমি তৈরি করতে চাই EventEmitter অন্যান্য উপাদান থেকে এটিতে অ্যাক্সেস পাওয়ার প্রয়োজন হলে আমি নিজেই স্ট্রিম তবে আমি উভয় উপায়েই কাজ করতে দেখতে পেলাম ...

এখানে এমন এক প্লাঙ্কার যা ইভেন্ট ইমিটারের সাথে একটি প্রাথমিক পরিষেবা দেখায়: Plunkr


আমি এই পদ্ধতির চেষ্টা করেছি কিন্তু "নতুন ব্যবহার করতে পারছি না" এমন একটি অভিব্যক্তি দিয়ে যার টাইপের কোনও কল নেই বা স্বাক্ষর তৈরি করতে পারে না "-অরর। কারও ধারণা আছে কী করবেন?
স্পষ্ট 21

3
@ স্পোকটিকে এই আসল প্রশ্নটি থেকে আপডেট মনে হয়েছে। পর্যবেক্ষণযোগ্যদের জন্য আপনার আর "নতুন" দরকার নেই কারণ এটি আপনার জন্য এটি করে। কেবল নতুনটি সরান এবং কী ঘটে তা আমাকে জানান। আমি এখন কিছু জিনিস নিয়ে
গণ্ডগোল

1
যে EventEmitterকোনও কিছুর জন্য ব্যবহার @Output()করা নিরুত্সাহিত। আরও দেখুন stackoverflow.com/questions/34376854/...
গুন্টার Zöchbauer

@ গন্তেরজ্যাচবাউয়ার, হ্যাঁ এটি এখন ... সেই সময়টি ইভেন্ট জুড়েই চলছিল তবে তারা আরএক্স অবজারভেবলগুলিকে মানক করে দিয়েছে। আমার পর্যবেক্ষণযোগ্য উদাহরণটি এখনও কার্যকর হয় তবে আপনি যদি ইভেন্টইমিটার উদাহরণটি ব্যবহার করতে যাচ্ছিলেন তবে আমি সাবজেক্টগুলি সরাসরি ব্যবহার করার পরামর্শ দিয়েছি: github.com/Reactive-Extensions/RxJS/blob/master/doc/api/…
ডেনিস স্মোলেক

1
@ ম্যাক্সিসাম সম্পাদনার জন্য ধন্যবাদ, যদিও উত্তরটি পর্যবেক্ষণযোগ্যদের জন্য "নতুন" মুছে ফেলার জন্য আলফার সাথে সম্পর্কিত / আপেক্ষিক এখন সঠিক
ডেনিস স্মোলেক

29

আপনি কীভাবে আপনার নিজের পর্যবেক্ষণগুলি তৈরি করতে এবং ব্যবহার করতে পারেন তার এটি Angular2 ডক্সের একটি উদাহরণ :

সেবা

import {Injectable} from 'angular2/core'
import {Subject}    from 'rxjs/Subject';
@Injectable()
export class MissionService {
  private _missionAnnouncedSource = new Subject<string>();
  missionAnnounced$ = this._missionAnnouncedSource.asObservable();

  announceMission(mission: string) {
    this._missionAnnouncedSource.next(mission)
  }
}

কম্পোনেন্ট

    import {Component}          from 'angular2/core';
    import {MissionService}     from './mission.service';

    export class MissionControlComponent {
      mission: string;

      constructor(private missionService: MissionService) {

        missionService.missionAnnounced$.subscribe(
          mission => {
            this.mission = mission;
          })
      }

      announce() {
        this.missionService.announceMission('some mission name');
      }
    }

পূর্ণ এবং কার্যকারী উদাহরণটি এখানে পাওয়া যাবে: https://angular.io/docs/ts/latest/cookbook/comp घटक-communication.html#!# দ্বিদ্বন্দ্বী-পরিষেবা


18

আমি যুক্ত করতে চাই যে তৈরি করা বস্তুটি যদি স্থির হয় এবং HTTP এর মাধ্যমে না আসে তবে এরকম কিছু করা যায়:

public fetchModel(uuid: string = undefined): Observable<string> {
      if(!uuid) { //static data
        return Observable.of(new TestModel()).map(o => JSON.stringify(o));
      }
      else {
        return this.http.get("http://localhost:8080/myapp/api/model/" + uuid)
                .map(res => res.text());
      }
    }

সম্পাদনা করুন: কৌণিক 7.XX ম্যাপিংয়ের জন্য পাইপ () ব্যবহার করে এখানে করা উচিত ( https://stackoverflow.com/a/54085359/986160 ):

import {of,  Observable } from 'rxjs';
import { map } from 'rxjs/operators';
[...]
public fetchModel(uuid: string = undefined): Observable<string> {
      if(!uuid) { //static data
        return of(new TestModel());
      }
      else {
        return this.http.get("http://localhost:8080/myapp/api/model/" + uuid)
                .pipe(map((res:any) => res)) //already contains json
      }
    }

পর্যবেক্ষক এবং স্থিতিশীল ডেটা সম্পর্কে আমার প্রশ্নের উত্তর থেকে: https://stackoverflow.com/a/35219772/986160


17

আমি পার্টিতে কিছুটা দেরি করেছি, তবে আমি মনে করি আমার পদ্ধতির সুবিধা রয়েছে যে এটিতে ইভেন্টমিটার এবং বিষয়গুলির ব্যবহারের অভাব রয়েছে।

সুতরাং, এখানে আমার পদ্ধতির। আমরা সাবস্ক্রাইব () থেকে দূরে যেতে পারি না এবং আমরা চাই না। সেই শিরাতে, আমাদের পরিষেবা Observable<T>এমন একজন পর্যবেক্ষকের সাথে ফিরে আসবে যার কাছে আমাদের মূল্যবান কার্গো রয়েছে। কলকারী থেকে, আমরা একটি পরিবর্তনশীল সূচনা করব Observable<T>, এবং এটি পরিষেবাটি পাবে Observable<T>। পরবর্তী, আমরা এই বস্তুর সাবস্ক্রাইব করব। অবশেষে, আপনি আপনার "টি" পান! আপনার পরিষেবা থেকে

প্রথমত, আমাদের লোকেরা পরিষেবা দেয় তবে আপনারা প্যারামিটারগুলি পাস করেন না, এটি আরও বাস্তবসম্মত:

people(hairColor: string): Observable<People> {
   this.url = "api/" + hairColor + "/people.json";

   return Observable.create(observer => {
      http.get(this.url)
          .map(res => res.json())
          .subscribe((data) => {
             this._people = data

             observer.next(this._people);
             observer.complete();


          });
   });
}

ঠিক আছে, আপনি দেখতে পাচ্ছেন, আমরা একটি ফিরে আসছি Observable "লোক" টাইপ করে । পদ্ধতির স্বাক্ষর, এমন কি বলে! আমরা _peopleআমাদের পর্যবেক্ষকের মধ্যে বস্তুকে টাক-ইন করি । আমরা পরের অংশে আমাদের কলার থেকে এই ধরণের অ্যাক্সেস করব!

অংশে:

private _peopleObservable: Observable<people>;

constructor(private peopleService: PeopleService){}

getPeople(hairColor:string) {
   this._peopleObservable = this.peopleService.people(hairColor);

   this._peopleObservable.subscribe((data) => {
      this.people = data;
   });
}

আমরা আমাদের থেকে _peopleObservableএটি ফেরত দিয়ে আমাদের সূচনা করি । তারপরে, আমরা এই সম্পত্তি সাবস্ক্রাইব। অবশেষে, আমরা সেটObservable<people>PeopleServicethis.people আমাদের ডেটা ( people) প্রতিক্রিয়া ।

এই ফ্যাশনে পরিষেবাটি আর্কিটেক্ট করার একটি সাধারণ বৈশিষ্ট্যের চেয়ে বড় সুবিধা রয়েছে: মানচিত্র (...) এবং উপাদান: "সাবস্ক্রাইব (...)" প্যাটার্ন। বাস্তব বিশ্বে, আমাদের ক্লাসে থাকা আমাদের সম্পত্তিগুলিতে জসনকে ম্যাপ করা দরকার এবং কখনও কখনও আমরা সেখানে কিছু কাস্টম স্টাফ করি। সুতরাং এই পরিষেবাটি আমাদের পরিষেবায় ঘটতে পারে। এবং, সাধারণত, কারণ আমাদের পরিষেবা কলটি একবার ব্যবহার করা হবে না, তবে সম্ভবত, আমাদের কোডের অন্য জায়গাগুলিতে, আমাদের আবার কোনও অংশে সেই ম্যাপিং করতে হবে না। তদুপরি, আমরা যদি মানুষের সাথে একটি নতুন ক্ষেত্র যুক্ত করি তবে? ....


আমি সম্মত হলাম যে ফর্ম্যাটিংটি সেবার মধ্যে থাকা উচিত এবং আমি একটি মানক পর্যবেক্ষণযোগ্য পদ্ধতিও পোস্ট করেছি তবে পরিষেবাতে সাবজেক্টের সুবিধা হ'ল অন্যান্য ফাংশন এটিতে ট্রিগার করতে পারে। আপনার যদি সর্বদা কেবল সরাসরি HTTP কলের প্রয়োজন হয় তবে আমি পর্যবেক্ষণযোগ্য পদ্ধতিটি ব্যবহার করব ..
ডেনিস স্মোলেক

9

সার্ভিস.টি ফাইলগুলিতে -

ক। পর্যবেক্ষণযোগ্য / এর
খ থেকে 'এর' আমদানি করুন । একটি জেসন তালিকা তৈরি করুন
গ। Observable.of ()
প্রাক্তন ব্যবহার করে জেসন বস্তুটি ফেরত দিন । -

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';

@Injectable()
export class ClientListService {
    private clientList;

    constructor() {
        this.clientList = [
            {name: 'abc', address: 'Railpar'},
            {name: 'def', address: 'Railpar 2'},
            {name: 'ghi', address: 'Panagarh'},
            {name: 'jkl', address: 'Panagarh 2'},
        ];
    }

    getClientList () {
        return Observable.of(this.clientList);
    }
};

যে উপাদানটিতে আমরা পরিষেবাটির ফাংশনটি কল করছি -

this.clientListService.getClientList().subscribe(res => this.clientList = res);

ভাল কাজ @ অনির্বাণ, কেবল (this.clientList) ফিরে আসতে পারে;
ফু-বার

7

লক্ষ্য করুন যে আপনি কাঁচা বস্তুকে রূপান্তর করতে পর্যবেক্ষণযোগ্য # মানচিত্রটি ব্যবহার করছেন Responseআপনার বেস পর্যবেক্ষণযোগ্যটি JSON প্রতিক্রিয়াটির বিশ্লেষণ উপস্থাপনায় প্রকাশ করে।

আমি যদি আপনাকে সঠিকভাবে বুঝতে পারি তবে আপনি mapআবার চান । তবে এবার সেই কাঁচা JSON কে আপনার দৃষ্টান্তে রূপান্তরিত করছে Model। সুতরাং আপনি যেমন কিছু করতে হবে:

http.get('api/people.json')
  .map(res => res.json())
  .map(peopleData => peopleData.map(personData => new Person(personData)))

সুতরাং, আপনি এমন একটি পর্যবেক্ষণযোগ্য দিয়ে শুরু করেছিলেন যা কোনও Responseঅবজেক্টকে নির্গত করে , এটি একটি পর্যবেক্ষণযোগ্য করে তোলে যা সেই প্রতিক্রিয়াটির পার্সড জেএসওনের কোনও উপাদানকে নির্গত করে এবং তারপরে এটি আর একটি পর্যবেক্ষণযোগ্য করে তোলে যা সেই কাঁচা জেএসএনকে আপনার মডেলগুলির একটি অ্যারে রূপান্তরিত করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.