Как заставить Angular загружать данные перед загрузкой модуля? - PullRequest
1 голос
/ 07 мая 2020

Итак, я новичок в angular ... Этот код здесь:

  ngOnInit(): void {
    this.getProduct();
  }

  getProduct(): void {
    const id = +this.route.snapshot.paramMap.get('id');
    this.product = this.products.getProduct(id);
    console.log(this.product);
  }

Итак, когда эта вещь открывается в первый раз, я получаю "TypeError: Cannot read property 'sr c' of undefined «И этот console.log показывает« undefined », но когда я нажимаю кнопку« Домой »в приложении, а затем нажимаю то же самое, он работает правильно ... Регистрирует нужный элемент и отображает правильное изображение

public getProduct(id: number): Product {
   // console.log('returning product');
   return (this.products.find(product => product.id === id));
 }

модуль, который возвращает список продуктов, которые ранее были загружены из файла. json

  constructor( private http: HttpClient ) {
    this.getJSON().subscribe(data => {
      this.products = data.products;
     });
  }

Этот модуль используется для создания сетки продуктов, чтобы избежать загрузки. json дважды I просто импортировал его и использовал повторно.

Итак, если кто-нибудь может объяснить, почему он не работает в первый раз после загрузки страницы (конечно, с помощью ng serve) и почему он работает каждый раз после этого, я ' d действительно люблю тебя.

Редактировать, вот шаблон и весь component.ts согласно запросу:

<div>
<img src="{{product.src}}" alt="">
</div>
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';

import { Product } from '../classes/product.interface';
import { ShoppingGridComponent } from '../shopping-grid/shopping-grid.component';

@Component({
  selector: 'app-product',
  templateUrl: './product.component.html',
  styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
  product: Product;
  constructor(
    private route: ActivatedRoute,
    private location: Location,
    private products: ShoppingGridComponent
  ) {}
  ngOnInit(): void {
    this.getProduct();
  }

  getProduct(): void {
    const id = +this.route.snapshot.paramMap.get('id');
    console.log(id);
    this.product = this.products.getProduct(id);
    console.log(this.product);
  }
}

Ответы [ 4 ]

1 голос
/ 07 мая 2020

Вот для чего используются Резольверы . Он позволяет вам предварительно загружать данные до инициализации компонента.

Вот пример преобразователя:

@Injectable({ providedIn: 'root' })
export class ProductsResolver implements Resolve<Product> {
  constructor(private http: HttpService) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<any>|Promise<any>|any {
    return this.http.get('api/v1/products/' + route.paramMap.get('id'));
  }
}

Затем вы применяете его к своим маршрутам:

const routes = [
    {
        path: 'products/:id'
        component: ProductComponent,
        resolve: {
            product: ProductsResolver
            //you can add more resolvers here too!
        }
    }
]

Наконец, вы можете получить доступ к данным в вашем компоненте:

constructor(private route: ActivatedRoute) {}

ngOnInit() {
  this.product = this.route.snapshot.data.product;
}
0 голосов
/ 07 мая 2020

Когда речь идет о подписке, следует отметить, что задействованы асинхронные данные. Вы можете прочитать о них подробнее здесь .

По сути, данные не возвращаются сразу, как обычная функция. Вы подписываетесь на получение данных. Но в конечном итоге наблюдаемое определяет, когда вы его получите.

Здесь функции getProduct() предполагают, что переменная this.products уже определена, но это может быть не так.

Я предполагаю, что вы подписавшись на наблюдаемое в сервисе. Советую подписаться на компонент.

Итак, в этом случае вы можете переместить все, включая подписку, в ловушку OnInit и удалить подписку из службы. Попробуйте следующее

Компонент

products: Product[] = [];

ngOnInit(): void {
  this.getJSON().subscribe(data => {
    this.products = data.products;

    this.getProduct();
  });
}

getProduct(): void {
  const id = +this.route.snapshot.paramMap.get('id');
  this.product = this.products.getProduct(id);
  console.log(this.product);
}
0 голосов
/ 07 мая 2020

Вы можете использовать резольверы для решения этой проблемы. Вот как вы это делаете - https://codeburst.io/understanding-resolvers-in-angular-736e9db71267

0 голосов
/ 07 мая 2020

Используйте дополнительный оператор цепочки («вопросительный знак») в шаблоне:

<div>
  <img src="{{product?.src}}" alt="">
</div>

Часто называется «оператором элвиса», он позволит избежать ошибок, если product равно null или undefined.

Конечно, я предполагаю, что со временем product будет иметь какое-то значение. Это полезно, когда, например, вы go в базу данных, чтобы получить свой продукт, и, пока это происходит, product равно undefined.

[ОБНОВЛЕНИЕ]: С учетом последних обновлений, внесенных в вопрос:

ngOnInit() {
  this.getJSON().pipe(map(data => data.products)).subscribe(products => {
    this.products = products;
    this.product = this.products.find(product => product.id === id);
  });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...