【问题标题】:How to make FileReader work with Angular2?如何使 FileReader 与 Angular2 一起工作?
【发布时间】:2015-06-14 14:01:19
【问题描述】:

如何使 FileReader 与 Angular2 一起工作!!

当使用 Angular2 和 Typescript 从客户端读取文件时,

我尝试以这种方式使用 FileReader:

var fileReader = new FileReader();
fileReader.onload = function(e) {
    console.log("run fileReader.onload");
   //  ......
}

但它根本不起作用,这个'fileReader.onload'函数永远不会被调用。

真的需要一个读取文件的解决方案,请帮助。 谢谢

从在线 IDE 中检查:

预览: https://angular2-butaixianran.c9.io/src/index.html

编辑: https://ide.c9.io/butaixianran/angular2

【问题讨论】:

    标签: javascript angular


    【解决方案1】:

    首先你必须在模板的输入表单上指定更改事件的目标:

    @View({
      template:`
        <div>
          Select file:
          <input type="file" (change)="changeListener($event)">
        </div>
      `
    })
    

    如您所见,我将changeListener() 方法绑定到(change) 事件。我的类实现:

      changeListener($event) : void {
        this.readThis($event.target);
      }
    
      readThis(inputValue: any) : void {
        var file:File = inputValue.files[0]; 
        var myReader:FileReader = new FileReader();
    
        myReader.onloadend = function(e){
          // you can perform an action with readed data here
          console.log(myReader.result);
        }
    
        myReader.readAsText(file);
      }
    

    监听器正在将文件从事件传递到readThis 方法。阅读这个已经实现了它自己的FileReader。您也可以在组件中而不是在函数中定义 FileReader。

    【讨论】:

    • readThis(inputValue: any) : void { var file:File = inputValue.files[0]; var myReader:FileReader = new FileReader(); ...效果也很好..我认为看起来更干净..非常感谢
    • 这行得通,很好,但我想补充一点。出于某种原因(至少在我的情况下),如果您仅在“changeListener”方法中进行所有工作,这将不起作用。出于某种原因(我不知道),如果您在 changeListener 中使用“myReader.onloadend(...)”,它将永远不会被触发。
    • @haz111 这 readAsText() 是否返回任何文件的 base64?我想对上传的文件进行base64encode
    【解决方案2】:

    来自@haz111 的回答已经有效,但如果你想让文件阅读器成为可重用的组件,你可以使用这个或更好:改进这个:

    inputfilereader.ts

    import {Component, ElementRef, EventEmitter} from 'angular2/angular2';
    
    @Component({
        selector: 'filereader',
        templateUrl: './commons/inputfilereader/filereader.html',
        styleUrls: ['./commons/inputfilereader/filereader.css'],
        providers: [ElementRef],
        events : ['complete']
    })
    
    export class InputFileReader {
        complete :EventEmitter = new EventEmitter();
    
        constructor(public elementRef: ElementRef) {
        }
    
        resultSet:any; // dont need it 
    
        changeListener($event: any) {
            var self = this;
            var file:File = $event.target.files[0];
            var myReader:FileReader = new FileReader();
            myReader.readAsText(file);
            var resultSet = [];
            myReader.onloadend = function(e){
                // you can perform an action with data read here
                // as an example i am just splitting strings by spaces
                var columns = myReader.result.split(/\r\n|\r|\n/g);
    
                for (var i = 0; i < columns.length; i++) {
                    resultSet.push(columns[i].split(' '));
                }
    
                self.resultSet=resultSet; // probably dont need to do this atall
                self.complete.next(self.resultSet); // pass along the data which would be used by the parent component
            };
        }
    }
    

    filereader.html

    <input type="file" (change)="changeListener($event)" />
    

    在其他文件中的使用

    另一个文件让我们说 dfs.ts

    import {Component, ElementRef} from 'angular2/angular2';
    import {InputFileReader} from '../../commons/inputfilereader/inputfilereader';
    
    @Component({
        selector: 'dfs',
        templateUrl: './components/dfs/dfs.html',
        styleUrls: ['./components/dfs/dfs.css'],
        providers: [ElementRef],
        directives:[InputFileReader]
    })
    
    export class DfsCmp {
        constructor(public eleRef :ElementRef) {}
    
        callSomeFunc(data):void {
            console.log("I am being called with ", data);
        }
    }
    

    dfs.html

    <filereader (complete)="callSomeFunc($event)"></filereader> 
    

    【讨论】:

      【解决方案3】:

      在这里聚会有点晚了。这也可以通过将 FileReader 创建为服务来完成。这将有助于单元测试,并将 FileReader 与使用它的组件分离。

      您可以像这样创建令牌:

      export const FileReaderService = new InjectionToken<FileReader>('FileReader', {
        factory: () => new FileReader(),
      });
      

      然后你可以像这样使用它: (我相信它可以用作常规服务。我还没有测试过。但是我在这里展示的方式很好用)

      class MyService { // this could be a component too
        constructor(@Inject(FileReaderService) private reader: FileReader) {}
        readFile() {
          const file = // the file you want to read
          this.reader.onload = // whateever you need
          this.reader.readAsDataURL(file)
        }
      }
      

      【讨论】:

        【解决方案4】:

        我会创建一个类似下面的方法

        readFileContent(file: File): Promise<string | ArrayBuffer> {
            return new Promise<string | ArrayBuffer>((resolve, reject) => {
        
              const myReader: FileReader = new FileReader();
        
              myReader.onloadend = (e) => {
                resolve(myReader.result);
              };
        
              myReader.onerror = (e) => {
                reject(e);
              };
        
              myReader.readAsText(file);
            });
          }
        

        然后这样称呼它

        const content = await this.readFileContent(inputValue.files[0])
        

        【讨论】:

          【解决方案5】:

          只需添加

          fr.readAsText(event.files[0]);
          

          onLoad 定义之后。

          也许这对你有帮助,这是我的primeng文件上传库的上传处理函数

          archivoUploadHandler(event) {
            let contenido;
            let fr = new FileReader();
            fr.onload = (e) => {
              contenido = fr.result;
              console.log(contenido);
            };
            fr.readAsText(event.files[0]);
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-07-22
            • 1970-01-01
            • 1970-01-01
            • 2016-09-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-09-30
            相关资源
            最近更新 更多