首页 > 解决方案 > 如何修复错误“错误类型错误:无法读取未定义的属性'0'”

问题描述

我正在开发一个目录应用程序,我想在我的列表选项中显示工具提示。

这是我的清单,供您更好地理解:

列表

例如,当我的鼠标在列表的第一个选项上滑动时,我希望显示以下消息:“Exporte les données des catalogs du contexte de mapping en cours au format XML”

等等 ....

为此,我在 .ts 文件中创建了此表:

const info_bulle_export: Array<{id:number, text:string}> =[

    {id:1, text:'Exporte les données des catalogues du contexte de mapping en cours au format XML'},
    {id:2, text:''},
    {id:3, text:'Exporte les données de mapping du contexte de mapping en cours au format XML'},
    {id:4, text:''},
    {id:5, text:'Exporte un rapport détaillé du mapping des scopes du contexte de mapping en cours au format XLS'},
    {id:6, text:'Exporte dans le même fichier XML les données catalogues et mapping par système de mapping, peut exporter dans une archive de fichiers XML tous les systèmes de mapping du contexte en cours'},
    {id:7, text:'Exporte le contexte de mapping en cours au format zip archivant les données catalogues dans un fichier XML et les données mapping dans un autre fichier XML'},
    {id:8, text:'Exporte les entités non mappées au format XLS'},
    {id:9, text:'Exporte les entités sans relations au format XLS'},
    {id:10, text:''}
];

在我的 .html 文件中我放了这个:

<option *ngFor="let worker of workerExportList; index as i" [ngValue]="worker" data-toggle="tooltip" data-placement="top" title="{{info_bulle_export[i]}}">{{worker.label}}</option>

如果您需要,这是我的 .ts 文件的所有代码:

import { Observable } from 'rxjs/Rx';
import { Http, RequestOptions, Headers, ResponseContentType, Response } from '@angular/http';
import { environment } from './../../../../environments/environment';
import { ExportService } from './../../exportDirectoryBrowsing/export.service';
import { sideMenuComponent } from './../../../layout/side-menu-component/side-menu.component';
import { WorkerParameterInfo } from './../workerParameterInfo';
import { WorkerExport } from './WorkerExport';
import { MappingSystemService } from './../../mappingSystem/mapping-system.service';
import { CatalogService } from './../../catalogue/Catalog.service';
import { Catalog } from './../../catalogue/Catalog';
import { MappingSystem } from './../../mappingSystem/MappingSystem';
import { MappingContext } from './../../mappingContext/MappingContext';
import { Component,  ViewChild } from '@angular/core';
import { LazyLoadEvent, ConfirmationService, TreeNode, Message } from 'primeng/primeng';
import { FormsModule } from '@angular/forms';
import { WorkersService } from '../worker.service';
import { SharedService } from './../../../shared.service';
import { FormGroup, FormBuilder } from '@angular/forms';
import * as FileSaver from 'file-saver';
import { DialogModule, Dialog } from 'primeng/components/dialog/dialog';
import {ProgressSpinnerModule} from 'primeng/components/progressspinner/progressspinner';
import { Timeouts } from 'selenium-webdriver';
import { $$iterator } from 'rxjs/internal/symbol/iterator';

const info_bulle_export: Array<{id:number, text:string}> =[

    {id:1, text:'Exporte les données des catalogues du contexte de mapping en cours au format XML'},
    {id:2, text:''},
    {id:3, text:'Exporte les données de mapping du contexte de mapping en cours au format XML'},
    {id:4, text:''},
    {id:5, text:'Exporte un rapport détaillé du mapping des scopes du contexte de mapping en cours au format XLS'},
    {id:6, text:'Exporte dans le même fichier XML les données catalogues et mapping par système de mapping, peut exporter dans une archive de fichiers XML tous les systèmes de mapping du contexte en cours'},
    {id:7, text:'Exporte le contexte de mapping en cours au format zip archivant les données catalogues dans un fichier XML et les données mapping dans un autre fichier XML'},
    {id:8, text:'Exporte les entités non mappées au format XLS'},
    {id:9, text:'Exporte les entités sans relations au format XLS'},
    {id:10, text:''}
];
@Component({
    selector: 'export',
    templateUrl: './export.component.html',
    styleUrls: ['./../../global.css'],
    providers: [WorkersService, ConfirmationService]
})
export class ExportComponent {
    value = 0;
    workerForm: FormGroup;
    selectedExportWorker: WorkerExport;
    selectedMappingContext: MappingContext;
    selectedMappingSystem: MappingSystem;
    selectedCatalog: Catalog;
    catalogues: Catalog[] = [];
    workerExportList: WorkerExport[] = [];
    mappingSystems: MappingSystem[] = [];
    blankObject: Catalog = new Catalog(0, 'TOUS', 'TOUS', null);
    blankObjectMS: MappingSystem = new MappingSystem(0, 'TOUS', null, null, null, null, null);
    blanckObjectMSAllInAZip : MappingSystem = new MappingSystem(100, 'TOUS DANS UN ZIP', null, null, null, null, null);
    isHiddenCatalogue = false;
    isHiddenMappingSystem = false;
    filesTree2: TreeNode[] = [];
    selectedFile: TreeNode;
    msgs: Message[] = [];
    display: Boolean = false;
    response: Response;

    @ViewChild('dialog') dialog: DialogModule;
    @ViewChild('spinner') spinner: ProgressSpinnerModule;

    constructor(private workersService: WorkersService, private api: SharedService,
        fb: FormBuilder, private catalogService: CatalogService, private mappingSystemService: MappingSystemService,
        private exportService: ExportService, private confirmationService: ConfirmationService, private http: Http) {

        this.workerExportList.push(new WorkerExport('catalogueExport', 'Export des catalogues'));
        this.workerExportList.push(new WorkerExport('mappingExportV1_0', 'Export des mappings S1F0'));
        this.workerExportList.push(new WorkerExport('mappingExport', 'Export des mappings'));
        this.workerExportList.push(new WorkerExport('release', 'Livraison'));
        this.workerExportList.push(new WorkerExport('summaryExport', 'Export du rapport XLS - mapping des scopes'));
        this.workerExportList.push(new WorkerExport('koalaExport', 'Export koala'));
        this.workerExportList.push(new WorkerExport('pamdaExport', 'Export pamda'));
        this.workerExportList.push(new WorkerExport('orphanExport', 'Export orphelins - entités non mappées'));
        this.workerExportList.push(new WorkerExport('hierarchyValidator', 'Validation hiérarchie - entités sans relation'));
        this.workerExportList.push(new WorkerExport('dataExport', 'Export des données'));

        this.workerForm = fb.group({
            'selectedExportWorker': '',
            'selectedCatalog': this.blankObject,
            'selectedMappingSystem': this.blankObjectMS
        })



        this.selectedCatalog = this.blankObject;
        this.selectedMappingSystem = this.blankObjectMS;

        this.api.getDataMappingContext().subscribe(_sharingData => {
            this.selectedMappingContext = _sharingData;
            if (_sharingData) {
                this.exportService.getByMappingCOntext(_sharingData.id).subscribe(data => {
                    this.createTree(data, this.filesTree2, null);
                    console.log(this.filesTree2);
                });
            }
        });
    }


    ngOnInit() {
        localStorage.removeItem('mapping');
        localStorage.removeItem('page');
        this.api.getDataMappingContext().subscribe(mappingContext => {
            if (mappingContext != null) {
                this.selectedMappingContext = mappingContext;
                this.mappingSystemService.getByMappingContext(this.selectedMappingContext.id).subscribe(data => this.mappingSystems = data);
                this.catalogService.getCatalogByMappingContext(this.selectedMappingContext.id).subscribe(data => this.catalogues = data);
            }
        });
    }

    exportCatalogue() {
       return this.workersService.exportCatalogue(new WorkerParameterInfo()).subscribe();
    }

    selectWorker() {
        this.value = 0;
        if (this.selectedExportWorker != null && (
            this.selectedExportWorker.code === 'catalogueExport' ||
            this.selectedExportWorker.code === 'dataExport')) {
            this.isHiddenCatalogue = false;
        } else {
            this.isHiddenCatalogue = true ;
        }

        if (this.selectedExportWorker != null && this.selectedExportWorker.code === 'koalaExport') {
            this.isHiddenMappingSystem = false;
        } else {
            this.isHiddenMappingSystem = true;
        }
    }

    executer() {
        this.value = 60;
        let workerParameterInfo = new WorkerParameterInfo();
        workerParameterInfo.currentMappingContext = this.selectedMappingContext.id;
        workerParameterInfo.disabledByUser = false;
        if (this.selectedExportWorker.code === 'catalogueExport') {
            this.display = true;
            workerParameterInfo.catalogueIdOrALL = this.selectedCatalog.id.toString();
            this.workersService.exportCatalogue(workerParameterInfo).subscribe((res: Response) => {
                console.log('response catalogueExport :', res);
                this.display = false;
                this.refresh();
            });
        } else if (this.selectedExportWorker.code === 'mappingExportV1_0') {
            this.display = true;
            this.workersService.exportMappingV10(workerParameterInfo).subscribe((res: Response) => {
                this.display = false;
                this.refresh();
            });
        } else if (this.selectedExportWorker.code === 'mappingExport') {
            this.display = true;
            this.workersService.exportMapping(workerParameterInfo).subscribe((res: Response) => {
                this.display = false;
                this.refresh();
            });
        } else if (this.selectedExportWorker.code === 'koalaExport') {
            this.display = true;
            workerParameterInfo.mappingSystemIdOrALL = this.selectedMappingSystem.id.toString();
            console.log('koala workerParameterInfo :', workerParameterInfo.mappingSystemIdOrALL);
            this.workersService.exportKoala(workerParameterInfo).subscribe((res: Response) => {
                console.log(res);
                this.display = false;
                this.refresh();
            });
        } else if (this.selectedExportWorker.code === 'release') {
            this.display = true;
            this.workersService.exportLivraison(workerParameterInfo).subscribe((res: Response) => {
                this.display = false;
                this.refresh();
            });
        } else if (this.selectedExportWorker.code === 'summaryExport') {
            this.display = true;
            this.workersService.exportSummary(workerParameterInfo).subscribe((res: Response) => {
                this.display = false;
                this.refresh();
            });
        } else if (this.selectedExportWorker.code === 'pamdaExport') {
            this.display = true;
            this.workersService.exportPamda(workerParameterInfo).subscribe((res: Response) => {
                this.display = false;
                this.refresh();
            });
        } else if (this.selectedExportWorker.code === 'orphanExport') {
            this.display = true;
            this.workersService.exportOrphan(workerParameterInfo).subscribe((res: Response) => {
                this.display = false;
                this.refresh();
            });
        } else if (this.selectedExportWorker.code === 'hierarchyValidator') {
            this.display = true;
            this.workersService.validateHierarchy(workerParameterInfo).subscribe((res: Response) => {
                this.display = false;
                this.refresh();
            });
        } else if (this.selectedExportWorker.code === 'dataExport') {
            this.display = true;
            workerParameterInfo.catalogueIdOrALL = this.selectedCatalog.id.toString();
            this.workersService.exportData(workerParameterInfo).subscribe((res: Response) => {
                this.display = false;
                this.refresh();
            });
        }
        this.value = 90;
        this.refresh();
        this.value = 100;
    }

    createTree(data: any[], tree: TreeNode[], parent: TreeNode) {
        // console.log('creating Tree From: ', data);

        data.forEach(dir => {
            let treeNode: TreeNode = {
                label: '',
                data: '',
                children: [],
                leaf: false,
                expandedIcon: '',
                collapsedIcon: '',
                icon: '',
                expanded: true,
                parent: {}
            };

            if (dir.leaf === false) {
                treeNode.label = dir.label;
                treeNode.expandedIcon = 'fa-folder-open';
                treeNode.collapsedIcon = 'fa-folder';
                treeNode.parent = parent;
                this.createTree(dir.children, treeNode.children, treeNode)
                tree.push(treeNode);
            } else {
                treeNode.label = dir.label;
                treeNode.leaf = true;
                treeNode.data = dir.data;
                treeNode.parent = parent;
                if (treeNode.label.endsWith('zip')) {
                    treeNode.icon = 'fa-file-archive';
                } else if (treeNode.label.endsWith('xml')) {
                    treeNode.icon = 'fa-file-code';
                } else if (treeNode.label.endsWith('xls')) {
                    treeNode.icon = 'fa-file-excel';
                } else if (treeNode.label.endsWith('txt')) {
                    treeNode.icon = 'fa-file';
                } else {
                    treeNode.icon = 'fa-file';
                }
                tree.push(treeNode);
            }
        });
    }


    confirmDelete() {
        this.confirmationService.confirm({
            message: 'Êtes-vous sûr de vouloir supprimer cet objet?',
            header: 'Confirmation de suppression',
            icon: 'fa fa-trash',
            accept: () => {
                this.deleteFile();
            }
        });
    }

    nodeSelect(event) {
        if (event.node.leaf === false) {
            this.selectedFile = null;
        }
    }

    deleteFile() {
        this.exportService.delete(this.selectedFile.data).subscribe(() => {
            this.selectedFile.parent.children.splice(this.selectedFile.parent.children.findIndex(
                child => child.data === this.selectedFile.data), 1);
            this.showSuccess('Fichier supprimé avec succès');
        });
    }


    downloadFile() {
        const headers = new Headers();
        headers.append('Content-Type', 'application/json');
        let requestOptions = new RequestOptions({
            headers: headers,
            responseType: ResponseContentType.Blob, // dont forget to import the enum
            // In case you get Module not found: Error: Can't resolve '@angular/http/src/enums', just use 3 instead ex 'responseType:3'
        });
        let workerParameterInfo = new WorkerParameterInfo();
        workerParameterInfo.pathFile = this.selectedFile.data;

        let bodyString = JSON.stringify(workerParameterInfo);
        this.http.post(`${environment.url.base}${environment.url.pamda.downloadFile}`, bodyString, requestOptions).subscribe(res => {
            FileSaver.saveAs(res.blob(), this.selectedFile.label)
        });

    }


    refresh() {
        this.filesTree2 = [];
        if (this.selectedMappingContext) {
            this.exportService.getByMappingCOntext(this.selectedMappingContext.id).subscribe(data => {
                this.createTree(data, this.filesTree2, null);
                // console.log(this.filesTree2);
            })
        }
    }

    showError() {
        this.msgs = [];
        this.msgs.push({ severity: 'error', summary: 'Message d\'erreur', detail: 'Vous ne pouvez pas supprimer ce catalogue' });
    }

    showSuccess(details) {
        this.msgs = [];
        this.msgs.push({ severity: 'success', summary: 'Succès', detail: details });
    }

}

如果您需要,这是我的 .html 文件的所有代码:

 <div class="workers center">
    <p-dialog #dialog [(visible)]="display" modal="modal" width="450" responsive="true" closable="true" id="loading-panel" appendTo="body">
        <p-header style="color: #FB864F;font-size: 18px;">
            Worker en cours d'exécution ...
        </p-header>
        <img style="width: 200px; margin-left: 100px;" src="assets/images/panda_face.gif" />
    </p-dialog>
    <div class="box">
        <form [formGroup]="workerForm" id="workerForm">
            <div class="box-header with-border">
                <h1 class="box-title"> <i class="glyphicon glyphicon-th-large"></i> Workers </h1>
            </div>
            <div class="box-body">
                <div class="form-group">
                    <label for="worker" class="col-sm-2 control-label">Worker: </label>
                    <div class="col-sm-10">
                        <select id="worker" class="form-control" [(ngModel)]="selectedExportWorker" [formControl]="workerForm.controls['selectedExportWorker']"
                            (ngModelChange)="selectWorker()">
                            <option [ngValue]="blankObject"></option>
                            <option *ngFor="let worker of workerExportList; index as i" [ngValue]="worker" data-toggle="tooltip" data-placement="top" title="{{info_bulle_export[i]}}">{{worker.label}}</option>
                        </select>
                    </div>
                </div><br/><br/>
                <div class="form-group" [hidden]="isHiddenCatalogue">
                    <label for="catalog" class="col-sm-2 control-label">Catalogue: </label>
                    <div class="col-sm-10">
                        <select id="catalog" class="form-control" [(ngModel)]="selectedCatalog" [formControl]="workerForm.controls['selectedCatalog']">
                            <option [ngValue]="blankObject">{{blankObject.code}}</option>
                            <option *ngFor="let catalog of catalogues" [ngValue]="catalog">{{catalog.code}}</option>
                        </select>
                    </div>
                </div>
                <div class="form-group" [hidden]="isHiddenMappingSystem">
                    <label for="catalog" class="col-sm-2 control-label">Système de mapping: </label>
                    <div class="col-sm-10">
                        <select id="catalog" class="form-control" [(ngModel)]="selectedMappingSystem" [formControl]="workerForm.controls['selectedMappingSystem']">
                            <option [ngValue]="blankObjectMS">{{blankObjectMS.code}}</option>
                            <option [ngValue]="blanckObjectMSAllInAZip">{{blanckObjectMSAllInAZip.code}}</option>
                            <option *ngFor="let mappingSystem of mappingSystems" [ngValue]="mappingSystem">{{mappingSystem.code}}</option>
                        </select>
                    </div>
                </div>
            </div>
            <div class="box-footer form_settings">
                <button type="button" class="btn btn-info pull-right submit side" (click)="executer()">Executer</button>
            </div>
        </form>
    </div>

    <div class="box">
        <div class="box-header with-border">
            <h3 class="box-title"> <i class="glyphicon glyphicon-th-large"></i> Progression de l'exécution </h3>
        </div>
        <div class="box-body">
            <p-progressBar [value]="value"></p-progressBar>
            <div class="workerSuccess" id="workerSuccess"><h4>Le worker a été importé avec succès !</h4></div>
        </div>
    </div>

    <!-- <div class="box loading">
        <div class="box-header with-border">
            <h3 class="box-title"> <i class="glyphicon glyphicon-th-large"></i> Workers en cours d'exécution </h3>
        </div>
        <div class="box-body"></div>
    </div> -->

    <div class="box">
        <div class="box-header with-border">
            <h2 class="box-title"> <i class="glyphicon glyphicon-th-large"></i> Fichiers présents sur le serveur</h2>
        </div>
        <div class="PrimeTableDiv box-body">
            <p-toolbar>
                <div class="ui-toolbar-group-left form_settings toolbar">
                    <button pButton class="submit side toolbar" label="Supprimer" icon="fa-trash" (click)="confirmDelete()"></button>
                    <button pButton class="submit side toolbar" label="Télecharger" icon="fa-download" (click)="downloadFile()"></button>
                    <button pButton class="submit side toolbar" label="rafraichir" icon="fa-sync" (click)="refresh()"></button>
                </div>
            </p-toolbar>
            <!-- <p-tree [value]="filesTree2" selectionMode="single" [(selection)]="selectedFile" (onNodeSelect)="nodeSelect($event)" (onNodeUnselect)="nodeUnselect($event)" -->
            <p-tree [value]="filesTree2" selectionMode="single" [(selection)]="selectedFile" (onNodeSelect)="nodeSelect($event)"
                [style]="{'width':'100%'}">
                </p-tree>
        </div>
    </div>
</div>
<p-confirmDialog width="425" appendTo="body"></p-confirmDialog>

the problem is that i get the following error and i don't know how to fix it:

> ERROR TypeError: Cannot read property '0' of undefined
    at Object.eval [as updateRenderer] (ExportComponent.html:20)
    at Object.debugUpdateRenderer [as updateRenderer] (core.js:23937)
    at checkAndUpdateView (core.js:23312)
    at callViewAction (core.js:23548)
    at execEmbeddedViewsAction (core.js:23511)
    at checkAndUpdateView (core.js:23308)
    at callViewAction (core.js:23548)
    at execComponentViewsAction (core.js:23490)
    at checkAndUpdateView (core.js:23313)
    at callViewAction (core.js:23548)

我认为错误来自这一行,因为当我删除它时,错误消失了,但我不知道问题究竟来自哪里:

<option *ngFor="let worker of workerExportList; index as i" [ngValue]="worker" data-toggle="tooltip" data-placement="top" title="{{info_bulle_export[i]}}">{{worker.label}}</option>

有人能帮助我吗?

标签: javascripthtmlangularjsangularbootstrap-4

解决方案


info_bulle_export应该是组件上的属性,而不是在组件外部声明的常量。

export class ExportComponent {
  info_bulle_export: Array<{id:number, text:string}> = [
    {
      id:1, 
      text:'Exporte les données des catalogues du contexte de mapping en cours au format XML'
    }
    // etc...
  ];
}

或者,您仍然可以在组件外部声明原始变量并从组件属性中引用它:

const info_bulle_export: Array<{id:number, text:string}> =[
  {
    id:1, 
    text:'Exporte les données des catalogues du contexte de mapping en cours au format XML'
  }
  // etc...
];

export class ExportComponent {
  info_bulle_export: Array<{id:number, text:string}> = info_bulle_export;
}

演示:https ://stackblitz.com/edit/angular-y4j8jn

我通常会在这种情况下创建一个视图模型——尤其是对于像下拉列表这样基本的东西。

下拉选项.ts

export interface DropdownOption {
  description: string;
  text: string;
  value: string;
}

组件.html

<select>
  <option *ngFor="let option of options" [value]"option.value"
      [title]="option.description">
    {{option.text}}
  </option>
</select>

推荐阅读