developer tip

뷰 / 템플릿을 렌더링하기 전에 Angular 2가 모델을로드 / 해결할 때까지 기다립니다.

copycodes 2020. 11. 1. 18:16
반응형

뷰 / 템플릿을 렌더링하기 전에 Angular 2가 모델을로드 / 해결할 때까지 기다립니다.


Angular 1.x에서는 UI-Router가이를위한 주요 도구였습니다. "resolve"값에 대한 약속을 반환함으로써 라우터는 지시문을 렌더링하기 전에 약속이 완료되기를 기다릴 것입니다.

또는 Angular 1.x에서 null 개체는 템플릿을 충돌시키지 않습니다. 따라서 일시적으로 불완전한 렌더링이 마음에 들지 않으면 처음에 비어있는 모델 개체를 채운 $digest후 렌더링 하는 사용할 수 있습니다 promise.then().

두 가지 접근 방식 중 가능한 경우보기를로드 할 때까지 기다렸다가 리소스를로드 할 수없는 경우 경로 탐색을 취소하는 것을 선호합니다. 이렇게하면 "탐색 해제"작업이 절약됩니다. 편집 :이 질문은 특히이 질문이 Angular 2 Futures 호환 또는 모범 사례 방법을 요청하고 가능하면 "Elvis 연산자"를 피하도록 요청한다는 것을 의미합니다! 따라서 나는 그 답을 선택하지 않았습니다.

그러나이 두 가지 방법 중 어느 것도 Angular 2.0에서 작동하지 않습니다. 확실히이를 위해 계획되거나 사용 가능한 표준 솔루션이 있습니다. 누구든지 그것이 무엇인지 알고 있습니까?

@Component() {
    template: '{{cats.captchans.funniest}}'
}
export class CatsComponent {

    public cats: CatsModel;

    ngOnInit () {
        this._http.get('/api/v1/cats').subscribe(response => cats = response.json());
    }
}

다음 질문은 동일한 문제를 반영 할 수 있습니다 . 데이터가있는 PROMISE가로드 된 후 Angular 2 렌더링 템플릿 . 질문에는 코드가 없거나 답변이 허용되지 않습니다.


패키지 @angular/router에는 Resolve경로에 대한 속성이 있습니다. 따라서 경로보기를 렌더링하기 전에 데이터를 쉽게 해결할 수 있습니다.

참조 : https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html

2017 년 8 월 28 일 현재 문서의 예 :

class Backend {
  fetchTeam(id: string) {
    return 'someTeam';
  }
}

@Injectable()
class TeamResolver implements Resolve<Team> {
  constructor(private backend: Backend) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<any>|Promise<any>|any {
    return this.backend.fetchTeam(route.params.id);
  }
}

@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'team/:id',
        component: TeamCmp,
        resolve: {
          team: TeamResolver
        }
      }
    ])
  ],
  providers: [TeamResolver]
})
class AppModule {}

이제 데이터가 확인되고 반환 될 때까지 경로가 활성화되지 않습니다.

구성 요소에서 확인 된 데이터에 액세스

런타임에 구성 요소 내에서 확인 된 데이터에 액세스하려면 두 가지 방법이 있습니다. 따라서 필요에 따라 다음 중 하나를 사용할 수 있습니다.

  1. route.snapshot.paramMap 문자열을 반환하거나
  2. route.paramMap가능한 Observable을 반환합니다 .subscribe().

예:

  // the no-observable method
  this.dataYouResolved= this.route.snapshot.paramMap.get('id');
  // console.debug(this.licenseNumber);

  // or the observable method
  this.route.paramMap
     .subscribe((params: ParamMap) => {
        // console.log(params);
        this.dataYouResolved= params.get('id');
        return params.get('dataYouResolved');
        // return null
     });
  console.debug(this.dataYouResolved);

도움이 되었기를 바랍니다.


보십시오 {{model?.person.name}}이하지에 모델 기다려야 undefined하고 렌더링합니다.

Angular 2는이 ?.구문을 Elvis 연산자라고 합니다. 문서에서 참조하기는 어렵 기 때문에 변경 / 이동할 경우에 대비 한 사본이 있습니다.

Elvis 연산자 (?.) 및 null 속성 경로

Angular“Elvis”연산자 (?.)는 속성 경로에서 null 및 정의되지 않은 값을 방지하는 유창하고 편리한 방법입니다. 여기에서 currentHero가 null 인 경우 뷰 렌더링 실패로부터 보호합니다.

The current hero's name is {{currentHero?.firstName}}

문제와이 특정 솔루션에 대해 자세히 설명하겠습니다.

다음 데이터 바인딩 된 제목 속성이 null이면 어떻게됩니까?

The title is {{ title }}

뷰는 여전히 렌더링되지만 표시된 값은 비어 있습니다. 뒤에 아무것도없는 "제목은"만 표시됩니다. 그것은 합리적인 행동입니다. 적어도 앱은 충돌하지 않습니다.

Suppose the template expression involves a property path as in this next example where we’re displaying the firstName of a null hero.

The null hero's name is {{nullHero.firstName}}

JavaScript throws a null reference error and so does Angular:

TypeError: Cannot read property 'firstName' of null in [null]

Worse, the entire view disappears.

We could claim that this is reasonable behavior if we believed that the hero property must never be null. If it must never be null and yet it is null, we've made a programming error that should be caught and fixed. Throwing an exception is the right thing to do.

On the other hand, null values in the property path may be OK from time to time, especially when we know the data will arrive eventually.

While we wait for data, the view should render without complaint and the null property path should display as blank just as the title property does.

Unfortunately, our app crashes when the currentHero is null.

We could code around that problem with NgIf

<!--No hero, div not displayed, no error --> <div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>

Or we could try to chain parts of the property path with &&, knowing that the expression bails out when it encounters the first null.

The null hero's name is {{nullHero && nullHero.firstName}}

These approaches have merit but they can be cumbersome, especially if the property path is long. Imagine guarding against a null somewhere in a long property path such as a.b.c.d.

The Angular “Elvis” operator ( ?. ) is a more fluent and convenient way to guard against nulls in property paths. The expression bails out when it hits the first null value. The display is blank but the app keeps rolling and there are no errors.

<!-- No hero, no problem! --> The null hero's name is {{nullHero?.firstName}}

It works perfectly with long property paths too:

a?.b?.c?.d


EDIT: The angular team has released the @Resolve decorator. It still needs some clarification, in how it works, but until then I'll take someone else's related answer here, and provide links to other sources:


EDIT: This answer works for Angular 2 BETA only. Router is not released for Angular 2 RC as of this edit. Instead, when using Angular 2 RC, replace references to router with router-deprecated to continue using the beta router.

The Angular2-future way to implement this will be via the @Resolve decorator. Until then, the closest facsimile is CanActivate Component decorator, per Brandon Roberts. see https://github.com/angular/angular/issues/6611

Although beta 0 doesn't support providing resolved values to the Component, it's planned, and there is also a workaround described here: Using Resolve In Angular2 Routes

A beta 1 example can be found here: http://run.plnkr.co/BAqA98lphi4rQZAd/#/resolved . It uses a very similar workaround, but slightly more accurately uses the RouteData object rather than RouteParams.

@CanActivate((to) => {
    return new Promise((resolve) => {
        to.routeData.data.user = { name: 'John' }

Also, note that there is also an example workaround for accessing nested/parent route "resolved" values as well, and other features you expect if you've used 1.x UI-Router.

Note you'll also need to manually inject any services you need to accomplish this, since the Angular Injector hierarchy is not currently available in the CanActivate decorator. Simply importing an Injector will create a new injector instance, without access to the providers from bootstrap(), so you'll probably want to store an application-wide copy of the bootstrapped injector. Brandon's second Plunk link on this page is a good starting point: https://github.com/angular/angular/issues/4112


Set a local value with the observer

...also, don't forget to initialize the value with dummy data to avoid uninitialized errors.

export class ModelService {
    constructor() {
      this.mode = new Model();

      this._http.get('/api/v1/cats')
      .map(res => res.json())
      .subscribe(
        json => {
          this.model = new Model(json);
        },
        error => console.log(error);
      );
    }
}

This assumes Model, is a data model representing the structure of your data.

Model with no parameters should create a new instance with all values initialized (but empty). That way, if the template renders before the data is received it won't throw an error.

Ideally, if you want to persist the data to avoid unnecessary http requests you should put this in an object that has its own observer that you can subscribe to.


Implement the routerOnActivate in your @Component and return your promise:

https://angular.io/docs/ts/latest/api/router/OnActivate-interface.html

EDIT: This explicitly does NOT work, although the current documentation can be a little hard to interpret on this topic. See Brandon's first comment here for more information: https://github.com/angular/angular/issues/6611

EDIT: The related information on the otherwise-usually-accurate Auth0 site is not correct: https://auth0.com/blog/2016/01/25/angular-2-series-part-4-component-router-in-depth/

EDIT: The angular team is planning a @Resolve decorator for this purpose.


A nice solution that I've found is to do on UI something like:

<div *ngIf="vendorServicePricing && quantityPricing && service">
 ...Your page...
</div

Only when: vendorServicePricing, quantityPricing and service are loaded the page is rendered.

참고URL : https://stackoverflow.com/questions/34731869/wait-for-angular-2-to-load-resolve-model-before-rendering-view-template

반응형