【问题标题】:Angular File Upload角度文件上传
【发布时间】:2018-06-04 19:02:21
【问题描述】:

我是 Angular 的初学者,我想知道如何创建 Angular 5 文件上传部分,我正在尝试查找任何教程或文档,但我在任何地方都看不到任何东西.有什么想法吗?我尝试了ng4-files,但它不适用于 Angular 5

【问题讨论】:

标签: angular typescript


【解决方案1】:

这是一个将文件上传到 api 的工作示例:

第 1 步:HTML 模板 (file-upload.component.html)

定义file 类型的简单输入标签。向(change)-event 添加一个函数来处理选择文件。

<div class="form-group">
    <label for="file">Choose File</label>
    <input type="file"
           id="file"
           (change)="handleFileInput($event.target.files)">
</div>

第 2 步:TypeScript 中的上传处理 (file-upload.component.ts)

为选定的文件定义一个默认变量。

fileToUpload: File | null = null;

创建您在文件输入标签的(change)-event 中使用的函数:

handleFileInput(files: FileList) {
    this.fileToUpload = files.item(0);
}

如果你想处理多文件选择,你可以遍历这个文件数组。

现在通过调用 file-upload.service 创建文件上传功能:

uploadFileToActivity() {
    this.fileUploadService.postFile(this.fileToUpload).subscribe(data => {
      // do something, if upload success
      }, error => {
        console.log(error);
      });
  }

第 3 步:文件上传服务 (file-upload.service.ts)

通过 POST 方法上传文件,您应该使用FormData,因为这样您就可以将文件添加到 http 请求中。

postFile(fileToUpload: File): Observable<boolean> {
    const endpoint = 'your-destination-url';
    const formData: FormData = new FormData();
    formData.append('fileKey', fileToUpload, fileToUpload.name);
    return this.httpClient
      .post(endpoint, formData, { headers: yourHeadersConfig })
      .map(() => { return true; })
      .catch((e) => this.handleError(e));
}

所以,这是一个非常简单的工作示例,我每天都会在工作中使用它。

【讨论】:

  • @GregorDoroschenko 我试图使用带有文件附加信息的模型,我必须这样做才能让它工作:const invFormData: FormData = new FormData(); invFormData.append('invoiceAttachment', invoiceAttachment, invoiceAttachment.name); invFormData.append('invoiceInfo', JSON.stringify(invoiceInfo)); 控制器有两个相应的参数,但我必须解析控制器中的 JSON。我的 Core 2 控制器不会自动拾取参数中的模型。我最初的设计是一个具有文件属性的模型,但我无法让它工作
  • @GregorDoroschenko 我试过这个代码createContrat(fileToUpload: File, newContrat: Contrat): Observable&lt;boolean&gt; { let headers = new Headers(); const endpoint = Api.getUrl(Api.URLS.createContrat)); const formData: FormData =new FormData(); formData.append('fileKey', fileToUpload, FileToUpload.name); let body newContrat.gup(this.auth.getCurrentUser().token); return this.http .post(endpoint, formData, body) .map(() =&gt; { return true; }) }
  • @GregorDoroschenko 对我来说不起作用。我在ws发帖:Content-Disposition: form-data; name="fileKey"; filename="file.docx" Content-Type: application/octet-stream &lt;file&gt;
  • 使用 Angular 5,这是行不通的。 formData 为空
  • $event.target.files有什么用??
【解决方案2】:

这样我在项目中实现了上传文件到web API。

我为谁担心。

const formData: FormData = new FormData();
formData.append('Image', image, image.name);
formData.append('ComponentId', componentId);
return this.http.post('/api/dashboard/UploadImage', formData);

一步一步

ASP.NET Web API

[HttpPost]
[Route("api/dashboard/UploadImage")]
public HttpResponseMessage UploadImage() 
{
    string imageName = null;
    var httpRequest = HttpContext.Current.Request;
    //Upload Image
    var postedFile = httpRequest.Files["Image"];
    //Create custom filename
    if (postedFile != null)
    {
        imageName = new String(Path.GetFileNameWithoutExtension(postedFile.FileName).Take(10).ToArray()).Replace(" ", "-");
        imageName = imageName + DateTime.Now.ToString("yymmssfff") + Path.GetExtension(postedFile.FileName);
        var filePath = HttpContext.Current.Server.MapPath("~/Images/" + imageName);
        postedFile.SaveAs(filePath);
    }
}

HTML 表单

<form #imageForm=ngForm (ngSubmit)="OnSubmit(Image)">

    <img [src]="imageUrl" class="imgArea">
    <div class="image-upload">
        <label for="file-input">
            <img src="upload.jpg" />
        </label>

        <input id="file-input" #Image type="file" (change)="handleFileInput($event.target.files)" />
        <button type="submit" class="btn-large btn-submit" [disabled]="Image.value=='' || !imageForm.valid"><i
                class="material-icons">save</i></button>
    </div>
</form>

使用 API 的 TS 文件

OnSubmit(Image) {
    this.dashboardService.uploadImage(this.componentId, this.fileToUpload).subscribe(
      data => {
        console.log('done');
        Image.value = null;
        this.imageUrl = "/assets/img/logo.png";
      }
    );
  }

服务 TS

uploadImage(componentId, image) {
        const formData: FormData = new FormData();
        formData.append('Image', image, image.name);
        formData.append('ComponentId', componentId);
        return this.http.post('/api/dashboard/UploadImage', formData);
    }

【讨论】:

  • 不发送标头的方法是什么?
【解决方案3】:

使用ng2-file-upload 是非常简单和最快的方法。

通过 npm 安装 ng2-file-upload。 npm i ng2-file-upload --save

首先在你的模块中导入模块。

import { FileUploadModule } from 'ng2-file-upload';

Add it to [imports] under @NgModule:
imports: [ ... FileUploadModule, ... ]

标记:

<input ng2FileSelect type="file" accept=".xml" [uploader]="uploader"/>

在您的组件中:

import { FileUploader } from 'ng2-file-upload';
...
uploader: FileUploader = new FileUploader({ url: "api/your_upload", removeAfterUpload: false, autoUpload: true });

这是最简单的用法。要了解此功能的所有功能,请参阅demo

【讨论】:

  • 图片上传后如何得到响应?会有什么反应,文档缺少这部分。
  • 警告:ng2-file-upload 不使用 Angular 的 http 服务,因此 MSAL 拦截器不会接收调用,因此不会自动将访问令牌添加到 Authorization 标头中。跨度>
【解决方案4】:
  1. HTML

    <div class="form-group">
      <label for="file">Choose File</label><br /> <input type="file" id="file" (change)="uploadFiles($event.target.files)">
    </div>

    <button type="button" (click)="RequestUpload()">Ok</button>

  1. ts 文件
public formData = new FormData();
ReqJson: any = {};

uploadFiles( file ) {
        console.log( 'file', file )
        for ( let i = 0; i < file.length; i++ ) {
            this.formData.append( "file", file[i], file[i]['name'] );
        }
    }

RequestUpload() {
        this.ReqJson["patientId"] = "12"
        this.ReqJson["requesterName"] = "test1"
        this.ReqJson["requestDate"] = "1/1/2019"
        this.ReqJson["location"] = "INDIA"
        this.formData.append( 'Info', JSON.stringify( this.ReqJson ) )
            this.http.post( '/Request', this.formData )
                .subscribe(( ) => {                 
                });     
    }
  1. 后端 Spring(java 文件)

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

@Controller
public class Request {
    private static String UPLOADED_FOLDER = "c://temp//";

    @PostMapping("/Request")
    @ResponseBody
    public String uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("Info") String Info) {
        System.out.println("Json is" + Info);
        if (file.isEmpty()) {
            return "No file attached";
        }
        try {
            // Get the file and save it somewhere
            byte[] bytes = file.getBytes();
            Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
            Files.write(path, bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "Succuss";
    }
}

我们必须在C盘创建一个文件夹“temp”,然后这段代码将在控制台打印Json并将上传的文件保存在创建的文件夹中

【讨论】:

  • 我们如何检索该文件?你对此有什么指导吗?
  • 另外,我的 spring 服务器在 8080 上运行,而 angular 在 3000 上运行。现在,当我将 server_url 标记为 localhost:8080/api/uploadForm 时,它说不允许使用 cors!
  • byte[] bytes = file.getBytes();它将给出字节流..您可以将其转换为文件,对于 cors 问题您可以在 google 中找到解决方案
  • 如果用户在没有选择任何文件之前直接点击“确定”按钮,是否有可能返回没有选择文件的警报?`
  • @Siddharth 将此添加到您的弹簧控制器注释中:@CrossOrigin(origins = "localhost:8080")
【解决方案5】:

首先,您需要在 Angular 项目中设置 HttpClient。

打开src/app/app.module.ts文件,导入HttpClientModule,添加到模块的imports数组中,如下:

import { BrowserModule } from '@angular/platform-browser';  
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';  
import { AppComponent } from './app.component';  
import { HttpClientModule } from '@angular/common/http';

@NgModule({  
  declarations: [  
    AppComponent,  
  ],  
  imports: [  
    BrowserModule,  
    AppRoutingModule,  
    HttpClientModule  
  ],  
  providers: [],  
  bootstrap: [AppComponent]  
})  
export class AppModule { }

接下来,生成一个组件:

$ ng generate component home

接下来,生成一个上传服务:

$ ng generate service upload

接下来打开src/app/upload.service.ts文件如下:

import { HttpClient, HttpEvent, HttpErrorResponse, HttpEventType } from  '@angular/common/http';  
import { map } from  'rxjs/operators';

@Injectable({  
  providedIn: 'root'  
})  
export class UploadService { 
    SERVER_URL: string = "https://file.io/";  
    constructor(private httpClient: HttpClient) { }
    public upload(formData) {

      return this.httpClient.post<any>(this.SERVER_URL, formData, {  
         reportProgress: true,  
         observe: 'events'  
      });  
   }
}

接下来,打开 src/app/home/home.component.ts 文件,首先添加以下导入:

import { Component, OnInit, ViewChild, ElementRef  } from '@angular/core';
import { HttpEventType, HttpErrorResponse } from '@angular/common/http';
import { of } from 'rxjs';  
import { catchError, map } from 'rxjs/operators';  
import { UploadService } from  '../upload.service';

接下来,定义fileUpload和files变量并注入UploadService如下:

@Component({  
  selector: 'app-home',  
  templateUrl: './home.component.html',  
  styleUrls: ['./home.component.css']  
})  
export class HomeComponent implements OnInit {
    @ViewChild("fileUpload", {static: false}) fileUpload: ElementRef;files  = [];  
    constructor(private uploadService: UploadService) { }

接下来,定义uploadFile()方法:

uploadFile(file) {  
    const formData = new FormData();  
    formData.append('file', file.data);  
    file.inProgress = true;  
    this.uploadService.upload(formData).pipe(  
      map(event => {  
        switch (event.type) {  
          case HttpEventType.UploadProgress:  
            file.progress = Math.round(event.loaded * 100 / event.total);  
            break;  
          case HttpEventType.Response:  
            return event;  
        }  
      }),  
      catchError((error: HttpErrorResponse) => {  
        file.inProgress = false;  
        return of(`${file.data.name} upload failed.`);  
      })).subscribe((event: any) => {  
        if (typeof (event) === 'object') {  
          console.log(event.body);  
        }  
      });  
  }

接下来,定义uploadFiles()方法,可以用来上传多个图片文件:

private uploadFiles() {  
    this.fileUpload.nativeElement.value = '';  
    this.files.forEach(file => {  
      this.uploadFile(file);  
    });  
}

接下来,定义 onClick() 方法:

onClick() {  
    const fileUpload = this.fileUpload.nativeElement;fileUpload.onchange = () => {  
    for (let index = 0; index < fileUpload.files.length; index++)  
    {  
     const file = fileUpload.files[index];  
     this.files.push({ data: file, inProgress: false, progress: 0});  
    }  
      this.uploadFiles();  
    };  
    fileUpload.click();  
}

接下来,我们需要创建图片上传 UI 的 HTML 模板。打开 src/app/home/home.component.html 文件,添加如下内容:

<div [ngStyle]="{'text-align':center; 'margin-top': 100px;}">
   <button mat-button color="primary" (click)="fileUpload.click()">choose file</button>  
   <button mat-button color="warn" (click)="onClick()">Upload</button>  
   <input [hidden]="true" type="file" #fileUpload id="fileUpload" name="fileUpload" multiple="multiple" accept="image/*" />
</div>

看看这个tutorial和这个post

【讨论】:

    【解决方案6】:

    好的,由于该线程出现在 google 的第一个结果中,并且对于其他有相同问题的用户,您不必像 trueboroda 所指出的那样重新启动轮子,有 ng2-file-upload 库可以简化此过程上传 Angular 6 和 7 的文件,您需要做的就是:

    安装最新的 Angular CLI

    yarn add global @angular/cli
    

    然后出于兼容性考虑安装 rx-compat

    npm install rxjs-compat --save
    

    安装 ng2-file-upload

    npm install ng2-file-upload --save
    

    在您的模块中导入 FileSelectDirective 指令。

    import { FileSelectDirective } from 'ng2-file-upload';
    
    Add it to [declarations] under @NgModule:
    declarations: [ ... FileSelectDirective , ... ]
    

    在您的组件中

    import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
    ...
    
    export class AppComponent implements OnInit {
    
       public uploader: FileUploader = new FileUploader({url: URL, itemAlias: 'photo'});
    }
    

    模板

    <input type="file" name="photo" ng2FileSelect [uploader]="uploader" />
    

    为了更好地理解,您可以查看此链接: How To Upload a File With Angular 6/7

    【讨论】:

    • 感谢您的链接。上传在桌面上工作正常,但我不能在我的生活中让上传在 iOS 等移动设备上工作。我可以从相机胶卷中选择一个文件,但是当我上传时它总是失败。有任何想法吗?仅供参考,在移动 safari 中运行,而不是在已安装的应用程序中运行。
    • 嗨@ScottN,不客气,也许问题出在您使用的浏览器上?你用另一个测试过吗?
    • 嗨@Mohamed Makkaoui 感谢您的回复。我确实在 iOS 上的 Chrome 中尝试过,结果仍然相同。我很好奇这是否是发布到服务器时的标题问题?我使用的是用 .Net 编写的自定义 WebAPI,而不是 AWS 仅供参考。
    • 嗨@ScottN,在您使用此链接developers.google.com/web/tools/chrome-devtools/… 调试代码并查看您收到什么错误消息之前,我们无法知道这是否是标头问题。
    • 另一方面,你不需要一个包来实现一个简单的文件上传。 API 应有尽有,您无需重新发明任何东西。
    【解决方案7】:

    我正在使用 Angular 5.2.11, 我喜欢 Gregor Doroschenko 提供的解决方案,但是我注意到上传的文件是零字节,我必须做一些小改动才能让它为我工作。

    postFile(fileToUpload: File): Observable<boolean> {
      const endpoint = 'your-destination-url';
      return this.httpClient
        .post(endpoint, fileToUpload, { headers: yourHeadersConfig })
        .map(() => { return true; })
        .catch((e) => this.handleError(e));
    }
    

    以下行 (formData) 对我不起作用。

    const formData: FormData = new FormData();
    formData.append('fileKey', fileToUpload, fileToUpload.name);
    

    https://github.com/amitrke/ngrke/blob/master/src/app/services/fileupload.service.ts

    【讨论】:

      【解决方案8】:

      就我个人而言,我在前端使用ngx-material-file-input,在后端使用Firebase。更准确地说是 Cloud Storage for Firebase 用于与 Cloud Firestore 结合的后端。下面的示例将文件限制为不大于 20 MB,并且仅接受某些文件扩展名。我也使用Cloud Firestore 来存储上传文件的链接,但你可以跳过这个。

      contact.component.html

      <mat-form-field>
        <!--
          Accept only files in the following format: .doc, .docx, .jpg, .jpeg, .pdf, .png, .xls, .xlsx. However, this is easy to bypass, Cloud Storage rules has been set up on the back-end side.
        -->
        <ngx-mat-file-input
          [accept]="[
            '.doc',
            '.docx',
            '.jpg',
            '.jpeg',
            '.pdf',
            '.png',
            '.xls',
            '.xlsx'
          ]"
          (change)="uploadFile($event)"
          formControlName="fileUploader"
          multiple
          aria-label="Here you can add additional files about your project, which can be helpeful for us."
          placeholder="Additional files"
          title="Additional files"
          type="file"
        >
        </ngx-mat-file-input>
        <mat-icon matSuffix>folder</mat-icon>
        <mat-hint
          >Accepted formats: DOC, DOCX, JPG, JPEG, PDF, PNG, XLS and XLSX,
          maximum files upload size: 20 MB.
        </mat-hint>
        <!--
          Non-null assertion operators are required to let know the compiler that this value is not empty and exists.
        -->
        <mat-error
          *ngIf="contactForm.get('fileUploader')!.hasError('maxContentSize')"
        >
          This size is too large,
          <strong
            >maximum acceptable upload size is
            {{
              contactForm.get('fileUploader')?.getError('maxContentSize')
                .maxSize | byteFormat
            }}</strong
          >
          (uploaded size:
          {{
            contactForm.get('fileUploader')?.getError('maxContentSize')
              .actualSize | byteFormat
          }}).
        </mat-error>
      </mat-form-field>
      

      contact.component.ts(尺寸验证器部分)

      import { FileValidator } from 'ngx-material-file-input';
      import { FormBuilder, FormGroup, Validators } from '@angular/forms';
      
      /**
       * @constructor
       * @description Creates a new instance of this component.
       * @param  {formBuilder} - an abstraction class object to create a form group control for the contact form.
       */
      constructor(
        private angularFirestore: AngularFirestore,
        private angularFireStorage: AngularFireStorage,
        private formBuilder: FormBuilder
      ) {}
      
      public maxFileSize = 20971520;
      public contactForm: FormGroup = this.formBuilder.group({
          fileUploader: [
            '',
            Validators.compose([
              FileValidator.maxContentSize(this.maxFileSize),
              Validators.maxLength(512),
              Validators.minLength(2)
            ])
          ]
      })
      

      contact.component.ts(文件上传器部分)

      import { AngularFirestore } from '@angular/fire/firestore';
      import {
        AngularFireStorage,
        AngularFireStorageReference,
        AngularFireUploadTask
      } from '@angular/fire/storage';
      import { catchError, finalize } from 'rxjs/operators';
      import { throwError } from 'rxjs';
      
      public downloadURL: string[] = [];
      /**
      * @description Upload additional files to Cloud Firestore and get URL to the files.
         * @param {event} - object of sent files.
         * @returns {void}
         */
        public uploadFile(event: any): void {
          // Iterate through all uploaded files.
          for (let i = 0; i < event.target.files.length; i++) {
            const randomId = Math.random()
              .toString(36)
              .substring(2); // Create random ID, so the same file names can be uploaded to Cloud Firestore.
      
            const file = event.target.files[i]; // Get each uploaded file.
      
            // Get file reference.
            const fileRef: AngularFireStorageReference = this.angularFireStorage.ref(
              randomId
            );
      
            // Create upload task.
            const task: AngularFireUploadTask = this.angularFireStorage.upload(
              randomId,
              file
            );
      
            // Upload file to Cloud Firestore.
            task
              .snapshotChanges()
              .pipe(
                finalize(() => {
                  fileRef.getDownloadURL().subscribe((downloadURL: string) => {
                    this.angularFirestore
                      .collection(process.env.FIRESTORE_COLLECTION_FILES!) // Non-null assertion operator is required to let know the compiler that this value is not empty and exists.
                      .add({ downloadURL: downloadURL });
                    this.downloadURL.push(downloadURL);
                  });
                }),
                catchError((error: any) => {
                  return throwError(error);
                })
              )
              .subscribe();
          }
        }
      

      storage.rules

      rules_version = '2';
      service firebase.storage {
        match /b/{bucket}/o {
          match /{allPaths=**} {
              allow read; // Required in order to send this as attachment.
            // Allow write files Firebase Storage, only if:
            // 1) File is no more than 20MB
            // 2) Content type is in one of the following formats: .doc, .docx, .jpg, .jpeg, .pdf, .png, .xls, .xlsx.
            allow write: if request.resource.size <= 20 * 1024 * 1024
              && (request.resource.contentType.matches('application/msword')
              || request.resource.contentType.matches('application/vnd.openxmlformats-officedocument.wordprocessingml.document')
              || request.resource.contentType.matches('image/jpg')
              || request.resource.contentType.matches('image/jpeg')
              || request.resource.contentType.matches('application/pdf')
                      || request.resource.contentType.matches('image/png')
              || request.resource.contentType.matches('application/vnd.ms-excel')
              || request.resource.contentType.matches('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'))
          }
        }
      }
      

      【讨论】:

      • 看起来不错,但为什么在contactForm声明中需要toString()
      • @trungk18 再次检查它,你是对的 toString() 没用,编辑了我的答案。对于那些会阅读此评论的人,在 contact.component.tsfileUploader 的末尾我有 ])].toString()})。现在很简单:])]}).
      【解决方案9】:

      使用 Angular 和 nodejs(express) 上传文件的完整示例

      HTML 代码

                  <div class="form-group">
                      <label for="file">Choose File</label><br/>
                      <input type="file" id="file" (change)="uploadFile($event.target.files)" multiple>
                  </div>
      

      TS 组件代码

      uploadFile(files) {
          console.log('files', files)
              var formData = new FormData();
      
          for(let i =0; i < files.length; i++){
            formData.append("files", files[i], files[i]['name']);
              }
      
          this.httpService.httpPost('/fileUpload', formData)
            .subscribe((response) => {
              console.log('response', response)
            },
              (error) => {
            console.log('error in fileupload', error)
             })
        }
      

      Node Js 代码

      fileUpload API 控制器

      function start(req, res) {
      fileUploadService.fileUpload(req, res)
          .then(fileUploadServiceResponse => {
              res.status(200).send(fileUploadServiceResponse)
          })
          .catch(error => {
              res.status(400).send(error)
          })
      }
      
      module.exports.start = start
      

      使用 multer 上传服务

      const multer = require('multer') // import library
      const moment = require('moment')
      const q = require('q')
      const _ = require('underscore')
      const fs = require('fs')
      const dir = './public'
      
      /** Store file on local folder */
      let storage = multer.diskStorage({
      destination: function (req, file, cb) {
          cb(null, 'public')
      },
      filename: function (req, file, cb) {
          let date = moment(moment.now()).format('YYYYMMDDHHMMSS')
          cb(null, date + '_' + file.originalname.replace(/-/g, '_').replace(/ /g,     '_'))
      }
      })
      
      /** Upload files  */
      let upload = multer({ storage: storage }).array('files')
      
      /** Exports fileUpload function */
      module.exports = {
      fileUpload: function (req, res) {
          let deferred = q.defer()
      
          /** Create dir if not exist */
          if (!fs.existsSync(dir)) {
              fs.mkdirSync(dir)
              console.log(`\n\n ${dir} dose not exist, hence created \n\n`)
          }
      
          upload(req, res, function (err) {
              if (req && (_.isEmpty(req.files))) {
                  deferred.resolve({ status: 200, message: 'File not attached', data: [] })
              } else {
                  if (err) {
                      deferred.reject({ status: 400, message: 'error', data: err })
                  } else {
                      deferred.resolve({
                          status: 200,
                          message: 'File attached',
                          filename: _.pluck(req.files,
                              'filename'),
                          data: req.files
                      })
                  }
              }
          })
          return deferred.promise
      }
      }
      

      【讨论】:

      • httpService从何而来?
      • @James httpService 是 Angular 的 http 模块,用于对服务器进行 http 调用。你可以使用任何你想要的 http 服务。import { HttpClientModule } from '@angular/common/http';
      【解决方案10】:

      Angular 7/8/9

      来源Link

      使用引导表单

      <form>
          <div class="form-group">
              <fieldset class="form-group">
      
                  <label>Upload Logo</label>
                  {{imageError}}
                  <div class="custom-file fileInputProfileWrap">
                      <input type="file" (change)="fileChangeEvent($event)" class="fileInputProfile">
                      <div class="img-space">
      
                          <ng-container *ngIf="isImageSaved; else elseTemplate">
                              <img [src]="cardImageBase64" />
                          </ng-container>
                          <ng-template #elseTemplate>
      
                              <img src="./../../assets/placeholder.png" class="img-responsive">
                          </ng-template>
      
                      </div>
      
                  </div>
              </fieldset>
          </div>
          <a class="btn btn-danger" (click)="removeImage()" *ngIf="isImageSaved">Remove</a>
      </form>
      

      组件类

      fileChangeEvent(fileInput: any) {
          this.imageError = null;
          if (fileInput.target.files && fileInput.target.files[0]) {
              // Size Filter Bytes
              const max_size = 20971520;
              const allowed_types = ['image/png', 'image/jpeg'];
              const max_height = 15200;
              const max_width = 25600;
      
              if (fileInput.target.files[0].size > max_size) {
                  this.imageError =
                      'Maximum size allowed is ' + max_size / 1000 + 'Mb';
      
                  return false;
              }
      
              if (!_.includes(allowed_types, fileInput.target.files[0].type)) {
                  this.imageError = 'Only Images are allowed ( JPG | PNG )';
                  return false;
              }
              const reader = new FileReader();
              reader.onload = (e: any) => {
                  const image = new Image();
                  image.src = e.target.result;
                  image.onload = rs => {
                      const img_height = rs.currentTarget['height'];
                      const img_width = rs.currentTarget['width'];
      
                      console.log(img_height, img_width);
      
      
                      if (img_height > max_height && img_width > max_width) {
                          this.imageError =
                              'Maximum dimentions allowed ' +
                              max_height +
                              '*' +
                              max_width +
                              'px';
                          return false;
                      } else {
                          const imgBase64Path = e.target.result;
                          this.cardImageBase64 = imgBase64Path;
                          this.isImageSaved = true;
                          // this.previewImagePath = imgBase64Path;
                      }
                  };
              };
      
              reader.readAsDataURL(fileInput.target.files[0]);
          }
      }
      
      removeImage() {
          this.cardImageBase64 = null;
          this.isImageSaved = false;
      }
      

      【讨论】:

      • 能否请您告诉我文件是否保存在本地文件夹中?
      • 老同学!好的!
      【解决方案11】:

      这是我上传 excel 文件的方法:
      目录结构:

      app
      |-----uploadcomponent
                 |-----uploadcomponent.module.ts
                 |-----uploadcomponent.html
      |-----app.module.ts
      |-----app.component.ts
      |-----app.service.ts
      

      上传组件.html

      <div>
         <form [formGroup]="form" (ngSubmit)="onSubmit()">
           <input type="file" name="profile"  enctype="multipart/form-data" accept=".xlsm,application/msexcel" (change)="onChange($event)" />
           <button type="submit">Upload Template</button>
           <button id="delete_button" class="delete_button" type="reset"><i class="fa fa-trash"></i></button> 
         </form>           
      </div>
      

      上传组件.ts

          import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
          import { Component, OnInit } from '@angular/core';
          ....
          export class UploadComponent implements OnInit {
              form: FormGroup;
              constructor(private formBuilder: FormBuilder, private uploadService: AppService) {}
              ngOnInit() {  
                  this.form = this.formBuilder.group({
                     profile: ['']
                  });
              }
      
              onChange(event) {
                  if (event.target.files.length > 0) {
                    const file = event.target.files[0];
      
                    this.form.get('profile').setValue(file);
                    console.log(this.form.get('profile').value)
                  }
              }
      
              onSubmit() {
                 const formData = new FormData();
                 formData.append('file', this.form.get('profile').value);
      
                 this.uploadService.upload(formData).subscribe(
                   (res) => {
                     this.response = res;
      
                     console.log(res);
      
                   },
                   (err) => {  
                     console.log(err);
                   });
               }
          }
      

      app.service.ts

          upload(formData) {
              const endpoint = this.service_url+'upload/';
              const httpOptions = headers: new HttpHeaders({    <<<< Changes are here
                  'Authorization': 'token xxxxxxx'})
              };
              return this.http.post(endpoint, formData, httpOptions);
          }
      

      在后端我使用 DJango REST 框架。
      模型.py

      from __future__ import unicode_literals
      from django.db import models
      from django.db import connection
      from django_mysql.models import JSONField, Model
      import uuid
      import os
      
      
      def change_filename(instance, filename):
          extension = filename.split('.')[-1]
          file_name = os.path.splitext(filename)[0]
          uuid_name = uuid.uuid4()
          return file_name+"_"+str(uuid_name)+"."+extension
      
      class UploadTemplate (Model):
          id = models.AutoField(primary_key=True)
          file = models.FileField(blank=False, null=False, upload_to=change_filename)
      
          def __str__(self):
              return str(self.file.name)
      

      views.py.

      class UploadView(APIView):
          serializer_class = UploadSerializer
          parser_classes = [MultiPartParser]       
      
          def get_queryset(self):
              queryset = UploadTemplate.objects.all()
              return queryset
      
          def post(self, request, *args, **kwargs):
              file_serializer = UploadSerializer(data=request.data)
              status = None
              message = None
              if file_serializer.is_valid():
                  file_serializer.save()
                  status = "Success"
                  message = "Success"
              else:
                  status = "Failure"
                  message = "Failure!"
              content = {'status': status, 'message': message}
              return Response(content)
      

      serializers.py.

      from uploadtemplate.models import UploadTemplate
      from rest_framework import serializers
      
      class UploadSerializer(serializers.ModelSerializer):
          class Meta:
              model = UploadTemplate
              fields = '__all__'   
      

      urls.py.

      router.register(r'uploadtemplate', uploadtemplateviews.UploadTemplateView, 
          base_name='UploadTemplate')
      urlpatterns = [
          ....
          url(r'upload/', uploadtemplateviews.UploadTemplateView.as_view()),
      ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
      
      if settings.DEBUG:
          urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
      

      MEDIA_URL 和 MEDIA_ROOT 在项目的 settings.py 中定义。

      谢谢!

      【讨论】:

        【解决方案12】:

        试试这个

        安装

        npm install primeng --save
        

        导入

        import {FileUploadModule} from 'primeng/primeng';
        

        HTML

        <p-fileUpload name="myfile[]" url="./upload.php" multiple="multiple"
            accept="image/*" auto="auto"></p-fileUpload>
        

        【讨论】:

        • 我厌倦了使用上面的例子。但我得到 ./upload.php not found.
        • 你应该提供你的 URL 应该被加载而不是 upload.php @sandeep kamath
        • @Vignesh 感谢您的回复。但是我发现我根本没有给出url属性它加载文件,应该是默认的。
        • 如果我们用这种方法,你能解释一下如何在php中接收文件。
        【解决方案13】:

        create-profile.html

        <body>
          <h1 class="font-weight-bold" >Create Advertistment</h1>
          <hr />
          <form [formGroup]="form" (submit)="onSubmit()">
            <div>
              <label class="font-weight-bold">Insert Subject name</label>
              <br>
              <input formControlName="name" type="text" placeholder="Enter name..." />
            </div>
            <div>
              <br>
              <label class="font-weight-bold">Select the Advertistment</label>
              <br>
              <input (change)="onFileSelect($event)" type="file" />
            </div>
            <br>
            <!--<div *ngIf="imageData">
              <img [src]="imageData" [alt]="form.value.name" />
            </div>-->
            <div>
        
              <label class="font-weight-bold">Upload the Advertistment</label>
              <br>
              <button type="submit" class="btn btn-success" >Upload Advertistment</button>
            </div>
          </form>
        
          </body>
        

        create-profile.ts

        import { Component, OnInit } from "@angular/core";
        import { FormGroup, FormControl } from "@angular/forms";
        
        import { Profile } from "../../models/Profile";
        import { ProfileService } from "src/app/services/profile.service";
        
        @Component({
          selector: "app-create-profile",
          templateUrl: "./create-profile.component.html",
          styleUrls: ["./create-profile.component.css"],
        })
        export class CreateProfileComponent implements OnInit {
          form: FormGroup;
          profile: Profile;
          imageData: string;
        
          constructor(private profileService: ProfileService) {}
        
          ngOnInit(): void {
            this.form = new FormGroup({
              name: new FormControl(null),
              image: new FormControl(null),
            });
          }
        
          onFileSelect(event: Event) {
            const file = (event.target as HTMLInputElement).files[0];
            this.form.patchValue({ image: file });
            const allowedMimeTypes = ["image/png", "image/jpeg", "image/jpg"];
            if (file && allowedMimeTypes.includes(file.type)) {
              const reader = new FileReader();
              reader.onload = () => {
                this.imageData = reader.result as string;
              };
              reader.readAsDataURL(file);
            }
          }
        
          onSubmit() {
            this.profileService.addProfile(this.form.value.name, this.form.value.image);
            this.form.reset();
            this.imageData = null;
          }
        }
        

        profile.service.ts

        import { Injectable } from "@angular/core";
        import { HttpClient } from "@angular/common/http";
        
        import { map } from "rxjs/operators";
        
        import { Profile } from "../models/Profile";
        import { Subject } from "rxjs";
        
        @Injectable({
          providedIn: "root",
        })
        export class ProfileService {
          private profiles: Profile[] = [];
          private profiles$ = new Subject<Profile[]>();
          readonly url = "http://localhost:3000/api/profiles";
        
          constructor(private http: HttpClient) {}
        
          getProfiles() {
            this.http
              .get<{ profiles: Profile[] }>(this.url)
              .pipe(
                map((profileData) => {
                  return profileData.profiles;
                })
              )
              .subscribe((profiles) => {
                this.profiles = profiles;
                this.profiles$.next(this.profiles);
              });
          }
        
          getProfilesStream() {
            return this.profiles$.asObservable();
          }
        
          addProfile(name: string, image: File): void {
            const profileData = new FormData();
            profileData.append("name", name);
            profileData.append("image", image, name);
            this.http
              .post<{ profile: Profile }>(this.url, profileData)
              .subscribe((profileData) => {
                const profile: Profile = {
                  _id: profileData.profile._id,
                  name: name,
                  imagePath: profileData.profile.imagePath,
                };
                this.profiles.push(profile);
                this.profiles$.next(this.profiles);
              });
          }
        }
        

        Profile.ts

        export interface Profile {
          _id: string;
          name: string;
          imagePath: string;
        }
        

        【讨论】:

          【解决方案14】:

          就我而言,我使用的是 http 拦截器,事情是默认情况下我的 http 拦截器将 content-type 标头设置为 application/json,但对于文件上传,我使用的是 multer 库。 稍微改变一下我的 http.interceptor 就定义了请求正文是否是 FormData ,它会删除标头并且不会触及访问令牌。 这是部分代码,这让我很开心。

          if (request.body instanceof FormData) {
            request = request.clone({ headers: request.headers.delete('Content-Type', 'application/json') });
          }
          
          if (request.body instanceof FormData) {
            request = request.clone({ headers: request.headers.delete('Accept', 'application/json')});
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-12-30
            • 2015-11-20
            • 2020-12-02
            • 1970-01-01
            • 2015-03-24
            • 2014-11-16
            • 2019-05-08
            • 2015-10-02
            相关资源
            最近更新 更多