This is a migrated thread and some comments may be shown as answers.

Kendo Angular Upload always sending empty file

1 Answer 67 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Philippe
Top achievements
Rank 1
Philippe asked on 22 Jun 2020, 02:13 PM

I'm trying to use Kendo Angular Upload but when I check the data being sent to the server in Google Chrome DevTools, the property rawFile, which I beleive is the one responsible to actually retrieve the file data, is always empty as the attachment indicates.

Here's my HTML:

<form class='content' novalidate [formGroup]="edicaoForm">
    <div class="k-i-loading" *ngIf="loading"></div>
    <div class="row"></div>
 
    <div class="clear-fix mt-4"></div>
    <div class="row">
        <div class="col-sm-12">
            <div class="col-sm-4 pull-left">
                <label [for]="logomarca">Logo</label>
                <kendo-uploaddropzone zoneId="myZone">Somente arquivos do tipo JPG, JPEG, PNG e SVG são permitidos.</kendo-uploaddropzone>
                <kendo-upload zoneId="myZone" [saveField]="logomarca" [saveUrl]="uploadLogoURL" [chunkable]="false" [restrictions]="restrictions" #logomarca [multiple]="false" [autoUpload]="true" formControlName="logomarca" ngDefaultControl>
                    <kendo-upload-messages select="Selecionar arquivo" uploadSelectedFiles="Enviar arquivo" clearSelectedFiles="Cancelar seleção de arquivo"
                        dropFilesHere="Solte arquivos aqui para carregar" invalidFileExtension="Tipo de arquivo não permitido." remove="Remover" cancel="Cancelar"
                        fileStatusUploaded="Arquivo carregado com sucesso." externalDropFilesHere="Arraste e solte arquivos aqui para carregar" resume="Concluir" pause="Pausar"
                        headerStatusUploaded="Concluído" headerStatusUploading="Carregando..." headerStatusPaused="Pausado" fileStatusFailed="Falha ao carregar arquivo."></kendo-upload-messages>
                </kendo-upload>
            </div>
 
            <div class="row">
                <div class="col-sm-6"
                    [ngClass]="{'has-error': displayMessages.empresaId }">
                    <label>Empresa</label>
                    <div>
                        <kendo-combobox [data]="empresasData" [allowCustom]="false" [placeholder]="'Empresa'" [textField]="'nomeFantasia'" [valueField]="'gid'"
                            [filterable]="true" class="w-100" formControlName="empresaId" (filterChange)="empresaHandleFilter($event)" (open)="empresaHandleOpen()" required
                            [suggest]="true" [valuePrimitive]="true" (blur)="blur('empresaId')"></kendo-combobox>
                        <span class="text-danger" *ngIf="displayMessages.empresaId">
                            <p [innerHTML]="displayMessages.empresaId"></p>
                        </span>
                    </div>
                </div>
 
                <div class="col-sm-6"
                    [ngClass]="{'has-error': displayMessages.codigo }">
                    <label>Código</label>
                    <div>
                        <input kendoTextBox [placeholder]="'Código'" maxlength="30" class="w-100" formControlName="codigo" />
                        <span class="text-danger" *ngIf="displayMessages.codigo">
                            <p [innerHTML]="displayMessages.codigo"></p>
                        </span>
                    </div>
                </div>
            </div>
 
            <div class="clear-fix mt-4"></div>
 
            <div class="row">
                <div class="col-sm-6" [ngClass]="{'has-error': displayMessages.descricao }">
                    <label>Descrição</label>
                    <div>
                        <input kendoTextBox [placeholder]="'Descrição'" class="w-100" formControlName="descricao" />
                        <span class="text-danger" *ngIf="displayMessages.descricao">
                            <p [innerHTML]="displayMessages.descricao"></p>
                        </span>
                    </div>
                </div>
 
                <div class="col-sm-6" [ngClass]="{'has-error': displayMessages.nomeFantasia }">
                    <label>Nome Fantasia</label>
                    <div>
                        <input kendoTextBox [placeholder]="'Nome Fantasia'" class="w-100" formControlName="nomeFantasia" />
                        <span class="text-danger" *ngIf="displayMessages.nomeFantasia">
                            <p [innerHTML]="displayMessages.nomeFantasia"></p>
                        </span>
                    </div>
                </div>
            </div>
 
            <div class="clear-fix mt-4"></div>
 
            <div class="row">
                <div class="col-sm-6 pull-left" [ngClass]="{'has-error': displayMessages.tipoIdentificacao }">
                    <label>Tipo de identificação</label>
                    <kendo-combobox [data]="tiposDeIdentificacao" [allowCustom]="false" [placeholder]="'Tipo de Identificação'" [textField]="'descricao'"
                        [valueField]="'valor'" [filterable]="true" class="w-100" [valuePrimitive]="true" formControlName="tipoIdentificacao"
                        (blur)="blur('tipoIdentificacao')"></kendo-combobox>
                    <span class="text-danger" *ngIf="displayMessages.tipoIdentificacao">
                        <p [innerHTML]="displayMessages.tipoIdentificacao"></p>
                    </span>
                </div>
 
                <div class="col-sm-6 pull-left" [ngClass]="{'has-error': displayMessages.numeroDocumento }">
                    <label>Número Documento</label>
                    <div>
                        <input kendoTextBox [placeholder]="'Número Documento'" maxlength="18" class="w-100" (keyup)="maskInputCpfCnpj()" formControlName="numeroDocumento" />
                        <span class="text-danger" *ngIf="displayMessages.numeroDocumento">
                            <p [innerHTML]="displayMessages.numeroDocumento"></p>
                        </span>
                    </div>
                </div>
            </div>
        </div>
    </div>
 
    <div class="clear-fix mt-4"></div>
 
    <div class="row">
        <div class="col-sm-12">
            <div class="col-sm-4 pull-left"
                [ngClass]="{'has-error': displayMessages.inscricaoMunicipal }">
                <label>Inscrição Municipal</label>
                <div>
                    <input kendoTextBox [placeholder]="'Inscrição Municipal'" maxlength="20" class="w-100" formControlName="inscricaoMunicipal" />
                    <span class="text-danger" *ngIf="displayMessages.inscricaoMunicipal">
                        <p [innerHTML]="displayMessages.inscricaoMunicipal"></p>
                    </span>
                </div>
            </div>
 
            <div class="col-sm-4 pull-left" [ngClass]="{'has-error': displayMessages.inscricaoEstadual }">
                <label>Inscrição Estadual</label>
                <div>
                    <input kendoTextBox [placeholder]="'Inscrição Estadual'" maxlength="20" class="w-100" formControlName="inscricaoEstadual" />
                    <span class="text-danger" *ngIf="displayMessages.inscricaoEstadual">
                        <p [innerHTML]="displayMessages.inscricaoEstadual"></p>
                    </span>
                </div>
            </div>
 
            <div class="col-sm-4 pull-left" [ngClass]="{'has-error': displayMessages.cnaeId }">
                <label>CNAE</label>
                <div>
                    <kendo-combobox [data]="cnaesData" [allowCustom]="false" [placeholder]="'CNAE'" [textField]="'descricao'" [valueField]="'gid'" [filterable]="true"
                        (filterChange)="cnaeHandleFilter($event)" (open)="cnaeHandleOpen()" [suggest]="true" class="w-100" formControlName="cnaeId" [valuePrimitive]="true"
                        (blur)="blur('cnaeId')"></kendo-combobox>
                    <span class="text-danger" *ngIf="displayMessages.cnaeId">
                        <p [innerHTML]="displayMessages.cnaeId"></p>
                    </span>
                </div>
            </div>
        </div>
    </div>
 
    <div class="clear-fix mt-4"></div>
    <div class="row">
        <div class="col-sm-12">
            <div class="col-sm-4 pull-left" [ngClass]="{'has-error': displayMessages.email }">
                <label>E-mail</label>
                <div>
                    <input kendoTextBox [placeholder]="'E-mail'" class="w-100" formControlName="email" />
                    <span class="text-danger" *ngIf="displayMessages.email">
                        <p [innerHTML]="displayMessages.email"></p>
                    </span>
                </div>
            </div>
 
            <div class="col-sm-4 pull-left" [ngClass]="{'has-error': displayMessages.site }">
                <label>Site</label>
                <div>
                    <input kendoTextBox [placeholder]="'Site'" class="w-100" formControlName="site" />
                    <span class="text-danger" *ngIf="displayMessages.site">
                        <p [innerHTML]="displayMessages.site"></p>
                    </span>
                </div>
            </div>
 
            <div class="col-sm-4 pull-left" [ngClass]="{'has-error': displayMessages.dataRegistro }">
                <label>Data Registro</label>
                <div>
                    <kendo-datepicker [(value)]="dataRegistro" [placeholder]="'Data Registro'" [format]="'dd/MM/yyyy'" [navigation]="false" [weekNumber]="true" class="w-100"
                        formControlName="dataRegistro"> </kendo-datepicker>
                    <span class="text-danger" *ngIf="displayMessages.dataRegistro">
                        <p [innerHTML]="displayMessages.dataRegistro"></p>
                    </span>
                </div>
            </div>
        </div>
    </div>
 
    <div class="clear-fix mt-4"></div>
 
    <div class="row">
        <div class="col-sm-12">
            <div class="col-sm-4 pull-left">
                <div class="col-sm-6 pull-left" style="padding-left: 2px;" [ngClass]="{'has-error': displayMessages.bloqueada }">
                    <input type="checkbox" id="bloqueada" class="k-checkbox" formControlName="bloqueada" [checked]="false">
                    <label class="k-checkbox-label" for="bloqueada">Bloqueada</label>
                </div>
 
                <div class="col-sm-6 pull-left" [ngClass]="{'has-error': displayMessages.matriz }">
                    <input type="checkbox" id="matriz" class="k-checkbox" formControlName="matriz" [checked]="false">
                    <label class="k-checkbox-label" for="matriz">Matriz</label>
                </div>
            </div>
        </div>
    </div>
 
    <div class="clear-fix mt-4"></div>
 
    <div class="row">
        <div class="col-sm-12">
            <div class="col-sm-12">
                <label [for]="observacao">Observação</label>
                <kendo-textbox-container class="w-100" style="padding-top: 4px;">
                    <textarea kendoTextArea formControlName="observacao" #observacao></textarea>
                </kendo-textbox-container>
                <span class="text-danger" *ngIf="displayMessages.observacao">
                    <p [innerHTML]="displayMessages.observacao"></p>
                </span>
            </div>
        </div>
    </div>
 
    <div class="clear-fix mt-4"></div>
 
    <div class="col-sm-12 mt-2">
        <button kendoButton [icon]="'save'"
            class="pull-left btn-primary btn-sm" (click)="atualizar()" [disabled]='!edicaoForm.valid'>Salvar</button>
        <button kendoButton [icon]="'delete'" class="pull-right btn-danger btn-sm ml-1" (click)="excluir()">Excluir</button>
        <button kendoButton [icon]="'close'" class="pull-right btn-secondary btn-sm" (click)="sendFormStatus()">Fechar</button>
    </div>
</form>
 
<app-alert (alertStatus)="alertEvent($event)" [openedAlert]="openedAlert" [title]="title" [message]="message"></app-alert>

Here's my angular component:

import { Component, OnChanges, AfterViewInit, Input, Output, EventEmitter, ElementRef, ViewChildren } from '@angular/core';
import { FormGroup, FormControlName, FormBuilder, Validators } from '@angular/forms';
import { FormValidator } from '../../../utils/form-validator';
import { NotificationService } from '@progress/kendo-angular-notification';
import { IntlService } from '@progress/kendo-angular-intl';
import { EstabelecimentosService } from '../../services/estabelecimentos.service';
import { Estabelecimento } from '../../models/estabelecimento';
import { Observable, forkJoin } from 'rxjs';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/observable/merge';
import { Cnae } from '../../../cnae/models/cnae';
import { CnaeService } from '../../../cnae/services/cnae.service';
import { Empresa } from '../../../empresas/models/empresa';
import { EmpresasService } from '../../../empresas/services/empresas.service';
import { Utils } from '../../../utils/utils';
import { FileRestrictions } from '@progress/kendo-angular-upload';
import { environment } from '../../../../environments/environment';
 
@Component({
    selector: 'app-edit-estabelecimento',
    templateUrl: './edit-estabelecimento.component.html',
    styleUrls: ['../index/index-estabelecimento.component.css', './edit-estabelecimento.component.css']
})
export class EditEstabelecimentoComponent implements AfterViewInit, OnChanges {
    @Input() habilitarView: boolean;
    @Input() estabelecimentoId: string;
    @Output() formStatus = new EventEmitter<boolean>();
    @Output() editedItem = new EventEmitter<Estabelecimento>();
    public message: string = '';
    public title: string = '';
    public openedAlert: boolean = false;
    public loading: boolean = false;
    private estabelecimentoDescricao: string;
    public estabelecimento: Estabelecimento;
    public cnaesData: Cnae[] = [];
    public cnaesSource: Cnae[] = [];
    public empresasData: Empresa[] = [];
    public empresasSource: Empresa[] = [];
    edicaoForm: FormGroup;
    formValidator: FormValidator;
    validationMessages: { [key: string]: { [key: string]: string } };
    displayMessages: { [key: string]: string } = {};
    dataRegistro: any = null;
    @ViewChildren(FormControlName, { read: ElementRef }) formInputElements: ElementRef[];
    public tiposDeIdentificacao: Array<{ descricao: string, valor: number }> = [{ descricao: 'Pessoa Jurídica', valor: 1 }, { descricao: 'Pessoa Física', valor: 2 }];
    uploadLogoURL: string = `${environment.url}imagens/estabelecimento/${this.estabelecimentoId}/logo`;
 
    public restrictions: FileRestrictions = {
        allowedExtensions: ['jpg', 'jpeg', 'png', 'svg'],
        maxFileSize: 5242880
    };
 
    constructor(private readonly fb: FormBuilder,
        private readonly utils: Utils,
        private readonly empresasService: EmpresasService,
        private readonly cnaeServices: CnaeService,
        private readonly estabelecimentosService: EstabelecimentosService,
        private readonly intl: IntlService,
        private readonly notificationService: NotificationService) { }
 
    ngAfterViewInit(): void {
        let controlBlurs: Observable<any>[] = this.formInputElements
            .map((formControl: ElementRef) => Observable.fromEvent(formControl.nativeElement, 'blur'));
 
        Observable.merge(...controlBlurs).subscribe(() => {
            this.displayMessages = this.formValidator.processMessages(this.edicaoForm);
        });
    }
 
    ngOnChanges(): void {
        this.loading = true;
        this.validationMessages = {
            codigo: { required: 'Informe o código' },
            descricao: { required: 'Informe a descrição' },
            tipoIdentificacao: { required: 'Informe o tipo de identificação' },
            nomeFantasia: { required: 'Informe o nome fantasia ' },
            numeroDocumento: { required: 'Informe o número do documento' },
            inscricaoEstadual: { required: 'Informe o número de inscrição estadual' },
            inscricaoMunicipal: { required: 'Informe o número de inscrição municipal' },
            email: { required: 'Informe o email' },
            site: { required: 'Informe o site' },
            dataRegistro: { required: 'Informe a data do registro' },
            observacao: { required: 'Preencha a observação' },
            empresaId: { required: 'Informe a Empresa' },
            cnaeId: { required: '' }
        };
 
        this.edicaoForm = this.fb.group({
            codigo: ['', [Validators.required]],
            descricao: ['', [Validators.required]],
            tipoIdentificacao: [0, [Validators.required]],
            nomeFantasia: ['', [Validators.required]],
            numeroDocumento: ['', [Validators.required]],
            inscricaoEstadual: ['', []],
            inscricaoMunicipal: ['', []],
            email: ['', []],
            site: ['', []],
            bloqueada: ['', []],
            dataRegistro: ['', []],
            observacao: ['', []],
            matriz: ['', []],
            empresaId: ['', [Validators.required]],
            cnaeId: ['', []],
            logomarca: ['', []]
        });
 
        this.formValidator = new FormValidator(this.validationMessages);
 
        forkJoin(this.estabelecimentosService.getEstabelencimento(this.estabelecimentoId), this.empresasService.getAll(), this.cnaeServices.getAll()).subscribe(response => {
            this.estabelecimento = new Estabelecimento();
            this.estabelecimento.gid = this.estabelecimentoId;
 
            response[0]['data'].numeroDocumento = this.utils.convertToCpfCnpj(response[0]['data'].numeroDocumento);
            this.preencherForm(response[0]['data']);
 
            this.empresasSource = response[1]['data'];
            this.formValidator.preencherCombo(this.edicaoForm, 'empresaId', this.empresasData = response[1]['data']);
 
            this.cnaesSource = response[2]['data'];
            this.formValidator.preencherCombo(this.edicaoForm, 'cnaeId', this.cnaesData = response[2]['data']);
        });
    }
 
    preencherForm(estabelecimento: any): void {
        this.estabelecimentoDescricao = estabelecimento.descricao;
        if (estabelecimento.cnae == [] || estabelecimento.cnae == undefined || estabelecimento.cnae == null) {
            estabelecimento.cnae = Object.assign({});
        }
 
        if (!estabelecimento.logomarca) {
            estabelecimento.logomarca = Object.assign({});
        }
 
        this.edicaoForm.patchValue({
            codigo: estabelecimento.codigo,
            descricao: estabelecimento.descricao,
            tipoIdentificacao: estabelecimento.tipoIdentificacao,
            nomeFantasia: estabelecimento.nomeFantasia,
            numeroDocumento: estabelecimento.numeroDocumento,
            inscricaoEstadual: estabelecimento.inscricaoEstadual,
            inscricaoMunicipal: estabelecimento.inscricaoMunicipal,
            email: estabelecimento.email,
            site: estabelecimento.site,
            dataRegistro: this.intl.parseDate(estabelecimento.dataRegistro),
            bloqueada: estabelecimento.bloqueada,
            matriz: estabelecimento.matriz,
            observacao: estabelecimento.observacao,
            empresaId: estabelecimento.empresa.gid,
            cnaeId: estabelecimento.cnae.gid,
            logomarca: estabelecimento.logomarca
        });
 
        this.loading = false;
    }
 
    sendFormStatus() {
        this.habilitarView = false;
        this.formStatus.emit(this.habilitarView);
    }
 
    atualizar() {
        this.loading = true;
 
        if (this.edicaoForm.dirty && this.edicaoForm.valid) {
            const estabelecimento = Object.assign({}, this.estabelecimento, this.edicaoForm.value);
            if (estabelecimento.cnaeId != [] && estabelecimento.cnaeId != undefined && estabelecimento.cnaeId != null) {
                estabelecimento.cnae = new Cnae();
                estabelecimento.cnae.gid = estabelecimento.cnaeId;
            } else {
                estabelecimento.cnae = null;
            }
 
            estabelecimento.empresa = new Empresa();
            estabelecimento.empresa.gid = estabelecimento.empresaId;
            estabelecimento.numeroDocumento = this.utils.removeCaracter(estabelecimento.numeroDocumento);
            this.estabelecimentosService.atualizar(estabelecimento).subscribe(success => {
                this.onSuccess(success, 'Atualizado');
            }, error => {
                this.onError(error);
            });
        }
    }
 
    excluir() {
        this.title = 'Atenção';
        this.message = `Você deseja realmente excluir o estabelecimento "${this.estabelecimentoDescricao}"?`;
        this.openedAlert = true;
        this.loading = true;
    }
 
    alertEvent($event: boolean) {
        this.openedAlert = false;
        $event == false ? this.loading = false : true;
        if ($event == true) {
            this.estabelecimentosService.excluir(this.estabelecimentoId).subscribe(success => {
                this.onSuccess(success, 'Excluído');
                this.habilitarView = false;
                this.formStatus.emit(this.habilitarView);
            }, error => {
                this.onError(error);
            });
        }
    }
 
    onSuccess(success: any, acao: string): any {
        this.notificationService.show({
            content: `${acao} com sucesso!`,
            animation: { type: 'slide', duration: 800 },
            cssClass: 'button-notification',
            position: { horizontal: 'center', vertical: 'bottom' },
            type: { style: 'success', icon: true },
            hideAfter: 1000
        });
 
        this.editedItem.emit(success);
        this.loading = false;
    }
 
    onError(error: any): any {
        this.notificationService.show({
            content: `Ocorreu um erro: ${error.message}.`,
            animation: { type: 'slide', duration: 800 },
            cssClass: 'button-notification',
            position: { horizontal: 'center', vertical: 'bottom' },
            type: { style: 'error', icon: true },
            closable: true
        });
        this.loading = false;
    }
 
    maskInputCpfCnpj() {
        let estabelecimento = Object.assign({}, this.estabelecimento, this.edicaoForm.value);
        this.edicaoForm.patchValue({
            numeroDocumento: estabelecimento.numeroDocumento = this.utils.convertToCpfCnpj(estabelecimento.numeroDocumento)
        });
    }
 
    blur(item: string) {
        if (this.edicaoForm.controls[item].value === '' || this.edicaoForm.controls[item].value === undefined || this.edicaoForm.controls[item].value === null) {
            this.displayMessages[item] = this.validationMessages[item].required
        } else {
            delete this.displayMessages[item];
        }
    }
 
    empresaHandleOpen() {
        this.empresasData = JSON.parse(JSON.stringify(this.empresasSource));
    }
 
    empresaHandleFilter(value: string) {
        if (value) {
            this.empresasData = this.empresasSource.filter((s) => s.nomeFantasia.toLocaleLowerCase().includes(value.toLocaleLowerCase()));
        }
    }
 
    cnaeHandleOpen() {
        this.cnaesData = JSON.parse(JSON.stringify(this.cnaesSource));
    }
 
    cnaeHandleFilter(value: string) {
        if (value) {
            this.cnaesData = this.cnaesSource.filter((s) => s.codigo.toLocaleLowerCase().includes(value.toLocaleLowerCase()));
        }
    }
}

1 Answer, 1 is accepted

Sort by
0
Martin
Telerik team
answered on 24 Jun 2020, 12:43 PM

Hi Philippe,

Thank you for the provided details.

Looking at the code several things make me an impression. The saveField option by design accepts strings as value, but a template reference variable is passed instead (logomarca). As I understand the Upload is part of a form. Setting the autoUpload to true will automatically send the request ot the server. In this case, the developer needs to ensure that the file is successfully uploaded to the server then double-check the formControl value. Here is a simplified example of how the Upload can be used in a form (rawFile here is present). Check the console:

https://stackblitz.com/edit/angular-lsbxzd-g4mzpy?file=app/upload.component.ts

Generally speaking, when the Upload is bound to a formControl, the value will be updated only after the success event is fired (that is when files are successfully uploaded or removed.). Please refer to the following article:

https://www.telerik.com/kendo-angular-ui/components/uploads/upload/model-binding/#toc-binding-of-file-collections

You can also check out our dedicated standalone example demonstrating the Upload component integration with ASP .NET Core:

https://github.com/telerik/kendo-angular/tree/master/examples-standalone/aspnetcore-upload

I hope this helps.

Regards,
Martin
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
Tags
General Discussions
Asked by
Philippe
Top achievements
Rank 1
Answers by
Martin
Telerik team
Share this question
or