Я пытаюсь загрузить данные из файла Excel в приложение angular. Я могу загрузить данные Excel, проанализировать их, чтобы получить только нужные мне столбцы, и сохранить их в массиве. Это сделано в моем файле service.ts.
Служба вызывается из файла component.ts в качестве возврата. Я подтверждаю, что получаю свои данные с помощью console.log ().
Я использую @Output () для отправки данных дочернему компоненту для отображения данных как MatTableDataSource.
Я знаю, что шаблон html работает, поскольку я поместил данные на json -сервер и вызвал его оттуда, используя службу для возврата данных.
Я пробовал несколько разных модов, чтобы увидеть почему источник данных не отображается в html. Мой экран html показывает, что у меня есть несколько записей, но не отображаются строки данных.
service.ts
import { Injectable, EventEmitter, Output } from '@angular/core';
import * as XLSX from 'xlsx';
import { BoMItem } from '../_models/bomItem';
import { Observable, of } from 'rxjs';
const BOM_DATA: BoMItem[] = [];
@Injectable({
providedIn: 'root'
})
export class ExcelService {
fileUploaded: File;
storeData: any;
worksheet: any;
jsonData: any;
myData = {} as BoMItem;
constructor() { }
readExcel(filesUploaded: FileList): Observable<any> {
// console.log(filesUploaded);
for (const file in filesUploaded) {
if (Object.prototype.hasOwnProperty.call(filesUploaded, file)) {
let importFile: File = filesUploaded[file];
// console.log('File: ', importFile);
let readFile = new FileReader();
readFile.onload = (e) => {
this.storeData = readFile.result;
let data = new Uint8Array(this.storeData);
let arr = new Array();
for (let i = 0; i !== data.length; ++i) {
arr[i] = String.fromCharCode(data[i]);
}
let bstr = arr.join('');
let workbook = XLSX.read(bstr, { type: 'binary' });
let firstSheetName = workbook.SheetNames[0];
this.worksheet = workbook.Sheets[firstSheetName];
this.createJsonData();
};
readFile.readAsArrayBuffer(importFile);
}
}
return of(BOM_DATA);
}
createJsonData() {
// : Observable<BoMItem[]>
this.jsonData = XLSX.utils.sheet_to_json(this.worksheet, { raw: false });
this.jsonData.forEach(element => {
this.myData = {} as BoMItem;
for (const key in element) {
if (Object.prototype.hasOwnProperty.call(element, key)) {
const item = element[key];
if (key === 'DESC' || key === 'Description' || key === 'Disc') {
this.myData.desc = item;
}
if (key === 'PART NUMBER' || key === 'MFG PART NUMBER' || key === 'Catalog') {
this.myData.partNumber = item;
}
if (key === 'MFG' || key === 'Manufacturer' || key === 'mfg') {
this.myData.mfg = item;
}
if (key === 'QTY' || key === 'qty' || key === 'Quantity') {
this.myData.qty = item;
}
}
}
BOM_DATA.push(this.myData);
});
// console.log('BOM_DATA: ', BOM_DATA);
return of(BOM_DATA);
}
model.ts
export interface BoMItem {
desc: string;
partNumber: string;
mfg: string;
qty: string;
supplierName?: string;
}
parent component.ts
import { Component, OnInit, Output } from '@angular/core';
import { ExcelService } from 'src/app/_services/excel.service';
@Component({
selector: 'app-bom-load',
templateUrl: './bom-load.component.html',
styleUrls: ['./bom-load.component.css']
})
export class BomLoadComponent implements OnInit {
@Output()
data: any;
constructor(
private excelService: ExcelService
) { }
ngOnInit(): void {
}
uploadedFile(evt) {
return this.excelService.readExcel(evt.target.files).subscribe((response: any) => {
this.data = response;
console.log('bom-load: ', this.data);
});
}
}
child component.ts
import { Component, ViewChild, OnInit, Input } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { NgForm } from '@angular/forms';
import * as _ from 'lodash';
import { BoMItem } from 'src/app/_models/bomItem';
import { HttpClient } from '@angular/common/http';
import { BomService } from 'src/app/_services/bom.service';
import { MatSort } from '@angular/material/sort';
@Component({
selector: 'app-bom-list',
templateUrl: './bom-list.component.html',
styleUrls: ['./bom-list.component.css']
})
export class BomListComponent implements OnInit {
@ViewChild('bomForm', { static: false})
bomForm: NgForm;
bomData: BoMItem;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@ViewChild(MatSort, {static: true}) sort: MatSort;
displayedColumns: string[] = ['desc', 'partNumber', 'mfg', 'qty', 'supName', 'actions'];
// displayedColumns: string[] = ['desc', 'partNumber', 'mfg', 'qty', 'actions'];
@Input()
data: any[];
dataSource: MatTableDataSource<BoMItem>;
isEditMode = false;
constructor(private http: HttpClient, private bomService: BomService) {
this.bomData = {} as BoMItem;
}
ngOnInit() {
this.dataSource = new MatTableDataSource(this.data);
// this.getAllBomItems();
console.log('bom-list: ', this.dataSource);
// this.dataSource.paginator = this.paginator;
// this.dataSource.sort = this.sort;
}
getAllBomItems() {
this.bomService.getList().subscribe((response: any) => {
this.dataSource.data = response;
});
}
editItem(element) {
this.bomData = _.cloneDeep(element);
this.isEditMode = true;
}
cancelEdit() {
this.isEditMode = false;
this.bomForm.resetForm();
}
onSubmit() {
if (this.bomForm.form.valid) {
if (this.isEditMode) {
this.updateBomItem();
}
else {
this.addBomItem();
}
} else {
console.log('Enter valid data!');
}
}
addBomItem() {
throw new Error('Method not implemented.');
}
updateBomItem() {
this.bomService.updateItem(this.bomData.partNumber, this.bomData).subscribe((response: any) => {
this.dataSource.data = this.dataSource.data.map((o: BoMItem) => {
if (o.partNumber === response.partNumber) {
o = response;
}
return o;
});
this.getAllBomItems();
});
}
}
родительский компонент. html
<mat-toolbar>
<input type="file" class="form-control" (change)="uploadedFile($event)" placeholder="Upload file"
accept=".xls,.xlsx" multiple>
</mat-toolbar>
<div *ngIf="data != null">
<app-bom-list [data]="data"></app-bom-list>
</div>
дочерний компонент. html
<div class="container">
<ng-container *ngIf="isEditMode;">
<button mat-button color="warn">Update</button>
<a mat-button color="warn" (click)="cancelEdit()">Cancel</a>
</ng-container>
</form> -->
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container matColumnDef="desc">
<th mat-header-cell *matHeaderCellDef>Description</th>
<td mat-cell *matCellDef="let element">{{element.desc }}</td>
</ng-container>
<ng-container matColumnDef="partNumber">
<th mat-header-cell *matHeaderCellDef>Part Number</th>
<td mat-cell *matCellDef="let element"> {{element.partNumber}} </td>
</ng-container>
<ng-container matColumnDef="mfg">
<th mat-header-cell *matHeaderCellDef>Manufacturer</th>
<td mat-cell *matCellDef="let element"> {{element.mfg}} </td>
</ng-container>
<ng-container matColumnDef="qty">
<th mat-header-cell *matHeaderCellDef> Quantity </th>
<td mat-cell *matCellDef="let element"> {{element.qty}} </td>
</ng-container>
<ng-container matColumnDef="supName">
<th mat-header-cell *matHeaderCellDef> Supplier Name </th>
<td mat-cell *matCellDef="let element"> {{element.supplierName}} </td>
</ng-container>
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef>
<!-- <button mat-icon-button color="primary">
<mat-icon aria-label="Example icon-button with a heart icon">add</mat-icon>
</button> -->
</mat-header-cell>
<mat-cell *matCellDef="let element; let i=index;">
<button mat-icon-button color="accent">
<mat-icon aria-label="Edit" (click)="editItem(element)">edit</mat-icon>
</button>
<button mat-icon-button color="accent">
<mat-icon aria-label="Delete">delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [length]="dataSource?.data.length" [pageSize]="5" [pageSizeOptions]="[5, 10, 25, 100, 500]">
</mat-paginator>
</div>
Информация журнала консоли:
bom-load:
[]
0: {qty: "6", mfg: "Mencom", partNumber: "1321-3R8-C", desc: "480V 3-PHASE AC DRIVE REACTORS, OPEN TYPE, 8A, 3 HP Drive"}
1: {qty: "1", mfg: "AB", partNumber: "1756-EN2T", desc: "1756 CONTROL LOGIX ETHERNET / IP BRIDGE MODULE (128 TCP/IP CONNECTIONS)"}
2: {qty: "1", mfg: "AB", partNumber: "1756-EN2TR", desc: "1756 CONTROL LOGIX ETHERNET / IP BRIDGE MODULE (128 TCP/IP CONNECTIONS) REDUNDANT"}
3: {qty: "1", mfg: "AB", partNumber: "1756-L81E", desc: "1756 CONTROL LOGIX CONTROLLER, USER MEMORY 3MB, 1Gb ENET PORT"}
4: {qty: "6", mfg: "AB", partNumber: "25B-D6P0N104", desc: "POWERFLEX 525 VARIABLE FREQUENCY DRIVE 3 HP, 480VAC 3 PH, FRAME A"}
5: {qty: "6", mfg: "AB", partNumber: "25-COMM-E2P", desc: "POWERFLEX 525 DUAL-PORT ETHERNET/IP MODULE"}
length: 6
__proto__: Array(0)
bom-list.component.ts:43 bom-list:
MatTableDataSource {_renderData: BehaviorSubject, _filter: BehaviorSubject, _internalPageChanges: Subject, _renderChangesSubscription: Subscriber, sortingDataAccessor: ƒ, …}
filterPredicate: (data, filter) => {…}
filteredData: (6) [{…}, {…}, {…}, {…}, {…}, {…}]
sortData: (data, sort) => {…}
sortingDataAccessor: (data, sortHeaderId) => {…}
_data: BehaviorSubject {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
_filter: BehaviorSubject {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
_internalPageChanges: Subject {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}
_renderChangesSubscription: Subscriber {closed: false, _parentOrParents: null, _subscriptions: Array(1), syncErrorValue: null, syncErrorThrown: false, …}
_renderData: BehaviorSubject {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
data: Array(6)
0: {qty: "6", mfg: "Mencom", partNumber: "1321-3R8-C", desc: "480V 3-PHASE AC DRIVE REACTORS, OPEN TYPE, 8A, 3 HP Drive"}
1: {qty: "1", mfg: "AB", partNumber: "1756-EN2T", desc: "1756 CONTROL LOGIX ETHERNET / IP BRIDGE MODULE (128 TCP/IP CONNECTIONS)"}
2: {qty: "1", mfg: "AB", partNumber: "1756-EN2TR", desc: "1756 CONTROL LOGIX ETHERNET / IP BRIDGE MODULE (128 TCP/IP CONNECTIONS) REDUNDANT"}
3: {qty: "1", mfg: "AB", partNumber: "1756-L81E", desc: "1756 CONTROL LOGIX CONTROLLER, USER MEMORY 3MB, 1Gb ENET PORT"}
4: {qty: "6", mfg: "AB", partNumber: "25B-D6P0N104", desc: "POWERFLEX 525 VARIABLE FREQUENCY DRIVE 3 HP, 480VAC 3 PH, FRAME A"}
5: {qty: "6", mfg: "AB", partNumber: "25-COMM-E2P", desc: "POWERFLEX 525 DUAL-PORT ETHERNET/IP MODULE"}
length: 6
__proto__: Array(0)
filter: (...)
paginator: (...)
sort: (...)
__proto__: DataSource
Изображение html таблицы, пытающейся использовать данные, загруженные из Excel
Image of static data using this.getAllBomItems
Изображение данных stati c с использованием this.getAllBomItems ()
Интересная разработка:
добавлением; как было предложено; ngOnChanges (), теперь я получаю данные, но ТОЛЬКО после нажатия кнопок пагинации.
ngOnChanges() {
this.dataSource = new MatTableDataSource(this.data);
this.dataSource.paginator = this.paginator;
console.log('bom-list: ', this.dataSource);
console.log('this.data: ', this.data);
this.dataSource.paginator = this.paginator;
}