Forms Support

You can use the FileSelect in template-driven or reactive forms.

The component supports the required built-in Angular validation and builds on top of that with custom restrictions for file extensions, minimum, and maximum file size.

Template-Driven Forms

The template-driven forms enable you to bind the FileSelect to the model by using the ngModel directive.

The following example demonstrates how to utilize the required validation and the restrictions configuration option. With these settings in place, the form will become valid when an image file is selected.

import { Component } from '@angular/core';
import { FileInfo, FileRestrictions } from '@progress/kendo-angular-upload';

@Component({
    selector: 'my-app',
    template: `
    <div class="example-config">
        <p>Valid: {{ myForm.valid }}</p>
        <p>Submitted: {{ myForm.submitted }}</p>
    </div>
    <form #myForm="ngForm" novalidate (ngSubmit)="save(myForm.value, myForm.valid)" class="example-wrapper">
        <div class="container-fluid">
        <div class="row">
            <div class="col-xs-12 col-sm-6">
            <label style="display: block; margin: .8em 0 .2em">Username:</label>
            <input type="text" name="uName" #uName="ngModel"
                [(ngModel)]="userName" required minlength="4"
                class="k-textbox" style="width: 100%" />
            <p style="color: red; font-size: .8em; margin-top: .5em;"
                [hidden]="uName.valid || (uName.pristine && !myForm.submitted)">
                Username is required and should be minimum 4 characters.
            </p>
            <label style="display: block; margin: .8em 0 .2em">Avatar:</label>
            <kendo-fileselect required
                name="myFileSelect" #myFileSelect="ngModel"
                [restrictions]="myRestrictions"
                [(ngModel)]="userImages">
            </kendo-fileselect>
            <p style="color: red; font-size: .8em; margin-top: .5em;"
            [hidden]="myFileSelect.valid || (myFileSelect.pristine && !myForm.submitted)">
                Selecting an avatar is required.
            </p>
            <button type="submit" class="k-button k-primary" style="margin: 1em 0;">Submit</button>
            </div>
        </div>
        </div>
    </form>
    `
})
export class AppComponent {
    public myRestrictions: FileRestrictions = {
        allowedExtensions: ['jpg', 'jpeg', 'png']
    };

    public userName: string;
    public userImages: Array<any>;

    save(_value: any, valid: boolean) {
        if (valid) {
            console.log('Everything is OK!');
        }
    }
}

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UploadsModule } from '@progress/kendo-angular-upload';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
    imports: [BrowserModule, HttpClientModule, UploadsModule, BrowserAnimationsModule, FormsModule, ReactiveFormsModule],
    declarations: [AppComponent],
    bootstrap: [AppComponent],
})

export class AppModule {}
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

Reactive Forms

The FormGroup provides a way to render reactive forms. For more details, refer to the Angular Documentation.

The following example demonstrates how to use the FileSelect in a reactive form.

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
    selector: 'my-app',
    template: `
    <div class="example-config">
        <p>Valid: {{ myForm.valid }}</p>
        <p>Submitted: {{ submitted }}</p>
    </div>
    <form [formGroup]="myForm" novalidate (ngSubmit)="save(myForm.value, myForm.valid)">
        <kendo-fileselect
            formControlName="files"
            [multiple]="false"
        >
        </kendo-fileselect>
        <p style="color: red; font-size: .8em; margin-top: .5em;"
        [hidden]="myForm.controls.files.valid || (myForm.controls.files.pristine && !submitted)">
            Selecting a file is required.
        </p>
        <button type="submit" class="k-button k-primary" style="margin: 1em 0;">Submit</button>
    </form>
    `
})
export class AppComponent {
    public myForm: FormGroup;
    public myFiles: Array<any>;
    public submitted = false;

    constructor(private fb: FormBuilder) {
        this.myForm = this.fb.group({
            files: [this.myFiles, [Validators.required]]
        });
    }

    save(_value: any, valid: boolean) {
        this.submitted = true;

        if (valid) {
            console.log('Everything is OK!');
        }
    }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UploadsModule } from '@progress/kendo-angular-upload';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
    imports: [BrowserModule, HttpClientModule, UploadsModule, BrowserAnimationsModule, FormsModule, ReactiveFormsModule],
    declarations: [AppComponent],
    bootstrap: [AppComponent],
})

export class AppModule {}
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

FormField Association

The following example demonstrates how to use the FileSelect within a FormField component and provide hint and error messages:

import { Component, Injectable, OnInit } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpProgressEvent, HttpEventType, HttpResponse } from '@angular/common/http';
import { FormGroup, Validators, FormControl } from '@angular/forms';

import { Observable, of, concat } from 'rxjs';
import { delay } from 'rxjs/operators';

@Component({
    selector: 'my-app',
    template: `
      <div class="example">
        <form class="k-form" [formGroup]="form" novalidate (ngSubmit)="save(form.value, form.valid)">
            <kendo-formfield>
                <kendo-label [for]="files" [text]="'Upload files'"></kendo-label>
                <kendo-fileselect #files [formControlName]="'files'" [multiple]="true"></kendo-fileselect>

                <kendo-formhint>Hint: Select your files</kendo-formhint>
                <kendo-formerror *ngIf="form.controls.files.errors?.required && submitted">Error: Uploading files is required</kendo-formerror>
            </kendo-formfield>

            <button type="submit" class="k-button k-primary" style="margin: 1em 0;">Submit</button>
        </form>
    </div>
  `
})
export class AppComponent implements OnInit {
    public data: any = {
        files: []
    };

    public form: FormGroup;
    public submitted = false;

    public ngOnInit(): void {
        this.form = new FormGroup({
            files: new FormControl(this.data.files, [Validators.required])
        });
    }

    public save(value: any, valid: boolean): void {
        this.submitted = true;

        if (valid) {
            console.log('Everything is OK!');
        } else {
            this.form.markAllAsTouched();
        }
    }
}

/*
  Mocked backend service.
  For further details, check
  https://angular.io/guide/http#writing-an-interceptor
*/

@Injectable()
export class UploadInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.url === 'saveUrl') {
            const events: Observable<HttpEvent<any>>[] = [0, 30, 60, 100].map((x) => of(<HttpProgressEvent>{
                type: HttpEventType.UploadProgress,
                loaded: x,
                total: 100
            }).pipe(delay(1000)));

            const success = of(new HttpResponse({ status: 200 })).pipe(delay(1000));
            events.push(success);

            return concat(...events);
        }

        if (req.url === 'removeUrl') {
            return of(new HttpResponse({ status: 200 }));
        }

        return next.handle(req);
      }
}
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';

import { LabelModule } from '@progress/kendo-angular-label';
import { InputsModule } from '@progress/kendo-angular-inputs';
import { UploadsModule } from '@progress/kendo-angular-upload';

import { UploadInterceptor } from './app.component';
import { AppComponent } from './app.component';

@NgModule({
    imports: [
        BrowserModule,
        HttpClientModule,
        UploadsModule,
        BrowserAnimationsModule,
        FormsModule,
        ReactiveFormsModule,
        LabelModule,
        InputsModule
    ],
    declarations: [ AppComponent ],
    bootstrap:    [ AppComponent ],
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: UploadInterceptor,
            multi: true
        }
    ]
})

  export class AppModule { }
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

In this article