ERROR TypeError: _co.saveXML is not a function

ERROR TypeError: _co.saveXML is not a function

在我的客户 Angular 项目中,我有一个名为 report-viewer 的组件。我在里面有一个表单,EmailSettings,当按下组件的按钮时调用它。

表单代码如下:

EmailSettings.html

<h1 mat-dialog-title>Email Settings</h1>
<div mat-dialog-content>
    <form id="formID" class="example-form">
        <mat-form-field *ngIf="data.smtpHost === ''" class="example-full-width" appearance="fill">
            <mat-label>SMTP Host</mat-label>
            <textarea matInput placeholder="Ex: smtp.gmail.com"></textarea>
        </mat-form-field> <br>
        <mat-form-field *ngIf="data.smtpPort === ''" class="example-full-width" appearance="fill">
            <mat-label>SMTP Port</mat-label>
            <textarea matInput placeholder="Ex: 587"></textarea>
        </mat-form-field> <br>
        <mat-form-field *ngIf="data.smtpUserName === ''" class="example-full-width" appearance="fill">
            <mat-label>SMTP User Name</mat-label>
            <textarea matInput placeholder="Ex: example@gmail.com"></textarea>
        </mat-form-field> <br>
        <mat-form-field *ngIf="data.smtpUserPassword === ''" class="example-full-width" appearance="fill">
            <mat-label>SMTP User Password</mat-label>
            <textarea matInput placeholder="Ex: password"></textarea>
        </mat-form-field> <br>
        <mat-form-field *ngIf="data.smtpFrom === ''" class="example-full-width" appearance="fill">
            <mat-label>SMTP From</mat-label>
            <textarea matInput placeholder="Ex: example@gmail.com"></textarea>
        </mat-form-field> <br>
        <mat-form-field *ngIf="data.smtpDisplayName === ''" class="example-full-width" appearance="fill">
            <mat-label>SMTP Display Name</mat-label>
            <textarea matInput placeholder="Ex: Jhon"></textarea>
        </mat-form-field> <br>
        <button mat-button (click)="saveXML()">Save</button>
     <!--    <mat-form-field class="example-full-width" appearance="fill">
            <button mat-button (click)="saveXML()">Save</button>
        </mat-form-field> -->
    </form>
</div>

EmailSettings.ts

import { Component, OnInit, ViewChild, ViewEncapsulation, ChangeDetectorRef, Inject } from '@angular/core';
import * as FileSaver from 'file-saver';
import { MatInputModule } from '@angular/material/input';

@Component({
    selector: 'app-EmailSettings',
    encapsulation: ViewEncapsulation.None,
    templateUrl: './EmailSettings.html',
  
  })

  export class EmailSettings{
    appIdOpts: any = [];
    saveXML(){
        console.log("TestXML");
        let blob = new Blob([document.getElementById('formID').innerHTML], {type: "text/xml"});
        FileSaver.saveAs(blob, "blobExport.xml");
      }

  }

当我按下表单的“保存”按钮时,出现错误 ERROR TypeError: _co.saveXML is not a function

我知道已经有了,但是没有帮我解决错误。我能做什么?


编辑:

正如@SirOneOfMany 所建议的,我创建了一个新组件 EmailSettings。我的新结构如下:

根据您的要求,我的报告-viewer.component.ts有以下内容。请注意,它包含一些与本主题无关的其他功能。与我们相关的函数称为 openDialog().

import { Component, OnInit, ViewChild, ViewEncapsulation, ChangeDetectorRef, Inject } from '@angular/core';
import 'devexpress-reporting/dx-richedit';
import { DxReportViewerComponent } from 'devexpress-reporting-angular';
import { HttpClient } from '@angular/common/http';
import DevExpress from '@devexpress/analytics-core';
import List from "devextreme/ui/list";
import { DxSelectBoxModule, DxCheckBoxModule, DxListModule } from 'devextreme-angular';
import { ParagraphPropertiesKeepLinesTogetherDescriptor } from 'devexpress-richedit/lib/core/model/paragraph/paragraph-property-descriptors';
import { DxDropDownBoxModule, DxTreeViewModule, DxDataGridModule, DxTreeViewComponent, } from 'devextreme-angular';
import DXAnalytics from '@devexpress/analytics-core/dx-analytics-core'
import * as ko from 'knockout';
import { MatDialog, MAT_DIALOG_DATA } from '@angular/material';
import { MatInputModule } from '@angular/material/input';
import { EmailSettingsComponent } from '../email-settings/email-settings.component';  



@Component({
  selector: 'app-report-viewer',
  encapsulation: ViewEncapsulation.None,
  templateUrl: './report-viewer.component.html',
  styleUrls: [
    "./report-viewer.component.css",
    "../../../node_modules/jquery-ui/themes/base/all.css",
    "../../../node_modules/devextreme/dist/css/dx.common.css",
    "../../../node_modules/devextreme/dist/css/dx.light.css",
    "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.common.css",
    "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.light.css",
    "../../../node_modules/devexpress-reporting/dist/css/dx-webdocumentviewer.css"
  ]

})



export class ReportViewerComponent implements OnInit {


  @ViewChild(DxReportViewerComponent, { static: true }) viewer: DxReportViewerComponent;
  @ViewChild('selectedReport', { static: false }) public selectedReport: "C:\ReportDesigner\Reports";
  @ViewChild("emailSettings", { static: true }) emailSettings: EmailSettingsComponent;

 // @ViewChild('selectedReport', { static: false }) public selectedReport: "@/Reports";

  treeBoxValue: 'selectedReport';
  isTreeBoxOpened: boolean;
  

  title = 'DXReportViewerSample';
  hostUrl = 'http://localhost:54111/';
  invokeAction: string = "/WebDocumentViewer/Invoke";
  reportUrl: string = 'Employee'; 

//some other functions here...

  ngOnInit() {
      var ajaxSetup = DXAnalytics.Analytics.Utils.ajaxSetup
    ajaxSetup.ajaxSettings = {
      xhrFields: {
        withCredentials: true
     }
  };
  }

  openDialog(){ //this functions is used to open the form which was on EmailSettings.html)
    this.dialog.open(EmailSettingsComponent, {
      data: {
       // animal: 'panda',
        smtpHost: '',
        smtpPort: '',
        smtpUserName: '',
        smtpUserPassword: '',
        smtpFrom: '',
        smtpDisplayName: '',
      },
    });
  }
}

export interface DialogData { 
  smtpHost: any;
  smtpPort: any;
  smtpUserName: any;
  smtpUserPassword: any;
  smtpFrom: any;
  smtpDisplayName: any;
}

@Component({
  selector: 'app-email-settings',
  templateUrl: 'email-settings',
})
export class EmailSettings {
  constructor(@Inject(MAT_DIALOG_DATA) public data: DialogData) {}
} 

此时我得到错误ERROR in ./src/app/report-viewer/report-viewer.component.ts Module not found: Error: Can't resolve './email-settings' in 'C:\ProiectVisualStudio\ProjectName\JS\angular-report-designer\src\app\report-viewer'

正如我在评论部分所述,您必须声明一个组件。仅仅添加一个装饰器是不够的。 每添加一个 class @Component(...) 都需要添加到模块的声明数组中。

我假设您只有一个 AppModule class。所以你需要将你的组件添加到这个模块。

你用过

@Component({
    selector: 'app-EmailSettings',
    encapsulation: ViewEncapsulation.None,
    templateUrl: './EmailSettings.html',
})

因此您需要将 EmailSettings class 添加到您的模块声明数组中:

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

这就是为什么我说你应该用 ng 原理图创建你的组件,因为 angular 已经为你做了。

所以只需使用:

ng generate component relative/path/in/src/folder/email-settings

此命令将为您的组件创建文件(.ts、.html、.(s)css、.spec.ts)并将组件添加到最近的模块.

查看at this article以获得关于模块的更准确的解释


编辑

感谢您编辑您的问题。在 report-viewer 组件的最后,您有以下可能会引发错误的内容

@Component({
  selector: 'app-email-settings',
  templateUrl: 'email-settings', // this should throw the error
})
export class EmailSettings {
  constructor(@Inject(MAT_DIALOG_DATA) public data: DialogData) {}
}

删除 class 并使用新生成的组件。作为一个小的最佳实践提示:

只需实现一个 class 通过每个文件的 @Component 装饰

使用 ng schematics 生成代码,这样你就可以确保你的东西在整个应用程序中是一致的。

为每个接口提供一个文件并将其移动到模型文件夹