简体   繁体   English

Angular 10/Ionic 5 - 将输入数据从模态传递到父组件,然后提交到 firebase 数据库

[英]Angular 10/Ionic 5 - Passing input data from a modal to a parent component, then submitting to a firebase database

This is a follow-up to a question I recently asked regarding passing input data from an ionic modal.这是我最近提出的关于从离子模式传递输入数据的问题的后续。 I resolved the first error, but the second error is fairing harder for me to understand.我解决了第一个错误,但第二个错误对我来说更难理解。

I am trying to make a new instance of a workspace.我正在尝试创建一个工作区的新实例。 This is done with ngFor , from a workspace in a firebase database.这是使用ngFor完成的,来自 firebase 数据库中的工作区。 There are two pages: the workspace page, and the workspace modal page, the former being the parent.有两个页面: workspace页面和workspace modal页面,前者是父页面。

When a button is pressed, the modal prompts the user to enter a title for the new workspace (there are other fields as well, but I am just trying to get the first one to work).当按下按钮时,模式提示用户输入新工作区的标题(还有其他字段,但我只是想让第一个工作)。 That data is then passed back to the home component, where a function calls a custom service method that sends it to the firebase backend.然后将该数据传递回主组件,其中 function 调用自定义服务方法,将其发送到 firebase 后端。

Here is the HTML and TS for the parent component:这是父组件的 HTML 和 TS:

<div class="workspaceGrid" style="padding-right: 30px;">
  <!-- [workspace]="workspace" passes the data down to the child component via an input property *ngFor="let workspace of workspaces" -->
  <app-workspace
    *ngFor="let workspace of workspaces"
    [workspace]="workspace"
  ></app-workspace>
  <ion-button (click)="openWorkspaceModal()">
    Open Modal
  </ion-button>
</div>
import { Component, OnInit, OnDestroy } from "@angular/core";
import { Workspace } from "../models/workspace.model";
import { Subscription } from "rxjs";
import { WorkspaceService } from "src/app/services/workspace.service";
// ADD THE MODAL
import { ModalController } from "@ionic/angular";
import { WorkspaceModalComponent } from "../modals/workspace-modal.component";

@Component({
  selector: "app-workspaces",
  templateUrl: "./workspaces.component.html",
  styleUrls: ["./workspaces.component.scss"],
})
export class WorkspacesComponent implements OnInit, OnDestroy {
  // HANDLE WORKSPACE SUBSCRIPTION
  workspaces: Workspace[];
  sub: Subscription;

  constructor(
    public workspaceService: WorkspaceService,
    public modalController: ModalController
  ) {}

  // GET ALL WORKSPACES AND POPULATE THE WORKSPACES ARRAY
  ngOnInit() {
    this.sub = this.workspaceService
      .getUserWorkspaces()
      .subscribe((workspaces) => {
        this.workspaces = workspaces;
      });
  }

  /**
   * PRESENT THE MODAL FOR CREATING A NEW WORKSPACE
   * RETURN OF AN ASYNC FUNCTION HAS TO BE A PROMISE
   */
  async openWorkspaceModal() {
    const workspaceListModal = await this.modalController.create({
      component: WorkspaceModalComponent,
      // because this is a new workspace, there is no data being passed to the modal component
      componentProps: {},
    });
    workspaceListModal.onDidDismiss().then((result) => {
      if (result) {
        this.workspaceService.createWorkspace({
          title: result,
        });
      }
    });
    return await workspaceListModal.present();
  }

  // NAVIGATE AWAY FROM THE PAGE, WE CAN UNSUBSCRIBE FROM THE WORKSPACES OBSERVABLE
  ngOnDestroy() {
    this.sub.unsubscribe();
  }
}

Here is the HTML and the TS for the modal:这是 HTML 和模态的 TS:

<ion-header color="primary" mode="ios">
  <ion-toolbar>
    <ion-title>New Workspace</ion-title>
    <ion-buttons slot="end">
      <ion-button (click)="closeWorkspaceModal()">
        <ion-icon slot="icon-only" name="close"></ion-icon>
      </ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

<ion-content padding>
  <ion-item>
    <ion-input
      placeholder="Enter a title for the workspace"
      [(ngModel)]="data.title"
    >
    </ion-input>
  </ion-item>
  <!-- HANDLE SUBMISSION OF THE CONTENT -->
  <ion-button [data]="data.title" (click)="closeWorkspaceModal()"
    >Create Workspace</ion-button
  >
</ion-content>
import { Component, Inject } from "@angular/core";
import { ModalController } from "@ionic/angular";
import { WorkspacesComponent } from "../workspaces/workspaces.component";
import { Workspace } from "../models/workspace.model";

@Component({
  selector: "app-workspace-modal",
  templateUrl: "./workspace-modal.component.html",
  styles: [],
})
export class WorkspaceModalComponent {
  public data: Workspace = {
    title: "",
    description: "",
  };

  constructor(public modalController: ModalController) {}

  /**
   * CLOSE THE MODAL ON CLICK
   */
  async closeWorkspaceModal() {
    await this.modalController.dismiss();
  }
}

Here is the interface TS, followed by the function in the service in the backend that creates a new workspace:这里是接口TS,后面是创建新工作空间的后端服务中的function:

export interface Workspace {
  id?: any;
  title?: string;
  description?: string;
  color?: "blue" | "red" | "yellow";
  priority?: number;
}
import { Injectable } from "@angular/core";
import { AngularFireAuth } from "@angular/fire/auth";
import { AngularFirestore } from "@angular/fire/firestore";
import * as firebase from "firebase/app";
import { switchMap, map } from "rxjs/operators";
import { Workspace } from "../home/models/workspace.model";

@Injectable({
  providedIn: "root",
})
export class WorkspaceService {
  constructor(private afAuth: AngularFireAuth, private db: AngularFirestore) {}

  /**
   *
   * @param data
   * CREATES A WORKSPACE IN THE DATABASE BASED ON THE CURRENTLY LOGGED IN USER
   */
  async createWorkspace(data: Workspace) {
    const user = await this.afAuth.currentUser;
    return this.db.collection("workspaces").add({
      ...data,
      // automatically sets the UID property of the workspace here
      uid: user.uid,
    });
  }
}

Here is the error that the console is giving me:这是控制台给我的错误:

ERROR Error: Uncaught (in promise): FirebaseError: [code=invalid-argument]: Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field title.data)
FirebaseError: Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field title.data)
    at new n (index.cjs.js:160)
    at t.Tc (index.cjs.js:9425)
    at index.cjs.js:9624
    at zr (index.cjs.js:9625)
    at index.cjs.js:9634
    at I (index.cjs.js:548)
    at Gr (index.cjs.js:9633)
    at zr (index.cjs.js:9535)
    at index.cjs.js:9634
    at I (index.cjs.js:548)
    at resolvePromise (zone-evergreen.js:798)
    at zone-evergreen.js:705
    at fulfilled (tslib.es6.js:71)
    at ZoneDelegate.invoke (zone-evergreen.js:364)
    at Object.onInvoke (core.js:41654)
    at ZoneDelegate.invoke (zone-evergreen.js:363)
    at Zone.run (zone-evergreen.js:123)
    at zone-evergreen.js:857
    at ZoneDelegate.invokeTask (zone-evergreen.js:399)
    at Object.onInvokeTask (core.js:41632)

My grasp on promises is growing, but they are not mature enough to debug what is happening here.我对 Promise 的把握越来越大,但它们还不够成熟,无法调试这里发生的事情。 I feel it has something to do with the interface being passed through everything.我觉得这与通过所有东西传递的接口有关。 The only reason I have it initiated in the modal ts is that angular got upset, saying that data.title was undefined, so I set it to "" right away.我在模态 ts 中启动它的唯一原因是 angular 不高兴,说data.title未定义,所以我立即将其设置为“”。 I thought passing an empty componentProps object would be enough, but apparently not.我认为传递一个空的 componentProps object 就足够了,但显然不是。

Thank you so much for any help!非常感谢您的帮助!

*** there is some code that is commented out that is not used. *** 有一些被注释掉的代码没有被使用。

If you log what data is that you pass to createWorkspace , I'm willing to bet it's undefined.如果您记录传递给createWorkspacedata ,我敢打赌它是未定义的。 You aren't returning anything from your modal in its dismiss.你没有从你的模态中返回任何东西。

See the docs for ion-modal : https://ionicframework.com/docs/api/modal#dismissing-a-modal请参阅ion-modal的文档: https://ionicframework.com/docs/api/modal#dismissing-a-modal

Your closeWorkspaceModal method should pass this.data to the modal dismiss.您的closeWorkspaceModal方法应该将this.data传递给模态解除。

async closeWorkspaceModal() {
    await this.modalController.dismiss(this.data);
  }

I think the issue is that the shape of the data received by you from your modal via onDidDismiss here:我认为问题在于您通过 onDidDismiss 从您的模态接收到的数据的形状:

    workspaceListModal.onDidDismiss().then((result) => {
      if (result) {
        this.workspaceService.createWorkspace({
          title: result,
        });
      }
    });

Results in malformed Workspace object:结果在格式错误的工作区 object 中:

{
     title: {
         data: undefined
         role: undefined
     }
}

Which you are trying to pass to Firestore (hence error related to title.data being undefined since inside you dismissed the modal with no arguments).您尝试将其传递给 Firestore(因此与 title.data 相关的错误未定义,因为您在内部取消了没有参数的模态)。

To fix this you need to make sure what modal dismisses and what then gets formed inside onDidDismiss method is a valid Workspace shape object:要解决此问题,您需要确保在 onDidDismiss 方法中消除的模式以及随后在 onDidDismiss 方法中形成的模式是有效的工作区形状 object:

First, Inside you WorkspaceModalComponent make sure you dismiss (close) modal including your data object:首先,在您的 WorkspaceModalComponent 内部确保您关闭(关闭)模式,包括您的数据 object:

  async closeWorkspaceModal() {
    await this.modalController.dismiss(this.data);
  }

Now inside the onDidDismiss method the 'result' will be of shape:现在在 onDidDismiss 方法中,“结果”将具有以下形状:

{
    data: this.data, // which is your data object
    role: undefined
}

So you need to ensure you do:所以你需要确保你这样做:

workspaceListModal.onDidDismiss().then((result) => {
  if (result && result.data) {
    this.workspaceService.createWorkspace(result.data);
  }
});

If you console.log(result.data) it should be of valid Workspace shape now and error should be resolved.如果您 console.log(result.data) 它现在应该是有效的工作区形状并且应该解决错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM