Angular

Integrate Strapi with Angular.

开始使用 Angular

本集成指南遵循 快速入门指南,并假设您已完全完成“动手”路径。您应该能够通过浏览 URL http://localhost:1337/api/restaurants 来使用该 API。

如果您尚未阅读快速入门指南,则使用 Angular 请求 Strapi API 的方式保持不变,只是您不会获取相同的内容。

创建 Angular 应用

使用 angular CLI 创建基本的 Angular 应用。

bash
npx -p @angular/cli ng new angular-app

使用 Angular HTTP 客户端

导入 Angular HttpClientModule:

./src/app/app.module.ts
ts
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HttpClientModule } from '@angular/common/http'

import { AppComponent } from './app.component'

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

GET 请求您的集合类型

restaurant 集合类型执行 GET 请求以获取您的所有餐厅。

确保您已激活 restaurant 集合类型的 find 权限。

Example GET request
ts
// this.http is the Angular HttpClient service.
this.http
  .get('http://localhost:1337/api/restaurants', {
    params: { populate: '*' },
  })
  .subscribe((response) => {
    console.log(response)
  })
Example response
json
{
  "data": [
    {
      "id": 1,
      "attributes": {
        "name": "Biscotte Restaurant",
        "description": "Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products, often local, organic when possible, and always produced by passionate producers.",
        "createdAt": "2023-03-25T11:13:41.883Z",
        "updatedAt": "2023-03-25T11:17:45.737Z",
        "publishedAt": "2023-03-25T11:17:45.735Z",
        "categories": {
          "data": [
            {
              "id": 2,
              "attributes": {
                "name": "Brunch",
                "createdAt": "2023-03-25T11:14:20.605Z",
                "updatedAt": "2023-03-25T11:17:00.158Z",
                "publishedAt": "2023-03-25T11:17:00.153Z"
              }
            }
          ]
        }
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "pageSize": 25,
      "pageCount": 1,
      "total": 1
    }
  }
}

Example

./src/app/app.component.ts
ts
import { HttpClient, HttpErrorResponse } from '@angular/common/http'
import { Component, OnInit } from '@angular/core'
import { Observable, catchError, map, of } from 'rxjs'

interface Restaurant {
  name: string
  description: string
}

interface Entry<T> {
  id: number
  attributes: T
}

interface Response {
  data: Entry<Restaurant>[]
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  error: any | undefined
  restaurants$: Observable<Restaurant[]> | undefined

  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    const url = 'http://localhost:1337/api/restaurants'
    const opts = { params: { populate: '*' } }

    this.restaurants$ = this.http.get<Response>(url, opts).pipe(
      catchError(error => this.handleError(error)),
      map(response => response.data.map(x => x.attributes))
    )
  }

  private handleError(error: HttpErrorResponse): Observable<never> {
    this.error = error
    return of()
  }
}
./src/app/app.component.html
html
<div *ngIf="error">{{error}}</div>

<ul *ngIf="restaurants$|async as restaurants">
  <li *ngFor="let restaurant of restaurants">{{restaurant.name}}</li>
</ul>

POST 请求您的集合类型

对“restaurant”集合类型执行“POST”请求以创建餐厅。

确保您已激活“restaurant”集合类型的“create”权限和“category”集合类型的“find”权限。

在此示例中,已创建“japanese”类别,其 ID 为:3。

Example POST request with axios
ts
// this.http is the Angular HttpClient service.
this.http
  .post('http://localhost:1337/api/restaurants', {
    data: {
      name: 'Dolemon Sushi',
      description:
        'Unmissable Japanese Sushi restaurant. The cheese and salmon makis are delicious',
      categories: [3],
    },
  })
  .subscribe((response) => {
    console.log(response)
  })
Response Example
json
{
  "id": 2,
  "name": "Dolemon Sushi",
  "description": "Unmissable Japanese Sushi restaurant. The cheese and salmon makis are delicious",
  "created_by": null,
  "updated_by": null,
  "created_at": "2020-08-04T09:57:11.669Z",
  "updated_at": "2020-08-04T09:57:11.669Z",
  "categories": [
    {
      "id": 3,
      "name": "Japanese",
      "created_by": 1,
      "updated_by": 1,
      "created_at": "2020-07-31T11:36:23.164Z",
      "updated_at": "2020-07-31T11:36:23.172Z"
    }
  ]
}

Example

./src/app/app.module.ts
ts
import { HttpClientModule } from '@angular/common/http'
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { BrowserModule } from '@angular/platform-browser'

import { AppComponent } from './app.component'

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, FormsModule, HttpClientModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

./src/app/app.component.ts

ts
import { Component, OnInit } from '@angular/core'
import { FormArray, FormBuilder } from '@angular/forms'
import { Observable, catchError, map, of, tap } from 'rxjs'
import { HttpClient, HttpErrorResponse } from '@angular/common/http'

interface Category {
  name: string
}

interface Entry<T> {
  id: number
  attributes: T
}

interface Response<T> {
  data: Entry<T>[]
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  allCategories$: Observable<Entry<Category>[]> | undefined
  error: any | undefined
  modifiedData = {
    name: '',
    description: '',
    categories: new Array<{ id: number, checked: boolean }>(),
  }

  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    this.allCategories$ = this.http
      .get<Response<Category>>('http://localhost:1337/api/categories')
      .pipe(
        catchError(error => this.handleError(error)),
        map(response => response.data),
        tap((data) => {
          data.forEach((x) => {
            this.modifiedData.categories.push({ id: x.id, checked: false })
          })
        })
      )
  }

  onSubmit(): void {
    const body = {
      data: {
        name: this.modifiedData.name,
        description: this.modifiedData.description,
        categories: this.modifiedData.categories
          .filter(x => x.checked)
          .map(x => x.id),
      },
    }

    this.http
      .post('http://localhost:1337/api/restaurants', body)
      .pipe(catchError(error => this.handleError(error)))
      .subscribe((response) => {
        console.log(response)
        this.resetForm()
      })
  }

  private handleError(error: HttpErrorResponse): Observable<never> {
    this.error = error.message
    return of()
  }

  private resetForm(): void {
    this.modifiedData.name = ''
    this.modifiedData.description = ''
    this.modifiedData.categories.forEach(x => (x.checked = false))
  }
}
./src/app/app.component.html
html
<div *ngIf="error">{{error}}</div>

<form (ngSubmit)="onSubmit()">
  <div>
    <label for="name"> Name </label>
    <input name="name" type="text" [(ngModel)]="modifiedData.name" />
  </div>

  <div>
    <label for="address"> Description </label>
    <input
      name="description"
      type="text"
      [(ngModel)]="modifiedData.description"
    />
  </div>

  <div *ngIf="allCategories$ | async as allCategories">
    <br />
    Select categories
    <div *ngFor="let category of allCategories; index as i">
      <label
        >{{category.attributes.name}}
        <input
          type="checkbox"
          name="category{{i}}"
          [(ngModel)]="modifiedData.categories[i].checked"
        />
      </label>
    </div>
  </div>

  <button class="button" type="submit">Create</button>
</form>

PUT 请求您的集合类型

restaurant 集合类型执行 PUT 请求,以更新餐厅的类别。

确保您已为 restaurant 集合类型激活 put 权限。

我们认为您的餐厅的 ID 为 2。 您的类别的 ID 为 2

Example PUT request
ts
// this.http is the Angular HttpClient service.
this.http
  .put('http://localhost:1337/api/restaurants/2', {
    data: {
      categories: [2],
    },
  })
  .subscribe((response) => {
    console.log(response)
  })
Example response
json
{
  "id": 2,
  "attributes": {
    "name": "Dolemon Sushi",
    "description": "Unmissable Japanese Sushi restaurant. The cheese and salmon makis are delicious",
    "created_by": null,
    "updated_by": null,
    "created_at": "2020-08-04T10:21:30.219Z",
    "updated_at": "2020-08-04T10:21:30.219Z",
    "categories": [
      {
        "id": 2,
        "name": "Brunch",
        "created_by": 1,
        "updated_by": 1,
        "created_at": "2020-08-04T10:24:26.901Z",
        "updated_at": "2020-08-04T10:24:26.911Z"
      }
    ]
  }
}