0
votes

I am trying to implement required field validation for kendo-dropdownlist on my template driven form in angular 7. If you can see I am looping and generating a dynamic table which has kendo dropdownlist in every row. I need to highlight the dropdown if it is not selected. I tried to enclose my divs withing a form tag thinking I could handle it when the user presses submit but I think this is more of setting within kendo. Could somebody tell me the way to do it. Whatever examples I am seeing so far all jquery based.

Here is the stackblitz https://stackblitz.com/edit/angular-4v2k8f

Html

form name="form" (ngSubmit)="f.form.valid && createDocument()" #f="ngForm" novalidate>
<div class="center" class="file-upload-wrapper">
    <ngx-file-drop dropZoneLabel="Drop files here" dropZoneClassName="file-drop" multiple="true"
        (onFileDrop)="dropped($event)" (onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)">
        <ng-template ngx-file-drop-content-tmp let-openFileSelector="openFileSelector">
            <button type="button" (click)="openFileSelector()">Drop Files to Upload</button>
        </ng-template>
    </ngx-file-drop>

    <div class="upload-table">
        <table id="table1" class="center">

            <tbody class="upload-name-style">
                <tr *ngFor="let item of files; let i=index">
                    <td> <input kendoTextBox [(ngModel)]="item.relativePath" style="width: 350px" /></td>
                    <td>
                        <kendo-dropdownlist style="width:350px" [(ngModel)]="item.selectedDocumentItem" 
                            [data]="DocumentTypes" [defaultItem]="defaultItem" [filterable]="false" textField="Name"
                            valueField="Id">
                        </kendo-dropdownlist>
                    </td>
                    <td>
                        <kendo-datepicker style="width: 200px" [format]="'dd MMM, yyyy'"
                            [(ngModel)]="item.selectedDate"></kendo-datepicker>
                    </td>
                    <td> <button class="btn btn-default" (click)="deleteRow(i)"><i class="fa fa-trash"></i>Delete
                        </button></td>
                </tr>
            </tbody>
        </table>


    </div>
    <div class="wrapper">
        <button *ngIf="files.length > 0" type="submit" class="btn btn-primary btn-upload">upload</button>
    </div>
</div>


</form>

Component

 public createDocument() {
        this.files.forEach(element => {

            this.uploadDocument = <IDocument>{

                id: 5508,
                documentTypeId: element.selectedDocumentItem.Id ,
                name: element.relativePath,
                documentDate: element.selectedDate

              };


        });
        }
1
Can you provide a stackblitz example of that? - Munim Munna
Here you got with the stackblitz stackblitz.com/edit/angular-4v2k8f - Tom
what about isRequired ? look at the documentation : telerik.com/kendo-angular-ui/components/dropdowns/dropdownlist/… - bubbles

1 Answers

1
votes

The only thing you need is use a reference variable and see if is valid or not. I put a simple example in stackblitz. As you only want to know if has a valid, you can use simple required. My stackblitz is like

Update: in a form, disabled the button submit

@Component({
  selector: 'my-app',
  template: `
    <div class="example-wrapper">
    <form #myForm="ngForm">
    <div *ngFor="let item of files; let i=index">
      <p>T-shirt size:</p>
      <kendo-dropdownlist name="select{{i}}" #name="ngModel" [(ngModel)]="value[i]" [data]="listItems" required>
      </kendo-dropdownlist>
      <span *ngIf="name.invalid">*</span>
    </div>
    <button [disabled]="myForm.invalid">submit</button>
    </form>
    </div>
  `
})
export class AppComponent {
    public listItems: Array<string> = ["X-Small", "Small", "Medium", "Large", "X-Large", "2X-Large"];
    value=[]
    files=[{value:''},{value:''},{value:''}]
}

Briefly explain (but you has the docs) When we has a [(ngModel)] we can use a template reference to refer to the input. If we equal the template reference to ngModel #name="ngModel", we can use in the .html the template variable and all the properties of ngModel (invalid, touched...) in the way, name.invalid, name.touched...

Ah!, don't worry about you are put the "same" reference variable, if the variable of the model is not equal, Angular understand that they are diferents variables.

NOTE: Personally, I suggest you use ReactiveForms and FormArray, but it's only an opinion

Update 2 Really The problem is that you can not loop over the same list that you want modified. You has *ngFor="let item of files" and you're changing files. the trick is iterate over ' '.repeat(files.length).split('') -or create an array in code- this.iterator=new Array(this.files.length), then you can do <tr *ngFor="let t of iterator;let i=index">

The [(ngModel)] is over files[i].selectedDocumentItem.Id

See the stackblitz and the code

<div class="example-wrapper">
    <form #myForm="ngForm">
        <!-- other way is <tr *ngFor="let t of iterator;let i=index"> -->
        <tr *ngFor="let t of ' '.repeat(files.length).split(''); let i=index">
            <td>
                <kendo-dropdownlist name="select{{i}}" #name="ngModel" [(ngModel)]="files[i].selectedDocumentItem.Id" [defaultItem]="files[i].selectedDocumentItem.id"
                 [data]="DocumentTypes" [valuePrimitive]="true" textField="Name" valueField="Id" required>
                </kendo-dropdownlist>
                <span *ngIf="name.invalid">*</span>
      </td>
    </tr>
    <button [disabled]="myForm.invalid">submit</button>
  </form>
</div>

If we want use as [ngModel]=files[i].selectedDocumentItem (an object), we need create a customError directive. It's looks like

@Directive({
  selector: '[requiredId]',
  providers: [{provide: NG_VALIDATORS, useExisting: RequiredIdDirective, multi: true}]
})
export class RequiredIdDirective implements Validator {

  validate(control: AbstractControl): {[key: string]: any} | null {
    return control.value.Id?null:{required:true}
  }
}

And our dropdown is now like

<kendo-dropdownlist name="select{{i}}" #name="ngModel"
      [(ngModel)]="files[i].selectedDocumentItem" 
      [defaultItem]="files[i].selectedDocumentItem" 
      [data]="DocumentTypes" 
      textField="Name" valueField="Id" requiredId>
      </kendo-dropdownlist>

See a new stackblitz