웹샵 제품 관리를 위한 CRUD 만들기
서버 없는 쇼핑몰 구축 방법 - 제3부분
이 시리즈의 이 부분에서 우리는 어떻게 우리 제품을 위해 CRUD 단점을 구축하는지 탐색할 것이다.
신제품을 만들고, 기존 제품을 업데이트하고, 삭제할 수도 있습니다.
이 시리즈의 다음 부분에서, 우리는 모든 사람이 인증을 통해 우리의 제품을 추가하거나 업데이트하거나 삭제할 수 없다는 것을 확보할 것이다.
만약 당신이 FaunaDB API로 당신의 손을 더럽힐 준비를 하고 있다면 따라오세요.
즐거운 인코딩!🚀
1. 제품 관리자
우리의 제품을 관리하기 위해서, 우리는 제품 관리 페이지가 하나 있어야 한다.
ng generate component products/components/product-admin
이 페이지에 액세스하려면 모든 제품 데이터에 액세스하는 경로를 만들어야 합니다.
import { NgModule } from '@angular/core'
import { Routes, RouterModule } from '@angular/router'
import { ProductListComponent } from './products/components/product-list/product-list.component'
import { ProductItemComponent } from './products/components/product-item/product-item.component'
import { ProductAdminComponent } from './products/components/product-admin/product-admin.component'
const routes: Routes = [
{
path: '',
component: ProductListComponent,
},
{
path: 'product/:id',
component: ProductItemComponent,
},
{
path: 'admin',
component: ProductAdminComponent,
},
]
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
이app.component.html
관리 페이지로 이동하기 위한 단추가 추가되었습니다.
<div class="toolbar" role="banner">
<h1 class="name">FaunaDB Webshop</h1>
<nav>
<button [routerLink]="['/']" mat-flat-button>Home</button>
<button [routerLink]="['/admin']" mat-flat-button>Admin</button>
</nav>
</div>
<div class="content" role="main">
<router-outlet></router-outlet>
</div>
2. 단순화 테이블
Angular나 다른 웹 응용 프로그램에서 폼을 만드는 것은 시간이 걸리는 작업입니다.양식을 쉽게 만들고 유지하기 위해 NGX Formly를 사용합니다.
If you want to check out a more detailed tutorial about all the details in NGX-Formly, check my first and second part here.
Angular CLI 를 통해 추가할 수 있습니다.이 예에서는 다음 명령에 Formly 재료 플러그인을 추가했습니다.바꿀 수 있습니다.옷감 가지다독자적으로 창립하다 또는
어떤 것they offer.
ng add @ngx-formly/schematics --ui-theme=material
이제 Angular CLI에서 Formly 모듈을응용 프로그램.단원송전 시스템. 그러나 양식에 재료 입력 구성 요소를 사용할 수 있도록 재료 모듈을 추가해야 합니다.
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { MatButtonModule } from '@angular/material/button'
import { HttpClientModule } from '@angular/common/http'
import { ProductListComponent } from './products/components/product-list/product-list.component'
import { ProductItemComponent } from './products/components/product-item/product-item.component'
import { ReactiveFormsModule } from '@angular/forms'
import { FormlyModule } from '@ngx-formly/core'
import { FormlyMaterialModule } from '@ngx-formly/material'
import { FormlyMatDatepickerModule } from '@ngx-formly/material/datepicker'
import { FormlyMatToggleModule } from '@ngx-formly/material/toggle'
import { MatDatepickerModule } from '@angular/material/datepicker'
import { MatDialogModule } from '@angular/material/dialog'
import { MatFormFieldModule } from '@angular/material/form-field'
import { MatInputModule } from '@angular/material/input'
import { MatRadioModule } from '@angular/material/radio'
import { MatSelectModule } from '@angular/material/select'
import { MatCheckboxModule } from '@angular/material/checkbox'
import { MatNativeDateModule } from '@angular/material/core'
import { ProductAdminComponent } from './products/components/product-admin/product-admin.component'
@NgModule({
declarations: [
AppComponent,
ProductListComponent,
ProductItemComponent,
ProductItemComponent,
ProductAdminComponent,
],
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
BrowserAnimationsModule,
MatButtonModule,
ReactiveFormsModule,
FormlyModule.forRoot(),
FormlyMaterialModule,
ReactiveFormsModule,
MatCheckboxModule,
MatDatepickerModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
MatRadioModule,
MatSelectModule,
MatNativeDateModule,
FormlyMatDatepickerModule,
FormlyMatToggleModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
첫 번째 표를 작성합시다.
3. 제품 개요
대부분의 관리 페이지와 마찬가지로 모든 제품의 목록을 표시하고자 합니다.모든 제품에 대해 우리는 편집 및 삭제와 같은 제품 조작 단추를 추가하고 싶습니다.
우리는 재료표를 사용할 것이다.이를 위해서는 가져오기Mattable 모듈 app.module.ts
에서.
//... all the other imported modules
import { MatTableModule } from '@angular/material/table'
@NgModule({
declarations: [//...],
imports: [
//...
MatTableModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
이제 시계를 추가할 수 있습니다제품 항목 구성 요소 및 사용 ProductService
각도
import { Component, OnInit } from ' @angular/core'
import { ProductData } from '../../models/product'
import { ProductService } from '../../service/product.service'
@Component({
selector: 'app-product-admin',
templateUrl: './ product-admin.component.html',
styleUrls: ['./product-admin.component.scss'],
})
export class ProductAdminComponent implements OnInit {
public products: ProductData[] = []
public displayedColumns: string[] = ['id', 'name', 'price', 'actions']
public dataSource = null
constructor(private productService: ProductService) {}
ngOnInit(): void {
console.log('dataSource: ', this.dataSource)
this.productService.getProducts().then((products: ProductData[]) => {
console.log(products)
this.products = products
this.dataSource = products
console.log('dataSource: ', this.dataSource)
})
}
}
... 에 있다 product-admin.component.html
우리는 오른쪽 열에 모든 데이터를 표시하기 위해 표를 추가합니다.
<header class="admin__header">
<h1>Products admin</h1>
<button mat-flat-button color="primary">New product</button>
</header>
<mat-table [dataSource]="dataSource">
<!-- ID Column -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> ID </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.id }} </mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.price }} </mat-cell>
</ng-container>
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let element">
<button [routerLink]="['/admin/product/', element.id]" mat-flat-button color="primary">Edit</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *_matRowDef="let row; columns:displayedColumns"></mat-row>
</mat-table>
우리는 스타일을 개선하기 위해 CSS를 추가할 수 있다.
:host {
width: 100%;
}
.admin {
&__header {
margin-bottom: 1rem;
}
}
3. 제품 만들기
제품을 만들거나 업데이트하기 위한 폼을 보여 주는 보기가 필요합니다.따라서 구성 요소를 생성하고 루트 모듈에 추가합니다.
ng generate component products/components/product-form
라우팅 모듈에서 라우팅을 추가했습니다.
import { NgModule } from '@angular/core'
import { Routes, RouterModule } from '@angular/router'
import { ProductListComponent } from './products/components/product-list/product-list.component'
import { ProductItemComponent } from './products/components/product-item/product-item.component'
import { ProductAdminComponent } from './products/components/product-admin/product-admin.component'
import { ProductFormComponent } from './products/components/product-form/product-form.component'
const routes: Routes = [
{
path: '',
component: ProductListComponent,
},
{
path: 'product/:id',
component: ProductItemComponent,
},
{
path: 'admin',
component: ProductAdminComponent,
},
{
path: 'admin/product/:id',
component: ProductFormComponent,
},
{
path: '**',
redirectTo: '',
},
]
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
관리 페이지를 보고 편집 버튼을 클릭하면 "http://localhost:4200/admin/product/266790280843231752” URL이 표시되지만 아직 양식이 없습니다. 따라서 제품 정보를 표시하기 위해 이 양식을 만듭니다.
URL에서 제품 ID를 가져오려면노선 활성화 ... 에서제품 창 구성 요소. ... 에 있다엥고니트 제품의 모든 데이터를 가져오려면 제품 ID가 필요합니다.그러나 우리의 예에서, 우리도 이 구성 요소를 사용한다
새 제품을 만들 때 양식을 표시합니다.
import { Component, OnInit } from '@angular/core'
import { ProductData } from '../../models/product'
import { ProductService } from '../../service/product.service'
import { ActivatedRoute } from '@angular/router'
import { FormGroup } from '@angular/forms'
import { FormlyFieldConfig } from '@ngx-formly/core'
@Component({
selector: 'app-product-form',
templateUrl: './product-form.component.html',
styleUrls: ['./product-form.component.scss'],
})
export class ProductFormComponent implements OnInit {
public id: string = ''
public productItem: ProductData = null
public productProps: string[] = []
public form = new FormGroup({})
public model = {}
public fields: FormlyFieldConfig[] = [
{
key: 'name',
type: 'input',
templateOptions: {
label: 'Name',
placeholder: 'Enter name',
required: true,
},
},
{
key: 'description',
type: 'input',
templateOptions: {
type: 'text',
label: 'Description',
placeholder: 'Enter description',
required: true,
},
},
{
key: 'price',
type: 'input',
templateOptions: {
type: 'number',
label: 'Price',
placeholder: 'Enter price',
required: true,
},
},
{
key: 'quantity',
type: 'input',
templateOptions: {
typpe: 'number',
label: 'Quantity',
placeholder: 'Enter quantity',
required: true,
},
},
{
key: 'backorderLimit',
type: 'input',
templateOptions: {
typpe: 'number',
label: 'Backorder limit',
placeholder: 'Enter backorderLimit',
required: true,
},
},
{
key: 'backordered',
type: 'checkbox',
templateOptions: {
label: 'Backordered',
placeholder: 'Enter backordered',
required: true,
},
},
]
constructor(private product: ProductService, private route: ActivatedRoute) {
this.route.params.subscribe((params) => {
this.id = params?.id
})
}
public ngOnInit(): void {
this.getProduct()
}
private getProduct() {
if (this.id !== 'new') {
this.product.getProductById(this.id).then((product) => {
this.productItem = product
})
} else {
this.productItem = new ProductData()
}
}
public onSubmit(data) {
console.log(data)
}
}
폼에 대해 우리는 NGX의 형식을 사용한다. 마치 우리가 몇 걸음 설치한 것처럼.지금 저희가 하나 만들어야 돼요.창틀 와 a영역 우리는 그 중에서 폼에 필요한 모든 필드의 그룹을 설정합니다.
NGX의 장점은 하나만 추가하면 된다는 것이다<form>
. 및 <formly>
개의 요소.... 에 있다 요소, 우리는 필드와 모델을 추가합니다.필드는formly에서 자동으로 생성됩니다.이 모델은 기존 표시
제품
<div class="form__wrapper">
<form [formGroup]="form" (ngSubmit)="onSubmit(productItem)">
<formly-form [form]="form" [fields]="fields" [model]="productItem"></formly-form>
<button mat-flat-button color="primary" type="submit" class="btn btn-default">Submit</button>
</form>
</div>
결과는 이렇다.하지만 나는 네가 스타일을 바꾸어 그것을 더욱 즐겁게 하고 싶은 사용자를 상상할 수 있다.
이제 편집 보기가 있는 전단을 준비했습니다. 새 제품과 기존 제품의 데이터를 저장할 서버 함수가 없습니다.
... 에 있다 product-service.js
나는 새로운 방법을 추가하여 신제품의 데이터를 발표했다.
createNewProduct(product) {
return new Promise((resolve, reject) => {
if (!product) {
reject('No product data provided')
}
this.client
.query(
q.Create(q.Collection('products'), {
data: product,
}),
)
.then((result) => {
resolve(result)
})
.catch((error) => {
console.log('createNewProduct', error)
reject(error)
})
})
}
서버 기능이 없는 경우 새 파일을 만들었습니다.신제품.회사 명 그러면 새로운 끝점 /product-new
이 생성됩니다.
import { ProductService } from '../lib/product-service.js'
import { client, headers } from '../lib/config.js'
const service = new ProductService({ client })
exports.handler = async (event, context) => {
console.log('Function `product-new` invoked')
const { body } = event
if (event.httpMethod === 'OPTIONS') {
return { statusCode: 200, headers, body: 'Ok' }
}
const parsedBody = JSON.parse(body)
if (!parsedBody) {
return {
statusCode: 400,
headers,
body: JSON.stringify({
message: 'Some product data is missing', parsedBody }),
}
}
if (event.httpMethod !== 'POST') {
return {
statusCode: 405, headers, body: 'Method Not Allowed' }
}
try {
const product = await
service.createNewProduct(parsedBody)
return {
statusCode: 200,
headers,
body: JSON.stringify(product),
}
} catch (error) {
console.log('error', error)
return {
statusCode: 400,
headers,
body: JSON.stringify(error),
}
}
}
}
이 함수에서 나는 주체에 제품 데이터가 있는지, 그리고 주체에 데이터가 있는지 검사한다.그렇지 않으면 오류가 반환됩니다.내 데이터를 받아들일지 안 받아들일지 테스트하기 위해서, 나는 Insomnia 로컬에서 테스트를 진행했다
Postman API 테스트에 유용한 도구이기도 합니다.
보내는 경우직책 Anguar로부터 요청이 먼저 전송됩니다.옵션 요구 사항지금 우리는 이 모든 것을 받아들이지만, 너는 반드시 이 점을 확보해야 한다.
이것은 내가 단점을 테스트하는 데 쓰는 데이터이다.
{
"name": "iPhone 12",
"description": "The newest iPhone",
"price": 1299,
"quantity": 2000,
"backorderLimit": 10,
"backordered": false,
"image": "https://images.unsplash.com/photo-1577937927133-66ef06acdf18?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=0&q=80"
}
이제 API 노드가 작동하는 것을 보았습니다. Angular 응용 프로그램에서 연결할 수 있습니다.우리가 바꾼다onSubmit 회사 방법
Angular product 서비스에서 서버가 없는 기능으로 요청을 보내는 방법을 추가했습니다.
//.... ProductService
createNewProduct(product) {
return new Promise((resolve, reject) => {
if (!product) {
reject('No product data provided')
}
this.client
.query(
q.Create(q.Collection('products'), {
data: product,
}),
)
.then((result) => {
resolve(result)
})
.catch((error) => {
console.log('createNewProduct', error)
reject(error)
})
})
}
//...
//.... ProductFormComponent
public async onSubmit(data) {
console.log(data)
const newProduct = await
this.product.createNewProduct(data)
if (newProduct) {
this.router.navigate(['/admin'])
}
}
//....
브라우저를 검사할 때 양식을 작성하고'제출'단추를 누르면 신제품을 만들 수 있습니다.생성이 완료되면
페이지를 관리합니다.
Check the Github repo for the complete code.
4. 제품 업데이트
이제 우리는 제품을 만들 수 있습니다. 우리는 그것의 정보를 업데이트하고 싶습니다.서버 없는 함수를 업데이트하는 제품을 만듭니다.제품에 변경된 필드만 보내고 모든 필드는 보내지 않아도 됩니다.
서버 기능이 없는 제품 서비스에서 업데이트 방법을 만들었습니다.기존 제품에 비해 변경된 필드를 확인하기 위해 변경되지 않은 필드를 필터링하는 방법을 만들었습니다.
import faunadb from 'faunadb'
const q = faunadb.query
export class ProductService {
// Code from previous steps ....
async updateProduct(productId, product) {
const filterdProduct = await this.filterUnChangedKeys(product)
return new Promise((resolve, reject) => {
if (!product || !filterdProduct) {
reject('No product data provided')
}
this.client
.query(q.Update(q.Ref(q.Collection('products'), productId), { data: filterdProduct }))
.then((result) => {
resolve(result)
})
.catch((error) => {
console.log('updateProduct', error)
reject(error)
})
})
}
async filterUnChangedKeys(product) {
const originalProduct = await this.getProductById(product.id)
return new Promise((resolve, reject) => {
if (!originalProduct) {
reject(originalProduct)
}
const tempProduct = {}
for (const key in product) {
const value = product[key]
if (value !== originalProduct.data[key] && key !== 'id' && key !== 'storehouse') {
tempProduct[key] = value
}
}
resolve(tempProduct)
})
}
}
디렉토리에서기능/제품 업데이트.회사 명 우리는 무서버 기능을 만들어서 그 중에서 서비스를 호출했다.
import { ProductService } from '../lib/product-service.js'
import { client, headers } from '../lib/config.js'
const service = new ProductService({ client })
exports.handler = async (event, context) => {
console.log('Function `product-update` invoked')
const { body, path } = event
const productId = path.substr(path.lastIndexOf('/') + 1)
if (event.httpMethod === 'OPTIONS') {
return { statusCode: 200, headers, body: 'Ok' }
}
const parsedBody = JSON.parse(body)
if (!parsedBody) {
return {
statusCode: 400,
headers,
body: JSON.stringify({
message: 'Some product data is missing',
parsedBody,
}),
}
}
if (event.httpMethod !== 'PUT') {
return {
statusCode: 405,
headers,
body: 'Method Not Allowed',
}
}
try {
let product = null
if (event.httpMethod === 'PUT' && productId) {
product = await service.updateProduct(productId, parsedBody)
}
return {
statusCode: 200,
headers,
body: JSON.stringify(product),
}
} catch (error) {
console.log('error', error)
return {
statusCode: 400,
headers,
body: JSON.stringify(error),
}
}
}
현재, 우리는 전면에서 같은 표를 사용하여 제품 정보를 변경할 수 있다.우리는 사용할 때 가치를 표시하기 위해 NGX Formly를 사용하여 제품 형식을 지능화합니다.제출 방법 중 신제품인지 기존 제품인지 선택해야 합니다( product-form.component.ts
).
public async onSubmit(data) {
let product = this.id === 'new' ? await
this.product.createNewProduct(data) : await
this.product.updateProduct(this.id, data)
if (product) {
this.router.navigate(['/admin'])
}
}
만약 당신이 당신의 제품을 업데이트하는 것을 테스트한다면, 그것은 반드시 작용할 것이다.
Check the Github repo for the complete code
4. 제품 삭제
물론 우리도 제품 하나를 삭제하고 싶습니다.제품을 삭제하는 데 사용할 서버 없는 함수를 만듭니다.서버 함수가 없는 서비스에서 우리는 FaunaDB API를 호출하여 제품을 삭제하는 방법을 추가했다.
async deleteProduct(productId) {
return new Promise((resolve, reject) => {
if (!productId) {
reject('No product ID provided')
}
this.client
.query(q.Delete(q.Ref(q.Collection('products'),
productId)))
.then((result) => {
resolve('OK')
})
.catch((error) => {
console.log('deleteProduct', error)
reject(error)
})
})
}
서버 기능 없음기능/제품 삭제.회사 명 이렇게 보여요.
import { ProductService } from '../lib/product-service.js'
import { client, headers } from '../lib/config.js'
const service = new ProductService({ client })
exports.handler = async (event, context) => {
console.log('Function `product-delete` invoked')
const { path } = event
const productId = path.substr(path.lastIndexOf('/') + 1)
if (event.httpMethod === 'OPTIONS') {
return { statusCode: 200, headers, body: 'Ok' }
}
if (event.httpMethod !== 'DELETE') {
return {
statusCode: 405,
headers,
body: 'Method Not Allowed',
}
}
try {
let product = null
if (event.httpMethod === 'DELETE' && productId) {
product = await service.deleteProduct(productId)
}
return {
statusCode: 200,
headers,
body: JSON.stringify(product),
}
} catch (error) {
console.log('error', error)
return {
statusCode: 400,
headers,
body: JSON.stringify(error),
}
}
}
우체부나 불면증을 통해삭제 방법 응답 주체는좋다 이 URL 사용: "http://localhost:9000/.netlify/functions/product-delete/PRODUCT_ID"
이제 관리 페이지에 삭제 기능을 추가할 수 있습니다.우리가 이전에 추가한 편집 단추가 변경될 것입니다.나는 아이콘을 추가하는 것이 사용자 체험에 있어서 더욱 명확하다고 생각한다.
덧붙이다마티공 모듈 간 app.module.ts
그것을 사용하다.
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { MatButtonModule } from '@angular/material/button'
import { HttpClientModule } from '@angular/common/http'
import { ProductListComponent } from './products/components/product-list/product-list.component'
import { ProductItemComponent } from './products/components/product-item/product-item.component'
import { ReactiveFormsModule } from '@angular/forms'
import { FormlyModule } from '@ngx-formly/core'
import { FormlyMaterialModule } from '@ngx-formly/material'
import { FormlyMatDatepickerModule } from '@ngx-formly/material/datepicker'
import { FormlyMatToggleModule } from '@ngx-formly/material/toggle'
import { MatDatepickerModule } from '@angular/material/datepicker'
import { MatDialogModule } from '@angular/material/dialog'
import { MatFormFieldModule } from '@angular/material/form-field'
import { MatInputModule } from '@angular/material/input'
import { MatRadioModule } from '@angular/material/radio'
import { MatSelectModule } from '@angular/material/select'
import { MatCheckboxModule } from '@angular/material/checkbox'
import { MatNativeDateModule } from '@angular/material/core'
import { MatTableModule } from '@angular/material/table'
// MatIconModule import
import { MatIconModule } from '@angular/material/icon'
import { ProductAdminComponent } from './products/components/product-admin/product-admin.component'
import { ProductFormComponent } from './products/components/product-form/product-form.component'
@NgModule({
declarations: [
AppComponent,
ProductListComponent,
ProductItemComponent,
ProductItemComponent,
ProductAdminComponent,
ProductFormComponent,
],
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
BrowserAnimationsModule,
MatButtonModule,
ReactiveFormsModule,
FormlyModule.forRoot(),
FormlyMaterialModule,
ReactiveFormsModule,
MatCheckboxModule,
MatDatepickerModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
MatRadioModule,
MatSelectModule,
MatTableModule,
// MatIconModule import
MatIconModule,
MatNativeDateModule,
FormlyMatDatepickerModule,
FormlyMatToggleModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
... 에 있다 product-admin.component.html
편집 버튼을 변경하고 제품 삭제 버튼을 새로 추가할 수 있습니다.
<header class="admin__header">
<h1>Products admin</h1>
<button [routerLink]="['/admin/product/new']" mat-flat-button color="secondary">New product</button>
</header>
<mat-table [dataSource]="dataSource">
<!-- ID Column -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> ID </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.id }} </mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.price }} </mat-cell>
</ng-container>
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let element">
<button
[routerLink]="['/admin/product/', element.id]"
mat-icon-button
color="primary"
aria-label="Edit product"
>
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="error" aria-label="Delete product">
<mat-icon>delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
If you get all kinds of error’s in the frontend, please restart the Angular development server, it might not have imported the MatIconModule correctly.
브라우저의 결과는 이렇다.
... 에 있다제품서비스송전 시스템 delete 서버less 함수를 호출하는 방법을 정의했습니다.
public async deleteProduct(productId: string) {
if (!productId) return
let product = null
try {
product = await this.http.delete<Product>(environment.apiUrl + 'product-delete/' + productId).toPromise()
} catch (error) {
console.error('error: ', error)
return error
}
return product
}
지금 저희가 있을 수 있어요.제품 관리자.구성 부분송전 시스템 그래서 저희가 통과할 수 있어요.
삭제 버튼을 클릭합니다.우리는 제품을 삭제한 후에 모든 새로운 데이터를 얻고 싶기 때문에, 이 모든 것을 완성할 수 있는 방법을 만들어야 한다.그래서 저희가 있을 수 있어요. ngOnInit()
및 deleteProduct()
방법
import { Component, OnInit } from '@angular/core'
import { ProductData } from '../../models/product'
import { ProductService } from '../../service/product.service'
import { Router } from '@angular/router'
@Component({
selector: 'app-product-admin',
templateUrl: './product-admin.component.html',
styleUrls: ['./product-admin.component.scss'],
})
export class ProductAdminComponent implements OnInit {
public products: ProductData[] = []
public displayedColumns: string[] = ['id', 'name', 'price', 'actions']
public dataSource = null
constructor(private productService: ProductService, private router: Router) {}
ngOnInit(): void {
console.log('dataSource: ', this.dataSource)
this.getProductData()
}
deleteProduct(productId: string): void {
this.productService
.deleteProduct(productId)
.then((result) => {
this.getProductData()
})
.catch((error) => {
console.log(error)
})
}
getProductData(): void {
this.productService.getProducts().then((products: ProductData[]) => {
console.log(products)
this.products = products
this.dataSource = products
})
}
}
... 에 있다 product-admin.component.html
우리는 삭제 단추에 클릭 처리 프로그램을 추가했다.
<header class="admin__header">
<h1>Products admin</h1>
<button [routerLink]="['/admin/product/new']" mat-flat-button color="secondary">New product</button>
</header>
<mat-table [dataSource]="dataSource">
<!-- ID Column -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> ID </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.id }} </mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.price }} </mat-cell>
</ng-container>
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let element">
<button
[routerLink]="['/admin/product/', element.id]"
mat-icon-button
color="primary"
aria-label="Edit product"
>
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="error" aria-label="Delete product" (click)="deleteProduct(element.id)">
<mat-icon>delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
브라우저에서 테스트!내 경험에 따르면 easyFaunaDB API 및
Netlify의 서버 없는 기능이 로켓처럼 빠르게 실행됨.
검사Github repo의 전체 코드
5. 안전
주의하세요, 저는 아직 안전층을 실현하지 못했습니다.따라서 나는 이 버전을 나의 테스트 환경에 배치하지 않을 것이다.다음 단계에서, 우리는 우리의 사용자를 구축할 것이다
인증
그 동안 나의 다음 단계가 발표될 때까지 모든 것을 놀았다.
제품을 만들고 편집하고 삭제하는 기능에 자부심을 가져야 한다고 생각합니다.지금까지 나는 네가 나의 관점, 즉 서버 기능이 없다는 것에 동의할 것이라고 생각한다
FaunaDB 데이터베이스는 그리 어렵지 않다.
즐거움 코드🚀
Reference
이 문제에 관하여(웹샵 제품 관리를 위한 CRUD 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/devbyrayray/create-crud-for-managing-webshop-products-4c18
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
ng generate component products/components/product-admin
import { NgModule } from '@angular/core'
import { Routes, RouterModule } from '@angular/router'
import { ProductListComponent } from './products/components/product-list/product-list.component'
import { ProductItemComponent } from './products/components/product-item/product-item.component'
import { ProductAdminComponent } from './products/components/product-admin/product-admin.component'
const routes: Routes = [
{
path: '',
component: ProductListComponent,
},
{
path: 'product/:id',
component: ProductItemComponent,
},
{
path: 'admin',
component: ProductAdminComponent,
},
]
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
<div class="toolbar" role="banner">
<h1 class="name">FaunaDB Webshop</h1>
<nav>
<button [routerLink]="['/']" mat-flat-button>Home</button>
<button [routerLink]="['/admin']" mat-flat-button>Admin</button>
</nav>
</div>
<div class="content" role="main">
<router-outlet></router-outlet>
</div>
If you want to check out a more detailed tutorial about all the details in NGX-Formly, check my first and second part here.
ng add @ngx-formly/schematics --ui-theme=material
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { MatButtonModule } from '@angular/material/button'
import { HttpClientModule } from '@angular/common/http'
import { ProductListComponent } from './products/components/product-list/product-list.component'
import { ProductItemComponent } from './products/components/product-item/product-item.component'
import { ReactiveFormsModule } from '@angular/forms'
import { FormlyModule } from '@ngx-formly/core'
import { FormlyMaterialModule } from '@ngx-formly/material'
import { FormlyMatDatepickerModule } from '@ngx-formly/material/datepicker'
import { FormlyMatToggleModule } from '@ngx-formly/material/toggle'
import { MatDatepickerModule } from '@angular/material/datepicker'
import { MatDialogModule } from '@angular/material/dialog'
import { MatFormFieldModule } from '@angular/material/form-field'
import { MatInputModule } from '@angular/material/input'
import { MatRadioModule } from '@angular/material/radio'
import { MatSelectModule } from '@angular/material/select'
import { MatCheckboxModule } from '@angular/material/checkbox'
import { MatNativeDateModule } from '@angular/material/core'
import { ProductAdminComponent } from './products/components/product-admin/product-admin.component'
@NgModule({
declarations: [
AppComponent,
ProductListComponent,
ProductItemComponent,
ProductItemComponent,
ProductAdminComponent,
],
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
BrowserAnimationsModule,
MatButtonModule,
ReactiveFormsModule,
FormlyModule.forRoot(),
FormlyMaterialModule,
ReactiveFormsModule,
MatCheckboxModule,
MatDatepickerModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
MatRadioModule,
MatSelectModule,
MatNativeDateModule,
FormlyMatDatepickerModule,
FormlyMatToggleModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
//... all the other imported modules
import { MatTableModule } from '@angular/material/table'
@NgModule({
declarations: [//...],
imports: [
//...
MatTableModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
import { Component, OnInit } from ' @angular/core'
import { ProductData } from '../../models/product'
import { ProductService } from '../../service/product.service'
@Component({
selector: 'app-product-admin',
templateUrl: './ product-admin.component.html',
styleUrls: ['./product-admin.component.scss'],
})
export class ProductAdminComponent implements OnInit {
public products: ProductData[] = []
public displayedColumns: string[] = ['id', 'name', 'price', 'actions']
public dataSource = null
constructor(private productService: ProductService) {}
ngOnInit(): void {
console.log('dataSource: ', this.dataSource)
this.productService.getProducts().then((products: ProductData[]) => {
console.log(products)
this.products = products
this.dataSource = products
console.log('dataSource: ', this.dataSource)
})
}
}
<header class="admin__header">
<h1>Products admin</h1>
<button mat-flat-button color="primary">New product</button>
</header>
<mat-table [dataSource]="dataSource">
<!-- ID Column -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> ID </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.id }} </mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.price }} </mat-cell>
</ng-container>
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let element">
<button [routerLink]="['/admin/product/', element.id]" mat-flat-button color="primary">Edit</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *_matRowDef="let row; columns:displayedColumns"></mat-row>
</mat-table>
:host {
width: 100%;
}
.admin {
&__header {
margin-bottom: 1rem;
}
}
ng generate component products/components/product-form
import { NgModule } from '@angular/core'
import { Routes, RouterModule } from '@angular/router'
import { ProductListComponent } from './products/components/product-list/product-list.component'
import { ProductItemComponent } from './products/components/product-item/product-item.component'
import { ProductAdminComponent } from './products/components/product-admin/product-admin.component'
import { ProductFormComponent } from './products/components/product-form/product-form.component'
const routes: Routes = [
{
path: '',
component: ProductListComponent,
},
{
path: 'product/:id',
component: ProductItemComponent,
},
{
path: 'admin',
component: ProductAdminComponent,
},
{
path: 'admin/product/:id',
component: ProductFormComponent,
},
{
path: '**',
redirectTo: '',
},
]
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
import { Component, OnInit } from '@angular/core'
import { ProductData } from '../../models/product'
import { ProductService } from '../../service/product.service'
import { ActivatedRoute } from '@angular/router'
import { FormGroup } from '@angular/forms'
import { FormlyFieldConfig } from '@ngx-formly/core'
@Component({
selector: 'app-product-form',
templateUrl: './product-form.component.html',
styleUrls: ['./product-form.component.scss'],
})
export class ProductFormComponent implements OnInit {
public id: string = ''
public productItem: ProductData = null
public productProps: string[] = []
public form = new FormGroup({})
public model = {}
public fields: FormlyFieldConfig[] = [
{
key: 'name',
type: 'input',
templateOptions: {
label: 'Name',
placeholder: 'Enter name',
required: true,
},
},
{
key: 'description',
type: 'input',
templateOptions: {
type: 'text',
label: 'Description',
placeholder: 'Enter description',
required: true,
},
},
{
key: 'price',
type: 'input',
templateOptions: {
type: 'number',
label: 'Price',
placeholder: 'Enter price',
required: true,
},
},
{
key: 'quantity',
type: 'input',
templateOptions: {
typpe: 'number',
label: 'Quantity',
placeholder: 'Enter quantity',
required: true,
},
},
{
key: 'backorderLimit',
type: 'input',
templateOptions: {
typpe: 'number',
label: 'Backorder limit',
placeholder: 'Enter backorderLimit',
required: true,
},
},
{
key: 'backordered',
type: 'checkbox',
templateOptions: {
label: 'Backordered',
placeholder: 'Enter backordered',
required: true,
},
},
]
constructor(private product: ProductService, private route: ActivatedRoute) {
this.route.params.subscribe((params) => {
this.id = params?.id
})
}
public ngOnInit(): void {
this.getProduct()
}
private getProduct() {
if (this.id !== 'new') {
this.product.getProductById(this.id).then((product) => {
this.productItem = product
})
} else {
this.productItem = new ProductData()
}
}
public onSubmit(data) {
console.log(data)
}
}
<div class="form__wrapper">
<form [formGroup]="form" (ngSubmit)="onSubmit(productItem)">
<formly-form [form]="form" [fields]="fields" [model]="productItem"></formly-form>
<button mat-flat-button color="primary" type="submit" class="btn btn-default">Submit</button>
</form>
</div>
createNewProduct(product) {
return new Promise((resolve, reject) => {
if (!product) {
reject('No product data provided')
}
this.client
.query(
q.Create(q.Collection('products'), {
data: product,
}),
)
.then((result) => {
resolve(result)
})
.catch((error) => {
console.log('createNewProduct', error)
reject(error)
})
})
}
import { ProductService } from '../lib/product-service.js'
import { client, headers } from '../lib/config.js'
const service = new ProductService({ client })
exports.handler = async (event, context) => {
console.log('Function `product-new` invoked')
const { body } = event
if (event.httpMethod === 'OPTIONS') {
return { statusCode: 200, headers, body: 'Ok' }
}
const parsedBody = JSON.parse(body)
if (!parsedBody) {
return {
statusCode: 400,
headers,
body: JSON.stringify({
message: 'Some product data is missing', parsedBody }),
}
}
if (event.httpMethod !== 'POST') {
return {
statusCode: 405, headers, body: 'Method Not Allowed' }
}
try {
const product = await
service.createNewProduct(parsedBody)
return {
statusCode: 200,
headers,
body: JSON.stringify(product),
}
} catch (error) {
console.log('error', error)
return {
statusCode: 400,
headers,
body: JSON.stringify(error),
}
}
}
}
{
"name": "iPhone 12",
"description": "The newest iPhone",
"price": 1299,
"quantity": 2000,
"backorderLimit": 10,
"backordered": false,
"image": "https://images.unsplash.com/photo-1577937927133-66ef06acdf18?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=0&q=80"
}
//.... ProductService
createNewProduct(product) {
return new Promise((resolve, reject) => {
if (!product) {
reject('No product data provided')
}
this.client
.query(
q.Create(q.Collection('products'), {
data: product,
}),
)
.then((result) => {
resolve(result)
})
.catch((error) => {
console.log('createNewProduct', error)
reject(error)
})
})
}
//...
//.... ProductFormComponent
public async onSubmit(data) {
console.log(data)
const newProduct = await
this.product.createNewProduct(data)
if (newProduct) {
this.router.navigate(['/admin'])
}
}
//....
Check the Github repo for the complete code.
import faunadb from 'faunadb'
const q = faunadb.query
export class ProductService {
// Code from previous steps ....
async updateProduct(productId, product) {
const filterdProduct = await this.filterUnChangedKeys(product)
return new Promise((resolve, reject) => {
if (!product || !filterdProduct) {
reject('No product data provided')
}
this.client
.query(q.Update(q.Ref(q.Collection('products'), productId), { data: filterdProduct }))
.then((result) => {
resolve(result)
})
.catch((error) => {
console.log('updateProduct', error)
reject(error)
})
})
}
async filterUnChangedKeys(product) {
const originalProduct = await this.getProductById(product.id)
return new Promise((resolve, reject) => {
if (!originalProduct) {
reject(originalProduct)
}
const tempProduct = {}
for (const key in product) {
const value = product[key]
if (value !== originalProduct.data[key] && key !== 'id' && key !== 'storehouse') {
tempProduct[key] = value
}
}
resolve(tempProduct)
})
}
}
import { ProductService } from '../lib/product-service.js'
import { client, headers } from '../lib/config.js'
const service = new ProductService({ client })
exports.handler = async (event, context) => {
console.log('Function `product-update` invoked')
const { body, path } = event
const productId = path.substr(path.lastIndexOf('/') + 1)
if (event.httpMethod === 'OPTIONS') {
return { statusCode: 200, headers, body: 'Ok' }
}
const parsedBody = JSON.parse(body)
if (!parsedBody) {
return {
statusCode: 400,
headers,
body: JSON.stringify({
message: 'Some product data is missing',
parsedBody,
}),
}
}
if (event.httpMethod !== 'PUT') {
return {
statusCode: 405,
headers,
body: 'Method Not Allowed',
}
}
try {
let product = null
if (event.httpMethod === 'PUT' && productId) {
product = await service.updateProduct(productId, parsedBody)
}
return {
statusCode: 200,
headers,
body: JSON.stringify(product),
}
} catch (error) {
console.log('error', error)
return {
statusCode: 400,
headers,
body: JSON.stringify(error),
}
}
}
public async onSubmit(data) {
let product = this.id === 'new' ? await
this.product.createNewProduct(data) : await
this.product.updateProduct(this.id, data)
if (product) {
this.router.navigate(['/admin'])
}
}
Check the Github repo for the complete code
async deleteProduct(productId) {
return new Promise((resolve, reject) => {
if (!productId) {
reject('No product ID provided')
}
this.client
.query(q.Delete(q.Ref(q.Collection('products'),
productId)))
.then((result) => {
resolve('OK')
})
.catch((error) => {
console.log('deleteProduct', error)
reject(error)
})
})
}
import { ProductService } from '../lib/product-service.js'
import { client, headers } from '../lib/config.js'
const service = new ProductService({ client })
exports.handler = async (event, context) => {
console.log('Function `product-delete` invoked')
const { path } = event
const productId = path.substr(path.lastIndexOf('/') + 1)
if (event.httpMethod === 'OPTIONS') {
return { statusCode: 200, headers, body: 'Ok' }
}
if (event.httpMethod !== 'DELETE') {
return {
statusCode: 405,
headers,
body: 'Method Not Allowed',
}
}
try {
let product = null
if (event.httpMethod === 'DELETE' && productId) {
product = await service.deleteProduct(productId)
}
return {
statusCode: 200,
headers,
body: JSON.stringify(product),
}
} catch (error) {
console.log('error', error)
return {
statusCode: 400,
headers,
body: JSON.stringify(error),
}
}
}
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { MatButtonModule } from '@angular/material/button'
import { HttpClientModule } from '@angular/common/http'
import { ProductListComponent } from './products/components/product-list/product-list.component'
import { ProductItemComponent } from './products/components/product-item/product-item.component'
import { ReactiveFormsModule } from '@angular/forms'
import { FormlyModule } from '@ngx-formly/core'
import { FormlyMaterialModule } from '@ngx-formly/material'
import { FormlyMatDatepickerModule } from '@ngx-formly/material/datepicker'
import { FormlyMatToggleModule } from '@ngx-formly/material/toggle'
import { MatDatepickerModule } from '@angular/material/datepicker'
import { MatDialogModule } from '@angular/material/dialog'
import { MatFormFieldModule } from '@angular/material/form-field'
import { MatInputModule } from '@angular/material/input'
import { MatRadioModule } from '@angular/material/radio'
import { MatSelectModule } from '@angular/material/select'
import { MatCheckboxModule } from '@angular/material/checkbox'
import { MatNativeDateModule } from '@angular/material/core'
import { MatTableModule } from '@angular/material/table'
// MatIconModule import
import { MatIconModule } from '@angular/material/icon'
import { ProductAdminComponent } from './products/components/product-admin/product-admin.component'
import { ProductFormComponent } from './products/components/product-form/product-form.component'
@NgModule({
declarations: [
AppComponent,
ProductListComponent,
ProductItemComponent,
ProductItemComponent,
ProductAdminComponent,
ProductFormComponent,
],
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
BrowserAnimationsModule,
MatButtonModule,
ReactiveFormsModule,
FormlyModule.forRoot(),
FormlyMaterialModule,
ReactiveFormsModule,
MatCheckboxModule,
MatDatepickerModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
MatRadioModule,
MatSelectModule,
MatTableModule,
// MatIconModule import
MatIconModule,
MatNativeDateModule,
FormlyMatDatepickerModule,
FormlyMatToggleModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
<header class="admin__header">
<h1>Products admin</h1>
<button [routerLink]="['/admin/product/new']" mat-flat-button color="secondary">New product</button>
</header>
<mat-table [dataSource]="dataSource">
<!-- ID Column -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> ID </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.id }} </mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.price }} </mat-cell>
</ng-container>
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let element">
<button
[routerLink]="['/admin/product/', element.id]"
mat-icon-button
color="primary"
aria-label="Edit product"
>
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="error" aria-label="Delete product">
<mat-icon>delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
If you get all kinds of error’s in the frontend, please restart the Angular development server, it might not have imported the MatIconModule correctly.
public async deleteProduct(productId: string) {
if (!productId) return
let product = null
try {
product = await this.http.delete<Product>(environment.apiUrl + 'product-delete/' + productId).toPromise()
} catch (error) {
console.error('error: ', error)
return error
}
return product
}
import { Component, OnInit } from '@angular/core'
import { ProductData } from '../../models/product'
import { ProductService } from '../../service/product.service'
import { Router } from '@angular/router'
@Component({
selector: 'app-product-admin',
templateUrl: './product-admin.component.html',
styleUrls: ['./product-admin.component.scss'],
})
export class ProductAdminComponent implements OnInit {
public products: ProductData[] = []
public displayedColumns: string[] = ['id', 'name', 'price', 'actions']
public dataSource = null
constructor(private productService: ProductService, private router: Router) {}
ngOnInit(): void {
console.log('dataSource: ', this.dataSource)
this.getProductData()
}
deleteProduct(productId: string): void {
this.productService
.deleteProduct(productId)
.then((result) => {
this.getProductData()
})
.catch((error) => {
console.log(error)
})
}
getProductData(): void {
this.productService.getProducts().then((products: ProductData[]) => {
console.log(products)
this.products = products
this.dataSource = products
})
}
}
<header class="admin__header">
<h1>Products admin</h1>
<button [routerLink]="['/admin/product/new']" mat-flat-button color="secondary">New product</button>
</header>
<mat-table [dataSource]="dataSource">
<!-- ID Column -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> ID </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.id }} </mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.price }} </mat-cell>
</ng-container>
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let element">
<button
[routerLink]="['/admin/product/', element.id]"
mat-icon-button
color="primary"
aria-label="Edit product"
>
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="error" aria-label="Delete product" (click)="deleteProduct(element.id)">
<mat-icon>delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
Reference
이 문제에 관하여(웹샵 제품 관리를 위한 CRUD 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/devbyrayray/create-crud-for-managing-webshop-products-4c18텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)