1
votes

I'm trying to make a directive similar to ng-model to work with file inputs. I am new to AngularDart so don't really know how to go about doing this.

Here is some code I managed to write by looking at the ng-model source files but it (obviously) doesn't work.

  @Decorator(
      selector: 'input[type=file][file-model]',
      map: const {'file-model': '&filesSelected'})
  class FileModel {
    final InputElement inputElement;
    String expression;
    final Scope scope;
    String _inputType;
    List<File> files;
    var filesSelected;

    FileModel(this.inputElement, this.scope, NodeAttrs attrs) {

      expression = attrs["file-model"];

      inputElement.onChange.listen((event) {
        files = inputElement.files;
        filesSelected(files);
      });
    }
  }

Any suggestions?

2
There was an attempt to implement this github.com/angular/angular.dart/issues/1094 (discussion only)Günter Zöchbauer
What doesn't work? Do you get some error message or is it like you didn't apply the decorator at all? When I look at github.com/angular/angular.dart/blob/… it looks quite a bit different.Günter Zöchbauer
Yes it does look quite different that's why it took me a long time to understand it enough to write the code that I did. But I don't know how to continue. How do you alert the callback function e.g. file-model="cmp.filesAdded(files)" or update a variable e.g. file-model="cmp.files". Personally I think the callback is better but have no idea how to implement that. The "expression" variable in my code holds the callback function as a string but I don't know how to evaluate it.andrei

2 Answers

3
votes

I've got it working.

@Decorator(
    selector: 'input[type=file][file-model]',
    map: const {'file-model': '&filesSelected'})
class FileModel {
  Element inputElement;
  String expression;
  final Scope scope;
  String _inputType;
  List<File> files;
  var listeners = {};

  FileModel(this.inputElement, this.scope) {
  }

  initListener(var stream, var handler) {
    int key = stream.hashCode;
    if (!listeners.containsKey(key)) {
      listeners[key] = handler;
      stream.listen((event) => handler({r"files": (inputElement as InputElement).files}));
    }
  }

  set filesSelected(value)  =>  initListener(inputElement.onChange, value);
}

Usage: <input type="file" multiple file-model="cmp.filesSelected(files)">
0
votes

For getting the files upon the change event, you can also just pass them via $event.target.files. Example:

import 'package:angular2/core.dart';

@Component(
    selector: 'my-app', 
    template: r'''
        <h1>{{title}}</h1>
        <input class="btn" type="file" (change)="onFileUpload($event.target.files)">
    ''')
class AppComponent {
    String title = 'File transfer';

    onFileUpload(List<File> files) {
        if (files == null) return;
        // read file content as dataURL
        final File file = files[0];
        final FileReader reader = new FileReader();
        reader.onLoad.listen((_) {
            print(reader.result);
        });
        reader.readAsDataUrl(file);
    }
}