Angular2:多文件上传二进制内容绑定到结构化对象数组的疑问
Hi DarioN1! Let's work through this multi-file upload scenario in Angular where you need to bind each selected file's binary content to your PriceList array items. I'll walk you through a complete implementation tailored to your existing setup:
1. Wire Up Your Template to Link File Inputs with PriceList Items
First, update your component template to render a file input for each item in your listFile array. We'll use *ngFor to loop through the array and attach a change event handler that passes both the file event and the corresponding PriceList item:
<div class="price-list-item" *ngFor="let priceList of listFile; let idx = index"> <h4>Price List #{{idx + 1}}</h4> <div> <label>Code: {{priceList.code}}</label> </div> <div> <label>Name: {{priceList.name}}</label> </div> <div> <label>Select File:</label> <input type="file" (change)="handleFileSelection($event, priceList)" accept=".pdf,.xlsx,.csv" <!-- Optional: Restrict file types --> > </div> <hr> </div> <button (click)="uploadAllPriceLists()" [disabled]="listFile.some(item => !item.binary)"> Upload All Price Lists </button>
2. Implement File Reading Logic in the Component
Next, add the handleFileSelection method to your component. This method will use the FileReader API to read the selected file's content and assign it to the binary property of the target PriceList item. We'll cover two common scenarios depending on how your WebAPI accepts binary data:
import { Component } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { PriceList } from './path-to-your-price-list-model'; @Component({ selector: 'app-price-list-upload', templateUrl: './price-list-upload.component.html' }) export class PriceListUploadComponent { public listFile: PriceList[] = []; constructor(private http: HttpClient) { // Assume this is populated from your WebAPI as you mentioned // this.listFile = fetchedPriceLists; } handleFileSelection(event: Event, priceList: PriceList): void { const fileInput = event.target as HTMLInputElement; const selectedFile = fileInput.files?.[0]; if (!selectedFile) return; const reader = new FileReader(); // Option 1: Convert file to Base64 string (ideal for JSON payloads) reader.readAsDataURL(selectedFile); reader.onload = () => { // Strip the "data:[mime-type];base64," prefix if your backend expects raw Base64 const base64Content = reader.result?.toString().split(',')[1]; priceList.binary = base64Content; }; // Option 2: Keep file as Blob (ideal for FormData uploads) // reader.readAsArrayBuffer(selectedFile); // reader.onload = () => { // priceList.binary = new Blob([reader.result as ArrayBuffer], { type: selectedFile.type }); // }; reader.onerror = (error) => { console.error(`Failed to read file ${selectedFile.name}:`, error); }; } uploadAllPriceLists(): void { // Choose the upload method based on your WebAPI's requirements // Method 1: Send as JSON (use with Option 1 above) this.http.post('/api/price-lists/bulk-upload', this.listFile) .subscribe({ next: (response) => { console.log('Upload successful!', response); // Reset file inputs or array here if needed }, error: (err) => console.error('Upload failed:', err) }); // Method 2: Send as FormData (use with Option 2 above) // const formData = new FormData(); // this.listFile.forEach((item, index) => { // formData.append(`priceLists[${index}].idPriceList`, item.idPriceList.toString()); // formData.append(`priceLists[${index}].code`, item.code); // formData.append(`priceLists[${index}].name`, item.name); // formData.append( // `priceLists[${index}].binary`, // item.binary, // `${item.code}-${item.name}.${selectedFile.name.split('.').pop()}` // ); // }); // this.http.post('/api/price-lists/bulk-upload', formData) // .subscribe(...); } }
3. Key Notes for Your Implementation
- Async File Reading: Remember that
FileReaderworks asynchronously, so always assign thebinaryvalue inside theonloadcallback (never immediately after callingreadAsDataURLorreadAsArrayBuffer). - Backend Compatibility: Check your WebAPI's documentation to confirm whether it accepts Base64 strings in JSON or expects multipart FormData. Adjust the file reading and upload logic accordingly.
- Validation: You can add checks in
handleFileSelectionto validate file size, type, or extension before reading the file (e.g.,if (selectedFile.size > 5 * 1024 * 1024) { alert('File too large!'); return; }). - Disabled Upload Button: The button in the template is disabled if any
PriceListitem doesn't have abinaryvalue, ensuring you don't upload incomplete data.
内容的提问来源于stack exchange,提问作者DarioN1

