2016-03-02 22 views
7

Tôi có một dự án angular2 như sau:Angular2 mẫu cố gắng để render giá trị trước khi giá trị trả về từ http.get

package.json:

{ 
    "name": "self-assessment", 
    "version": "1.0.0", 
    "scripts": { 
    "postinstall": "npm run typings install", 
    "lite": "lite-server", 
    "gulp": "gulp", 
    "start": "concurrent \"npm run gulp\" \"npm run lite\" ", 
    "typings" : "typings" 
    }, 
    "license": "ISC", 
    "dependencies": { 
    "angular2": "2.0.0-beta.3", 
    "systemjs": "0.19.6", 
    "es6-promise": "^3.0.2", 
    "es6-shim": "^0.33.3", 
    "reflect-metadata": "0.1.2", 
    "rxjs": "5.0.0-beta.0", 
    "zone.js": "0.5.11" 
    }, 
    "devDependencies": { 
    "autoprefixer": "^6.2.1", 
    "cssnano": "^3.4.0", 
    "concurrently": "^1.0.0", 
    "gulp": "^3.9.0", 
    "gulp-ext-replace": "^0.2.0", 
    "gulp-imagemin": "^2.4.0", 
    "gulp-postcss": "^6.0.1", 
    "gulp-sourcemaps": "^1.6.0", 
    "gulp-typescript": "^2.10.0", 
    "gulp-uglify": "^1.5.1", 
    "lite-server": "^2.0.1", 
    "postcss": "^5.0.13", 
    "postcss-scss": "^0.1.3", 
    "precss": "^1.3.0", 
    "typings":"^0.6.8", 
    "tsd": "^0.6.5-beta" 
    } 
} 

app.component.ts:

import {Component} from 'angular2/core'; 
import {AssessmentListComponent} from "./assessment-list.component"; 
import {HomeComponent} from "./home.component"; 
import {ApiService} from "../services/api.service"; 
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from 'angular2/router'; 
import {AssessmentComponent} from "./assessment.component"; 

@Component({ 
    selector: 'my-app', 
    templateUrl: 'app/components/app.component.html', 
    directives: [ 
     ROUTER_DIRECTIVES, 
    ], 
    providers: [ 
     ApiService, 
     ROUTER_PROVIDERS, 
    ] 
}) 
@RouteConfig([ 
    {path: '/home', name: 'Home', component: HomeComponent, useAsDefault: true}, 
    {path: '/assessments', name: 'Assessments', component: AssessmentListComponent}, 
    {path: '/assessment/:id', name: 'Assessment', component: AssessmentComponent}, 

]) 
export class AppComponent { 

    title = "Welcome to Self-Assessment" 

} 

assessment.component.ts:

import {Component, OnInit} from 'angular2/core'; 
import {AssessmentModel} from '../models/assessment.model'; 
import {RouteParams} from 'angular2/router'; 
import {ApiService} from '../services/api.service'; 

@Component({ 
    selector: 'assessment-component', 
    templateUrl: 'app/components/assessment.component.html', 
}) 
export class AssessmentComponent implements OnInit{ 
    assessment: AssessmentModel; 
    errorMessage: any; 

    constructor(
     private _apiService: ApiService, 
     private _routeParams: RouteParams 
    ) {} 


    ngOnInit():any { 
     let id = +this._routeParams.get('id'); 
     this.getAssessment(id); 
    } 

    private getAssessment(id: number) { 
     this._apiService.getAssessment(id) 
      .subscribe(
       assessment => this.assessment = assessment, 
       error => this.errorMessage = <any>error 
      ); 
    } 

    goBack() { 
     console.log(this.assessment); 
    } 
} 

api.service.ts:

import {Injectable} from 'angular2/core'; 
import {Http, Response} from 'angular2/http'; 
import {Observable} from 'rxjs/Observable'; 

@Injectable() 
export class ApiService { 
    constructor(private _http: Http) {} 

    private _baseApiUrl = 'http://localhost:8000/'; 

    getAssessments() { 
     return this.getObjectList('assessments', 'json'); 
    } 

    getAssessment(id: number) { 
     return this.getObject('assessments', id, 'json'); 
    } 

    getObjectList(listName:string, listExtension: string) { 

     var url = this._baseApiUrl + listName + '.' + listExtension; 

     return this._http.get(url) 
      .map(response => response.json()) 
      .catch(this.handleError); 
    } 

    getObject(objectName:string, objectId:number, objectExtension: string) { 

     var url = this._baseApiUrl + objectName + '/' + objectId + '.' + objectExtension; 

     return this._http.get(url) 
      .map(response => response.json()) 
      .catch(this.handleError); 
    } 

    private handleError(error: Response) { 
     console.error(error); 
     return Observable.throw(error.json().error || 'Server error'); 
    } 
} 

và cuối cùng assessment.component.html:

<h3>{{ assessment.id }}</h3> 
<button (click)="goBack()">Go Back 2</button> 

Khi trang web được gọi với url: http://localhost:3000/assessment/4 nó thực hiện các cuộc gọi thích hợp cho back2 end hai lần và tạo ra các lỗi sau đây trong bảng điều khiển

Uncaught EXCEPTION: TypeError: Cannot read property 'id' of undefined in [{{ assessment.id }} in [email protected]:4] 
ORIGINAL EXCEPTION: TypeError: Cannot read property 'id' of undefined 
ORIGINAL STACKTRACE: 
TypeError: Cannot read property 'id' of undefined 
    at AbstractChangeDetector.ChangeDetector_AssessmentComponent_0.detectChangesInRecordsInternal (viewFactory_AssessmentComponent:30:28) 
    at AbstractChangeDetector.detectChangesInRecords (http://localhost:3000/node_modules/angular2/bundles/angular2.dev.js:8116:14) 
    at AbstractChangeDetector.runDetectChanges (http://localhost:3000/node_modules/angular2/bundles/angular2.dev.js:8099:12) 
    at AbstractChangeDetector._detectChangesInViewChildren (http://localhost:3000/node_modules/angular2/bundles/angular2.dev.js:8184:14) 
    at AbstractChangeDetector.runDetectChanges (http://localhost:3000/node_modules/angular2/bundles/angular2.dev.js:8103:12) 
    at AbstractChangeDetector._detectChangesContentChildren (http://localhost:3000/node_modules/angular2/bundles/angular2.dev.js:8178:14) 
    at AbstractChangeDetector.runDetectChanges (http://localhost:3000/node_modules/angular2/bundles/angular2.dev.js:8100:12) 
    at AbstractChangeDetector._detectChangesInViewChildren (http://localhost:3000/node_modules/angular2/bundles/angular2.dev.js:8184:14) 
    at AbstractChangeDetector.runDetectChanges (http://localhost:3000/node_modules/angular2/bundles/angular2.dev.js:8103:12) 
    at AbstractChangeDetector.detectChanges (http://localhost:3000/node_modules/angular2/bundles/angular2.dev.js:8088:12) 
ERROR CONTEXT: 
[object Object]ExceptionHandler.call @ angular2.dev.js:1206(anonymous function) @ angular2.dev.js:12591NgZone._notifyOnError @ angular2.dev.js:13635collection_1.StringMapWrapper.merge.onError @ angular2.dev.js:13539Zone.run @ angular2-polyfills.js:1247NgZone._notifyOnTurnDone @ angular2.dev.js:13450(anonymous function) @ angular2.dev.js:13565zoneBoundFn @ angular2-polyfills.js:1220lib$es6$promise$asap$$flush @ angular2-polyfills.js:262 

Vì vậy, nó có vẻ như thể {{}} assessment.id đang cố gắng để render trước khi đối tượng được trả về từ back-end. Nếu tôi sau đó nhấn vào nút "Go Back 2" nút nó sẽ an ủi đăng đối tượng thích hợp:.

{"id":4,"title":"Assessment Title here!","description":"Here is a description","questions":["http://localhost:8000/questions/1.json","http://localhost:8000/questions/2.json","http://localhost:8000/questions/3.json","http://localhost:8000/questions/4.json","http://localhost:8000/questions/5.json","http://localhost:8000/questions/6.json","http://localhost:8000/questions/7.json","http://localhost:8000/questions/8.json","http://localhost:8000/questions/9.json","http://localhost:8000/questions/10.json","http://localhost:8000/questions/11.json","http://localhost:8000/questions/12.json","http://localhost:8000/questions/13.json"],"responses":[]} 

"Điều thú vị là" Tôi không nhìn thấy vấn đề ở những nơi khác trong ứng dụng (ví dụ có thể tải và hiển thị assessment- danh sách tốt, vv). Ngoài ra, tôi có cùng một vấn đề trong một ứng dụng Ionic2 tôi đã làm việc với đêm qua như một dự án học tập.

Đã googled mông của tôi ra, hy vọng ai đó biết câu trả lời cho câu đố này.

Cảm ơn!

+1

Thử '{{assessment? .id}}' '- [toán tử Elvis] (https://angular.io/docs/ts/latest/guide/template-syntax.html#!#expression-operators). Bạn có thể không có vấn đề với danh sách vì 'NgFor' xử lý trường hợp mảng không xác định hoặc trống cho bạn. Sau đó, khi dữ liệu xuất hiện, 'NgFor' được đánh giá lại. –

+0

Điều đó có hiệu quả, cảm ơn bạn. Đó là một cách 'đúng' để giải quyết nó hay là có một giải pháp thích hợp hơn? Nó có vẻ kỳ lạ mà sẽ không được đề cập trong bất kỳ hướng dẫn và như vậy tôi đã nhìn vào (mà tôi đã nhận thấy anyway). Cảm ơn @MarkRajcok! – Gerald

+0

Xem câu trả lời của tôi. Nhiều hướng dẫn thích hiển thị các ví dụ với các danh sách, đó có lẽ là lý do tại sao toán tử Elvis thường không được các nhà phát triển học hỏi về Góc. (Câu hỏi này xuất hiện thường xuyên trên SO.) –

Trả lời

10

Bạn có hai lựa chọn:

  1. sử dụng safe navigation operator (trước đây gọi là các nhà điều hành Elvis), {{ assessment?.id }}, mà bảo vệ chống lại các giá trị null và undefined
  2. sử dụng NgIf, <h3 *ngIf="assessment">{{assessment.id}}</h3>, đó là thích hợp hơn nếu bạn don Không muốn các phần tử được thêm vào DOM cho đến khi dữ liệu có sẵn/được điền vào

Bạn có thể không gặp vấn đề với danh sách vì NgFor xử lý trường hợp mảng không xác định, rỗng hoặc trống cho yo u. Sau đó, khi dữ liệu đến, NgFor được đánh giá lại.

+0

Tôi đã được mã hóa trong 20 năm và không bao giờ chạy qua các nhà điều hành Elvis cho đến bây giờ, cảm ơn mát mẻ. –

+0

@EricSoyke, giờ đây họ gọi đó là "toán tử điều hướng an toàn". –

Các vấn đề liên quan