Angular2 http.get (), map (), สมัครสมาชิก () และรูปแบบที่สังเกตได้ - ความเข้าใจพื้นฐาน


170

ตอนนี้ฉันมีหน้าเริ่มต้นที่ฉันมีสามลิงก์ เมื่อคุณคลิกที่ลิงก์ 'เพื่อน' ครั้งล่าสุดคอมโพเนนต์เพื่อนที่เหมาะสมจะได้รับการเริ่มต้น ในนั้นฉันต้องการดึงข้อมูล / รับรายชื่อเพื่อนของฉันที่เข้าสู่ไฟล์ friends.json จนถึงตอนนี้ทุกอย่างทำงานได้ดี แต่ฉันยังคงเป็นมือใหม่สำหรับบริการ HTTP ของ angular2 โดยใช้แนวคิดแผนที่ของ RxJs ที่สังเกตได้ ฉันพยายามที่จะเข้าใจและอ่านบทความไม่กี่ แต่จนกระทั่งฉันได้ทำงานจริงฉันจะไม่เข้าใจแนวคิดเหล่านั้นอย่างถูกต้อง

ที่นี่ฉันได้ทำ plnkr ซึ่งทำงานยกเว้นงานที่เกี่ยวข้องกับ HTTP

Plnkr

myfriends.ts

 import {Component,View,CORE_DIRECTIVES} from 'angular2/core';
 import {Http, Response,HTTP_PROVIDERS} from 'angular2/http';
 import 'rxjs/Rx';
 @Component({
    template: `
    <h1>My Friends</h1>
    <ul>
      <li *ngFor="#frnd of result">
          {{frnd.name}} is {{frnd.age}} years old.
      </li>
    </ul>
    `,
    directive:[CORE_DIRECTIVES]
  })

  export class FriendsList{

      result:Array<Object>; 
      constructor(http: Http) { 
        console.log("Friends are being called");

       // below code is new for me. So please show me correct way how to do it and please explain about .map and .subscribe functions and observable pattern.

        this.result = http.get('friends.json')
                      .map(response => response.json())
                      .subscribe(result => this.result =result.json());

        //Note : I want to fetch data into result object and display it through ngFor.

       }
  }

กรุณาแนะนำและอธิบายอย่างถูกต้อง ฉันรู้ว่ามันจะเป็นประโยชน์ต่อนักพัฒนาใหม่จำนวนมาก

คำตอบ:


205

นี่คือที่ที่คุณผิดพลาด:

this.result = http.get('friends.json')
                  .map(response => response.json())
                  .subscribe(result => this.result =result.json());

มันควรจะเป็น:

http.get('friends.json')
                  .map(response => response.json())
                  .subscribe(result => this.result =result);

หรือ

http.get('friends.json')
                  .subscribe(result => this.result =result.json());

คุณทำผิดสองครั้ง:

1- this.resultคุณมอบหมายสังเกตตัวเองไป this.resultเมื่อคุณต้องการจริงที่จะกำหนดรายชื่อของเพื่อนที่จะ วิธีที่ถูกต้องที่จะทำคือ:

  • คุณสมัครรับข้อมูลที่สังเกตได้ .subscribeเป็นฟังก์ชันที่เรียกใช้งานจริงที่สังเกตได้ ใช้พารามิเตอร์การติดต่อกลับสามพารามิเตอร์ดังนี้:

    .subscribe(success, failure, complete);

ตัวอย่างเช่น:

.subscribe(
    function(response) { console.log("Success Response" + response)},
    function(error) { console.log("Error happened" + error)},
    function() { console.log("the subscription is completed")}
);

โดยปกติคุณจะรับผลลัพธ์จากการติดต่อกลับสำเร็จแล้วกำหนดให้กับตัวแปรของคุณ ข้อผิดพลาดการโทรกลับเป็นตัวอธิบาย การโทรกลับเสร็จสมบูรณ์จะใช้เพื่อพิจารณาว่าคุณได้รับผลลัพธ์สุดท้ายโดยไม่มีข้อผิดพลาดใด ๆ บนตัวรวบรวมเสียงของคุณการเรียกกลับที่สมบูรณ์จะถูกเรียกใช้หลังจากความสำเร็จหรือข้อผิดพลาดในการติดต่อกลับ

2- ความผิดพลาดที่สองคุณเรียกว่า.json()บน.map(res => res.json())แล้วคุณเรียกมันอีกครั้งในการเรียกกลับความสำเร็จของการสังเกต .map()เป็นหม้อแปลงไฟฟ้าที่จะแปลงผลลัพธ์ให้เป็นสิ่งที่คุณส่งคืน (ในกรณีของคุณ.json()) ก่อนที่มันจะถูกส่งไปยังการเรียกกลับที่สำเร็จคุณควรเรียกมันว่าหนึ่งครั้งกับหนึ่งในนั้น


2
ที่นี่คุณไปplunker ของคุณ ฉันเปลี่ยนบรรทัด: 21, 23 ใน myfriends.ts
Abdulrahman Alsoghayer

1
สิ่งที่ฉันไม่เข้าใจคือเพราะเหตุใดจึงใช้ฟังก์ชั่น "แผนที่" ที่นี่เลย? เราสามารถเรียกผลลัพธ์. json ได้ ดังนั้นประโยชน์ของการทำเช่นนั้นคืออะไร?
rubmz

5
คุณถูก @rubmz คุณสามารถทำสิ่งที่ฉันกล่าวถึงในคำตอบของฉัน แต่ข้อดีอย่างหนึ่งคือการแยกตรรกะ getFriends(){return http.get('friends.json').map(r => r.json());}ยกตัวอย่างเช่นในการให้บริการของคุณคุณมีฟังก์ชั่น ตอนนี้คุณสามารถโทรgetFriends().subscribe(...)โดยไม่จำเป็นต้องโทร.json()ทุกครั้ง
Abdulrahman Alsoghayer

2
ใช่นี่เป็นเพียงความสับสนเล็กน้อยสำหรับมือใหม่ สิ่งที่แผนที่มิสเตอร์ () ทำอะไรและไม่ ... แต่ในที่สุดฉันก็ได้รับเช่นกัน :)
rubmz

1
@Abdulrahman คุณอาจสนใจที่จะดูคำถามนี้ด้วยเช่นกัน: stackoverflow.com/questions/40505691/…
nyluje

138

แนวคิด

สามารถสังเกตได้ในการประมวลผลแบบอะซิงโครนัสและเหตุการณ์สั้น ๆ การเปรียบเทียบกับสัญญานี้สามารถอธิบายได้ว่าเป็นสิ่งที่สามารถสังเกตได้ = สัญญา + เหตุการณ์

สิ่งที่ยอดเยี่ยมสำหรับสิ่งที่สังเกตได้คือพวกมันขี้เกียจพวกเขาสามารถยกเลิกได้และคุณสามารถใช้ตัวดำเนินการบางอย่างในตัวพวกเขา (เช่นmap, ... ) สิ่งนี้ช่วยให้สามารถจัดการสิ่งที่ไม่ตรงกันในวิธีที่ยืดหยุ่นได้มาก

ตัวอย่างที่ดีที่อธิบายถึงพลังของสิ่งที่สังเกตได้ดีที่สุดคือวิธีการเชื่อมต่ออินพุตตัวกรองเข้ากับรายการตัวกรองที่สอดคล้องกัน เมื่อผู้ใช้ป้อนอักขระรายการจะถูกรีเฟรช Observables จัดการการร้องขอ AJAX ที่สอดคล้องกันและยกเลิกการร้องขอที่กำลังดำเนินการก่อนหน้าหากมีการเรียกใช้อีกค่าใหม่ในอินพุต นี่คือรหัสที่เกี่ยวข้อง:

this.textValue.valueChanges
    .debounceTime(500)
    .switchMap(data => this.httpService.getListValues(data))
    .subscribe(data => console.log('new list values', data));

( textValueคือตัวควบคุมที่เกี่ยวข้องกับอินพุตตัวกรอง)

นี่คือคำอธิบายที่กว้างขึ้นเกี่ยวกับกรณีการใช้งานดังกล่าว: วิธีดูการเปลี่ยนแปลงแบบฟอร์มใน Angular 2 .

มีการนำเสนอที่ยอดเยี่ยมสองอย่างที่ AngularConnect 2015 และ EggHead:

Christoph Burgdorf ยังได้เขียนบทความบล็อกที่ยอดเยี่ยมในหัวข้อ:

ในการปฏิบัติ

ในความเป็นจริงเกี่ยวกับรหัสของคุณคุณผสมสองวิธี ;-) นี่คือ:

  • จัดการที่สังเกตได้ด้วยตัวคุณเอง ในกรณีนี้คุณต้องรับผิดชอบในการเรียกใช้subscribeเมธอดบนสิ่งที่สังเกตได้และกำหนดผลลัพธ์ลงในแอตทริบิวต์ขององค์ประกอบ จากนั้นคุณสามารถใช้แอททริบิวนี้ในมุมมองเพื่อวนซ้ำคอลเลกชัน:

    @Component({
      template: `
        <h1>My Friends</h1>
        <ul>
          <li *ngFor="#frnd of result">
            {{frnd.name}} is {{frnd.age}} years old.
          </li>
        </ul>
      `,
      directive:[CORE_DIRECTIVES]
    })
    export class FriendsList implement OnInit, OnDestroy {
      result:Array<Object>; 
    
      constructor(http: Http) {
      }
    
      ngOnInit() {
        this.friendsObservable = http.get('friends.json')
                      .map(response => response.json())
                      .subscribe(result => this.result = result);
       }
    
       ngOnDestroy() {
         this.friendsObservable.dispose();
       }
    }
    

    ผลตอบแทนจากทั้งสองgetและmapวิธีการเป็นสิ่งที่สังเกตได้ไม่ใช่ผลลัพธ์ (ในลักษณะเดียวกันกับสัญญา)

  • ให้จัดการที่สังเกตได้โดยแม่แบบเชิงมุม คุณยังสามารถใช้ประโยชน์จากasyncไปป์ในการจัดการสิ่งที่สังเกตได้โดยปริยาย ในกรณีนี้ไม่จำเป็นต้องเรียกsubscribeเมธอดอย่างชัดเจน

    @Component({
      template: `
        <h1>My Friends</h1>
        <ul>
          <li *ngFor="#frnd of (result | async)">
            {{frnd.name}} is {{frnd.age}} years old.
          </li>
        </ul>
      `,
      directive:[CORE_DIRECTIVES]
    })
    export class FriendsList implement OnInit {
      result:Array<Object>; 
    
      constructor(http: Http) {
      }
    
      ngOnInit() {
        this.result = http.get('friends.json')
                      .map(response => response.json());
       }
    }
    

คุณสามารถสังเกตเห็นว่าสิ่งที่สังเกตได้ขี้เกียจ ดังนั้นคำขอ HTTP ที่สอดคล้องกันจะถูกเรียกเพียงครั้งเดียวฟังที่แนบมากับมันโดยใช้subscribeวิธีการ

นอกจากนี้คุณยังสามารถสังเกตเห็นว่าmapวิธีการที่ใช้ในการแยกเนื้อหา JSON จากการตอบสนองและใช้มันในการประมวลผลที่สังเกตได้

หวังว่านี่จะช่วยคุณได้ธีรี่ร์


ขอบคุณสำหรับการอ้างอิงทั้งหมด แต่คุณสามารถช่วยฉันด้วยเสียงดังปัง ๆ ของฉันได้ไหม
nyks

ฉันอัพเดตคำตอบของฉันพร้อมรายละเอียดเพิ่มเติมเกี่ยวกับรหัสของคุณ หวังว่ามันจะช่วยคุณได้ ;-)
Thierry Templier

ขอโทษที่ฉันตอบคุณไม่ได้ ชัดเจนยิ่งขึ้น แต่คำตอบที่ได้รับการยอมรับและชื่นชมช่วยให้ฉันเข้าใจคำถามของฉันได้มากพอ แต่หวังว่าคุณจะได้รับความนิยมอย่างมากสำหรับคำตอบที่ชัดเจนเนื่องจากคุณมีคำอธิบายโดยละเอียด คำตอบที่ได้รับการยอมรับเช่นกันสำหรับการทำความเข้าใจพื้นฐานที่ดี
micronyks

2
Thierry Templier นี่เป็นคำตอบที่ยอดเยี่ยม แต่มีสิ่งหนึ่งที่ไม่ชัดเจนสำหรับฉันฉันขอ http.get ('friends.json') .map (response => response.json ()) คืนค่าที่สังเกตได้ <Array <Object>> ถ้าเป็นเช่นนั้นคุณส่งมาได้อย่างไร? พวกเขาเป็นประเภทที่แตกต่าง
Stav Alfi

@StavAlfi ยังมีpipes observablesลองชมวิดีโอนี้: youtube.com/watch?v=bVI5gGTEQ_Uแนะนำโดย thierry สำหรับข้อมูลเพิ่มเติม
candidJJ

11
import { HttpClientModule } from '@angular/common/http';

HttpClient API ได้รับการแนะนำในรุ่น 4.3.0 มันเป็นวิวัฒนาการของ HTTP API ที่มีอยู่และมีแพ็คเกจเป็นของตัวเอง @ angular / common / http การเปลี่ยนแปลงที่โดดเด่นที่สุดอย่างหนึ่งคือตอนนี้วัตถุตอบสนองคือ JSON โดยค่าเริ่มต้นดังนั้นไม่จำเป็นต้องแยกวิเคราะห์ด้วยวิธีการแผนที่อีกต่อไปตรงที่เราสามารถใช้งานได้ด้านล่าง

http.get('friends.json').subscribe(result => this.result =result);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.