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


当前回答

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

打开src/app/app.module。导入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>

看看这篇教程和这篇文章

其他回答

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

通过npm安装ng2-file-upload。NPM I ng2-file-upload——保存

首先在模块中导入模块。

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 });

这是最简单的用法。要知道所有的权力,这看到演示

使用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代码

上传火灾控制器

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
}
}

下面是一个上传文件到api的例子:

步骤1:HTML模板

定义文件类型的简单输入标记。为(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中处理上传

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

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);
      });
  }

第三步:文件上传服务

通过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));
}

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

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;
}

在我的情况下,我使用http拦截器,事情是,默认情况下,我的http拦截器设置内容类型头为应用程序/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')});
}