Ionic 2 (beta 6) / Angular 2 - Styled Upload / Attachment compoment

According to this issue: github.com/driftyco/ionic/issues/6628 we needed a solution to the problem. It ended up in a little custom component. Maybe this will be a temporary solution to others too or it could be basis for an ionic included solution.

Attention: As this was my first typescript, angular 2 component and also the first project with these tools, please be merciful if it includes bad practices or other mistakes. It is more a first draft than a final solution. Any improvements and fixes are welcome. We used the common practice for this styling issues and translate it to Angular. A hidden input element combined with a button doing the work.

Usage is simple just use the newly created tag ant tell it which ionic icon to use for the button. Also a callback must be defined which is executed after files are selected (FileList is passsed as parameter to it):

<upload-button [btnCallback]="addCallback" [btnStyle]="icon"></upload-button>
import {IONIC_DIRECTIVES} from "ionic-angular";
import {Component, ElementRef, Input, Inject, ViewChild, Renderer} from "angular2/core";
import {Log} from "../../log";

@Component({
  directives: [IONIC_DIRECTIVES],
  selector: "upload-button",
  template: `<button (click)="callback($event)" clear>
               <ion-icon name="{{btnStyle}}"></ion-icon>
             </button>
             <input type="file" (change)="filesAdded($event)" style="display: none" multiple #input />`
})

/**
 * Upload button component.
 *
 * As native input elements with type file are diffcult to style, it is common
 * practice to hide them and trigger the needed events manually as it done here.
 * A button is is used for user interaction, next to the hidden input.
 */
export class UploadButton {

  /**
   * The callback executed when button pressed, set by parent
   */
  @Input()
  private btnStyle: String;

  /**
   * The callback executed when files are selected, set by parent
   */
  @Input()
  private btnCallback: Function;

  /**
   * Native upload button (hidden)
   */
  @ViewChild("input")
  private nativeInputBtn: ElementRef;

  /**
   * Constructor
   * @param  {Renderer} renderer for invoking native methods
   * @param  {Log}      logger instance
   */
  constructor(private renderer: Renderer, @Inject(Log) private logger: Log) {}

  /**
   * Callback executed when the visible button is pressed
   * @param  {Event}  event should be a mouse click event
   */
  public callback(event: Event): void {
    this.logger.debug("upload-button callback executed");

    // trigger click event of hidden input
    let clickEvent: MouseEvent = new MouseEvent("click", {bubbles: true});
    this.renderer.invokeElementMethod(
        this.nativeInputBtn.nativeElement, "dispatchEvent", [clickEvent]);
  }

  /**
   * Callback which is executed after files from native popup are selected.
   * @param  {Event}    event change event containing selected files
   */
  public filesAdded(event: Event): void {
    let files: FileList = this.nativeInputBtn.nativeElement.files;
    this.logger.debug("Added files", files);
    this.btnCallback(files);
  }
}

3 comments: