【问题标题】:Cannot read properties of null (reading 'id')无法读取 null 的属性(读取“id”)
【发布时间】:2022-02-09 02:55:07
【问题描述】:

我正在尝试使用表单将数据发送到 MySQL 数据库中的表。 单击创建按钮时,我仅在 chrome 开发控制台中收到此 error

我已经通过结合 Jason Watmore 的前端和后端代码来配置这个应用程序,并使用 VS 代码终端命令将项目更新到 Angular 版本 11。 https://jasonwatmore.com/post/2020/08/29/angular-10-boilerplate-email-sign-up-with-verification-authentication-forgot-password

https://jasonwatmore.com/post/2020/09/08/nodejs-mysql-boilerplate-api-with-email-sign-up-verification-authentication-forgot-password

项目的所有其他方面都按预期工作,因为我没有编辑它们。 (注册、验证、登录、从其他 MySQL 表更新配置文件数据等)

我的数据库表被称为“实验室交换”,这些 properties

非常感谢任何帮助或指导,我希望这个问题包含足够的细节。 感谢您的阅读。

前端代码

home.component.html:

<div class="p-4">
    <div class="container">
        <h1>Welcome {{account.firstName}}!</h1>
        <h2>You can create a lab swap request here!</h2>
        <!-- <p></p> -->
    </div>
</div>

<form [formGroup]="labSwapForm" (ngSubmit)="onSubmit()">
    <div class="form-group col-4">
        <label>Your Full Name</label>
        <input type="text" formControlName="swapCandidateOne" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.swapCandidateOne.errors }" />
        <div *ngIf="submitted && f.swapCandidateOne.errors" class="invalid-feedback">
            <div *ngIf="f.swapCandidateOne.errors.required">Full Name is required</div>
        </div>
    </div>

    <div class="form-group col-4">
        <label>Lab Swap Request Details</label>
        <input type="text" formControlName="swapRequestDetail" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.swapRequestDetail.errors }" />
        <div *ngIf="submitted && f.swapRequestDetail.errors" class="invalid-feedback">
            <div *ngIf="f.swapRequestDetail.errors.required">Lab Swap Details are required</div>
        </div>
    </div>

    <div class="form-group">
        <button type="submit" [disabled]="loading" class="btn btn-primary mr-2 mb-3 ml-3">
            <span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span>
            Create Lab Swap Request
        </button>
    </div>
</form>

home.component.ts:

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { AccountService, AlertService, LabSwapService } from '@app/_services';
import { first } from 'rxjs/operators';


@Component({ templateUrl: 'home.component.html' })
export class HomeComponent {
    account = this.accountService.accountValue;
    labSwap = this.labSwapService.labSwapValue;
    loading = false;
    submitted = false;
    labSwapForm: FormGroup;

    constructor(
        private accountService: AccountService,
        private labSwapService: LabSwapService,
        private formBuilder: FormBuilder,
        private router: Router,
        private alertService: AlertService,
        private route: ActivatedRoute,
    ) { }

    ngOnInit() {
        this.labSwapForm = this.formBuilder.group({
            //id: this.formBuilder.control(null, Validators.required),
            swapCandidateOne: this.formBuilder.control(null),
            swapRequestDetail: this.formBuilder.control(null)
            // swapCandidateOne: [this.labSwap.swapCandidateOne, Validators.required],
            // swapRequestDetail: [this.labSwap.swapRequestDetail, Validators.required],
        });
    }

    get f() { 
        return this.labSwapForm.controls; 
    }

    onSubmit() {
        debugger;

        // reset alerts on submit
        //this.alertService.clear();

        // stop here if form is invalid
        if (this.labSwapForm.invalid) {
            return;
        }

        this.loading = true;
        this.labSwapService.update(this.labSwap.id, this.labSwapForm.value) //id is the issue here!
            .pipe(first())
            .subscribe({
                next: () => {
                    this.alertService.success('Lab Swap Created successfully', { keepAfterRouteChange: true });
                    this.router.navigate(['../'], { relativeTo: this.route });
                },
                error: error => {
                    this.alertService.error(error);
                    this.loading = false;
                }
            });
        debugger;
    }
}

labSwap.ts(模型):

export class LabSwap {
    id: number;
    fullNameList: string;
    swapRequestDetail: string;
    swapCandidateOne: string;
    swapCandidateTwo: string;
    isSwapComplete: boolean;
    
}

实验室交换服务.ts:

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map, finalize } from 'rxjs/operators';

import { environment } from '@environments/environment';
import { LabSwap } from '@app/_models';

//const baseUrl = `${environment.apiUrl}/accounts`;
const baseUrl = `${environment.apiUrl}/lab-swap`;
//const baseUrl = `${environment.apiUrl}/home`;

@Injectable({ providedIn: 'root' })
export class LabSwapService {
    private labSwapSubject: BehaviorSubject<LabSwap>;
    public labSwap: Observable<LabSwap>;

    constructor(
        private router: Router,
        private http: HttpClient
    ) {
        this.labSwapSubject = new BehaviorSubject<LabSwap>(null);
        this.labSwap = this.labSwapSubject.asObservable();
    }

    public get labSwapValue(): LabSwap {
        return this.labSwapSubject.value;
    }

    logout() {
        this.http.post<any>(`${baseUrl}/revoke-token`, {}, { withCredentials: true }).subscribe();
        this.stopRefreshTokenTimer();
        this.labSwapSubject.next(null);
        this.router.navigate(['/account/login']);
    }


    getAll() {
        return this.http.get<LabSwap[]>(baseUrl);
    }

    getById(id: string) {
        return this.http.get<LabSwap>(`${baseUrl}/${id}`);
    }
    
    create(params) {
        return this.http.post(baseUrl, params);
    }
    
    update(id, params) {
        return this.http.put(`${baseUrl}/${id}`, params)
            .pipe(map((labSwap: any) => {
                // update the current lab swap if it was updated
                if (labSwap.id === this.labSwapValue.id) {
                    // publish updated lab swap to subscribers
                    labSwap = { ...this.labSwapValue, ...labSwap };
                    this.labSwapSubject.next(labSwap);
                }
                return labSwap;
            }));
    }

}

后端代码

lab-swap.controller.js:

const express = require('express');
const router = express.Router();
const Joi = require('joi');
const validateRequest = require('_middleware/validate-request');
const authorize = require('_middleware/authorize')
const Role = require('_helpers/role');
const accountService = require('./account.service');
const labSwapService = require('./lab-swap.service')

// routes
router.post('/revoke-token', authorize(), revokeTokenSchema, revokeToken);
router.post('/register', labSwapSchema);
router.get('/', authorize(Role.Admin), getAllLabSwaps);
router.get('/:id', authorize(), getLabSwapById);
router.post('/', authorize(Role.Admin), createLabSwapSchema, create);
router.put('/:id', authorize(), updateLabSwapSchema, update);
router.delete('/:id', authorize(), _delete);

module.exports = router;


function labSwapSchema(req, res, next) {
    const schema = Joi.object({
        //fullNameList: Joi.string().required(),
        swapRequestDetail: Joi.string().required(),
        swapCandidateOne: Joi.string().required(),
        swapCandidateTwo: Joi.string().required(),
        isSwapComplete: Joi.boolean().valid(false).required()
    });
    validateRequest(req, next, schema);
}

function getAllLabSwaps(req, res, next) {
    labSwapService.getAllLabSwaps()
        .then(labSwaps => res.json(labSwaps))
        .catch(next);
}

function getLabSwapById(req, res, next) {
    // users can get their own account and admins can get any account
    if (Number(req.params.id) !== req.user.id && req.user.role !== Role.Admin) {
        return res.status(401).json({ message: 'Unauthorized' });
    }

    labSwapService.getLabSwapById(req.params.id)
        .then(labSwap => labSwap ? res.json(labSwap) : res.sendStatus(404))
        .catch(next);
}


function createLabSwapSchema(req, res, next) {
    const schema = Joi.object({
        fullNameList: Joi.string().required(),
        swapCandidateOne: Joi.string().required(),
        swapCandidateTwo: Joi.string().required(),
        swapRequestDetail: Joi.string().email().required(),
        isSwapComplete: Joi.boolean().valid(false).required()
    });
    validateRequest(req, next, schema);
}

function create(req, res, next) {
    labSwapService.create(req.body)
        .then(labSwap => res.json(labSwap))
        .catch(next);
}

function updateLabSwapSchema(req, res, next) {
    const schemaRules = {
        swapRequestDetail: Joi.string().empty(''),
        swapCandidateOne: Joi.string().empty(''),
        swapCandidateTwo: Joi.string().empty(''),
        isSwapComplete: Joi.boolean().empty(''),
    };

function update(req, res, next) {
    // users can update their own account and admins can update any account
    if (Number(req.params.id) !== req.user.id && req.user.role !== Role.Admin) {
        return res.status(401).json({ message: 'Unauthorized' });
    }

    labSwapService.update(req.params.id, req.body)
        .then(labSwap => res.json(labSwap))
        .catch(next);
}

实验室交换服务.js:

const db = require('_helpers/db');

module.exports = {
    getAllLabSwaps,
    getById,
    create,
    update,
    delete: _delete
};

async function getAllLabSwaps() {
    const labSwaps = await db.LabSwap.findAll();
    return labSwaps.map(x => basicDetails(x));
}

async function getById(id) {
    const labSwap = await getLabSwap(id);
    return basicDetails(labSwap);
}

async function create(params) {

    const labSwap = new db.LabSwap(params);
    labSwap.verified = Date.now();

    // save labSwap table
    await labSwap.save();

    return basicDetails(labSwap);
}

async function update(id, params) {
    const labSwap = await getLabSwap(id);

    // copy params to Lab Swap and save
    Object.assign(labSwap, params);
    labSwap.updated = Date.now();
    await labSwap.save();

    return basicDetails(labSwap);
}

async function _delete(id) {
    const labSwap = await getLabSwap(id);
    await labSwap.destroy();
}


// helper functions

async function getLabSwap(id) {
    const labSwap = await db.LabSwap.findByPk(id);
    if (!labSwap) throw 'Lab Swap not found';
    return labSwap;
}

function basicDetails(labSwap) {
    const { id, title, firstName, lastName, email, role, created, updated, isVerified } = labSwap;
    return { id, title, firstName, lastName, email, role, created, updated, isVerified };
}

实验室交换模型.js:

const { DataTypes } = require('sequelize');

module.exports = model;

function model(sequelize) {
    const attributes = {
        fullNameList: { type: DataTypes.STRING, allowNull: true },
        swapRequestDetail: { type: DataTypes.STRING, allowNull: true },
        swapCandidateOne: { type: DataTypes.STRING, allowNull: true },
        swapCandidateTwo: { type: DataTypes.STRING, allowNull: true },
        isSwapComplete: { type: DataTypes.BOOLEAN },
        //firstName: { type: DataTypes.STRING, allowNull: false },
        //lastName: { type: DataTypes.STRING, allowNull: false },
        created: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW },
        updated: { type: DataTypes.DATE },

    };

    const options = {
        // disable default timestamp fields (createdAt and updatedAt)
        timestamps: false,     
    };

    return sequelize.define('lab-swap', attributes, options);
}

【问题讨论】:

    标签: html mysql node.js angular typescript


    【解决方案1】:
    this.labSwap = this.labSwapSubject.asObservable();
    

    labSwap 是一个可观察的。您无法通过执行“this.labSwap.id”获得 id。 可以这样搞定

    let id = "";
    this.labSwap.pipe(take(1)).subscribe((data)=>{id = data.id});
    
    this.labSwapService.update(id, this.labSwapForm.value);
    

    【讨论】:

    • 感谢您的回答!我必须在前端的 lab-swap.service.ts 中将您的代码实现到当前函数中以解决问题吗?再次感谢您。
    • 是的。可以自行搜索如何从 observable 中获取数据
    • 再次感谢您。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 2022-01-12
    • 2021-12-04
    相关资源
    最近更新 更多