web-dev-qa-db-ja.com

<input type = "file">からのファイルのアップロード

角度2のベータ版を使用して、私は<input type="file">を働かせることができないようです。

Diagnosticを使用して、typeなどの他のtextに対する双方向バインディングを確認できます。

<form>
    {{diagnostic}}
    <div class="form-group">
        <label for="fileupload">Upload</label>
        <input type="file" class="form-control" [(ngModel)]="model.fileupload">
    </div>
</form>

TypeScriptファイルには、次のような診断行があります。

get diagnostic() { return JSON.stringify(this.model); }

それはJSONではないという問題であるということでしょうか。値はnullです。

inputの値を本当に検証できません。 「Choose file ...」の横のテキストが更新されても、何らかの理由でDOMの違いがわかりません。

61
PascalVKooten

サポートされていないと思います。このDefaultValueAccessorディレクティブをご覧ください( https://github.com/angular/angular/blob/master/modules/angular2/src/common/forms/directives/default_value_accessor.ts#L23を参照 =)。バインドされた要素を更新するために使用される値が$event.target.valueであることがわかります。

代わりにファイルオブジェクトが$event.srcElement.filesに達することができるので、これはタイプfileの入力の場合には当てはまりません。

詳細については、このplunkrを見てみることができます: https://plnkr.co/edit/ozZqbxIorjQW15BrDFrg?p=info

@Component({
  selector: 'my-app',
  template: `
    <div>
      <input type="file" (change)="onChange($event)"/>
    </div>
  `,
  providers: [ UploadService ]
})
export class AppComponent {
  onChange(event) {
    var files = event.srcElement.files;
    console.log(files);
  }
}
67
@Component({
  selector: 'my-app',
  template: `
    <div>
      <input name="file" type="file" (change)="onChange($event)"/>
    </div>
  `,
  providers: [ UploadService ]
})
export class AppComponent {
  file: File;
  onChange(event: EventTarget) {
        let eventObj: MSInputMethodContext = <MSInputMethodContext> event;
        let target: HTMLInputElement = <HTMLInputElement> eventObj.target;
        let files: FileList = target.files;
        this.file = files[0];
        console.log(this.file);
    }

   doAnythingWithFile() {
   }

}
39
Ashish Doneriya

添付ファイルにアクセスするためのもう少し良い方法があります。入力要素のインスタンスを取得するには、 テンプレート参照変数 を使用できます。

これは最初の答えに基づく例です:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <input type="file" #file (change)="onChange(file.files)"/>
    </div>
  `,
  providers: [ UploadService ]
})

export class AppComponent {
  onChange(files) {
    console.log(files);
  }
}

これが実際に動作していることを示すための サンプルアプリ です。

テンプレート参照変数は便利かもしれません。あなたはコントローラの中で直接@ViewChildを通してそれらにアクセスすることができました。

28
Frelseren

Frelserenによって提案されているように、テンプレート参照変数とViewChildを使用する別の方法:

import { ViewChild } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <input type="file" #fileInput/>
    </div>
  `
})  
export class AppComponent {
  @ViewChild("fileInput") fileInputVariable: any;
  randomMethod() {
    const files = this.fileInputVariable.nativeElement.files;
    console.log(files);
  }
}

https://stackoverflow.com/a/40165524/4361955 もご覧ください。

5
jhujhul

この小さなライブラリを試してください。Angular 5.0.0で動作します

Ng2-file-upload 1.3.0を使ったクイックスタートの例:

ユーザーがカスタムボタンをクリックすると、非表示の入力タイプ= "ファイル"からアップロードダイアログが表示され、単一のファイルを選択すると自動的にアップロードが開始されます。

app.module.ts:

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

your.component.html:

...
  <button mat-button onclick="document.getElementById('myFileInputField').click()" >
    Select and upload file
  </button>
  <input type="file" id="myFileInputField" ng2FileSelect [uploader]="uploader" style="display:none">
...

your.component.ts:

import {FileUploader} from 'ng2-file-upload';
...    
uploader: FileUploader;
...
constructor() {
   this.uploader = new FileUploader({url: "/your-api/some-endpoint"});
   this.uploader.onErrorItem = item => {
       console.error("Failed to upload");
       this.clearUploadField();
   };
   this.uploader.onCompleteItem = (item, response) => {
       console.info("Successfully uploaded");
       this.clearUploadField();

       // (Optional) Parsing of response
       let responseObject = JSON.parse(response) as MyCustomClass;

   };

   // Asks uploader to start upload file automatically after selecting file
  this.uploader.onAfterAddingFile = fileItem => this.uploader.uploadAll();
}

private clearUploadField(): void {
    (<HTMLInputElement>window.document.getElementById('myFileInputField'))
    .value = "";
}

代わりのlib、Angular 4.2.4で動作しますが、Angular 5.0.0に採用するにはいくつかの回避策が必要です。

2
Yurii Bratchuk

複数のファイルや他の入力を含む複雑なフォームがある場合は、ここでngModelを使用するとよい解決策になります。

これは、単純なファイル入力をラップし、それをControlValueAccessorで消費できるようにするためのngModelインターフェースを実装するファイル入力コンポーネントで構成されています。コンポーネントはFileListオブジェクトをngModelに公開します。

この解決策は this 記事に基づいています。

コンポーネントは次のように使用されています。

<file-input name="file" inputId="file" [(ngModel)]="user.photo"></file-input>
<label for="file"> Select file </label>

これがコンポーネントコードです。

import { Component, Input, forwardRef } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';

const noop = () => {
};

export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => FileInputComponent),
    multi: true
};

@Component({
  selector: 'file-input',
  templateUrl: './file-input.component.html',
  providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class FileInputComponent {

  @Input()
  public name:string;

  @Input()
  public inputId:string;

  private innerValue:any;

  constructor() { }

  get value(): FileList {
    return this.innerValue;
  };

  private onTouchedCallback: () => void = noop;
  private onChangeCallback: (_: FileList) => void = noop;

  set value(v: FileList) {
    if (v !== this.innerValue) {
      this.innerValue = v;
      this.onChangeCallback(v);
    }
  }

  onBlur() {
    this.onTouchedCallback();
  }

  writeValue(value: FileList) {
    if (value !== this.innerValue) {
      this.innerValue = value;
    }
  }

  registerOnChange(fn: any) {
    this.onChangeCallback = fn;
  }

  registerOnTouched(fn: any) {
    this.onTouchedCallback = fn;
  }

  changeFile(event) {
    this.value = event.target.files;
  }
}

これがコンポーネントテンプレートです。

<input type="file" name="{{ name }}" id="{{ inputId }}" multiple="multiple" (change)="changeFile($event)"/>
0
Jens

(onclick)="this.value = null"を試すだけ

あなたのHTMLページに以前の値を削除するためにonclickメソッドを追加するので、ユーザーは同じファイルを再び選択することができます。

0
yogesh chavan