这里是 Angular 的新手。我知道以前有人问过类似的问题,我在这里读了太多关于 AJAX 和异步编程的答案,但无法解决问题。我想在单击“详细信息”按钮时查看产品的详细信息,路由完成其工作,但除了静态 html 之外,页面上看不到任何值。所以这里是:
这是我的详细信息服务,用于获取产品的具体详细信息
@Injectable()
export class DetailsService {
constructor(private http:HttpClient) { }
path = "http://localhost:3000/products";
getProductById(productId: any): Observable<Product> {
let newPath = this.path
if (productId) {
newPath += "?id=" + productId;
}
console.log(newPath);
return this.http.get<Product>(newPath).pipe(
tap(data => console.log(JSON.stringify(data) )),
catchError(this.handleError)
);
}
//handle error func here
这是详细信息组件
export class DetailsComponent implements OnInit {
title = 'Product Details'
productId: any;
product: Product;
constructor(private detailsService: DetailsService,
private activatedRoute: ActivatedRoute,
private alertifyService: AlertifyService,
) {}
ngOnInit() {
this.activatedRoute.params.subscribe(params => {
this.productId = params["id"];
console.log(this.productId);
this.detailsService.getProductById(this.productId).subscribe(data => {
this.product = data;
console.log(this.product);
console.log('38')
});
console.log(this.productId + " " + typeof this.productId);
});
}
一切正常,没有任何错误或其他问题,但属性未显示在details.component.html上;
<div *ngIf="product">
<img class="listing-photo" [src]="product.imageUrl"
alt="Exterior photo of {{product.name}}"/>
<section class="listing-description">
<h2 class="listing-heading">{{product.name}}</h2>
<p class="listing-location">{{product.description}}, {{product.price}}</p>
</section>
<section class="listing-features">
<h2 class="section-heading">About this housing location</h2>
<ul>
<li>Units available: {{product.price}}</li>
<li>Does this location have wifi: {{product.price}}</li>
<li>Does this location have laundry: {{product.price}}</li>
</ul>
</section>
</div>
调用是从product.component.html进行的
//snippet with ngFor etc
<div class="card-footer">
<a (click)="addToCart(product)" class="btn btn-primary text-white">Add to cart</a>
<a [routerLink]="['/products',product.id]" class="btn btn-secondary ml-3 ">Details</a>
</div>
//the rest
我尝试了一百种方法,如果有两百种的话,我现在迷失了。我了解异步编程的本质,但无法让它按预期工作。
我看到路由未接收的问题 由于异步调用,视图发生变化, 所以这里有一个例子。
我使用了官方文档和jsonplaceholder作为Api。
这里还有 stackblitz 示例:demo
main.ts
只是样板:
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { TodoDetailComponent, TodoListComponent } from './todos.service';
import { provideHttpClient } from '@angular/common/http';
import {
RouterModule,
Routes,
provideRouter,
RouterLink,
RouterOutlet,
RouterLinkActive,
} from '@angular/router';
import { CommonModule } from '@angular/common';
import {} from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>Example!</h1>
<app-todo-list></app-todo-list>
<router-outlet></router-outlet>
`,
imports: [
CommonModule,
RouterLink,
RouterOutlet,
RouterLinkActive,
TodoListComponent,
],
})
export class App {
name = 'Angular';
}
const appRoutes: Routes = [
{ path: 'todo/:id', component: TodoDetailComponent },
];
bootstrapApplication(App, {
providers: [provideRouter(appRoutes), provideHttpClient()],
});
服务、组件
import { AsyncPipe, CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, Injectable, OnInit, inject } from '@angular/core';
import {
ActivatedRoute,
RouterLink,
RouterLinkActive,
RouterOutlet,
} from '@angular/router';
import { Observable, switchMap } from 'rxjs';
// Interface to manage object
export interface Todo {
userId: number;
id: number;
title: string;
complete: boolean;
}
// Service to handle data
@Injectable()
export class TodosService {
private BASE_URL: string = 'https://jsonplaceholder.typicode.com/todos';
constructor(private http: HttpClient) {}
getTodos() {
return this.http.get(`${this.BASE_URL}`);
}
getTodoById(id: string): Observable<Todo> {
return this.http.get<Todo>(`${this.BASE_URL}/${id}`);
}
}
//Full list of todo items
@Component({
standalone: true,
selector: 'app-todo-list',
template: `
<ul>
@for(todo of todos; track todo.id){
<li>
<a [routerLink]="['todo',todo.id]" routerLinkActive="active">
{{todo.title}}
</a>
</li>
} @empty {
<li>No items.</li>
}
</ul>
`,
providers: [TodosService],
imports: [RouterLink, RouterLinkActive],
})
export class TodoListComponent implements OnInit {
private _todos: Todo[] = [];
private todoService: TodosService = inject(TodosService);
ngOnInit() {
this.todoService.getTodos().subscribe({
next: (response: any) => {
this.todos = response.slice(0, 4);
},
error: (error: any) => {
console.error(error);
},
});
}
get todos() {
return this._todos;
}
set todos(todos: Todo[]) {
this._todos = todos;
}
}
/**
* Detail of todo item passed by route param.
* @see https://angular.dev/guide/routing/common-router-tasks#accessing-query-parameters-and-fragments
*/
@Component({
standalone: true,
selector: 'app-todo-detail',
template: `
<a [routerLink]="['/']">Back</a>
<h2>Todo detail</h2>
@if( todo$ | async; as todoItem) {
{{todoItem.id}}
{{todoItem.title}}
{{todoItem.complete}}
}
`,
imports: [
CommonModule,
RouterLink,
RouterOutlet,
RouterLinkActive,
AsyncPipe,
],
providers: [TodosService],
})
export class TodoDetailComponent {
todo$!: Observable<Todo>;
constructor(
private route: ActivatedRoute,
private todoService: TodosService
) {}
ngOnInit() {
this.todo$ = this.route.paramMap.pipe(
switchMap((params) => {
let todoId = params.get('id');
return this.todoService.getTodoById('' + todoId);
})
);
}
}