angularangular7angular-material-7

Angular Material multi Select


I'm after a bit of advice with using Angular Material 7 multi selects. The documentation doesn't help that much with what I'm trying to do.

Bit of a background on what I'm trying to do.

So we are creating a record object and as part of that we need to know what Programme Funded them. The ProgrammeList is an array of Programme objects with {ProgrammeKey, Name, Description}. Previously we have used single selects and it works great. The issue is that each report can be funded by multiple Programmes so we need to use the multi Select.

Firstly, When it comes to the database. How will the multi select options be saved? The idea was that the multi-select would form its own array of selected objects and then pass them back to the back end to be saved in a Linking Table.

I have included the code below for the relevant areas

record.dto.ts

import {Programme} from "./programme.dto";

export class Record {
    Programme: Programme[];
    CcfLead: string;
    NihrRef: string;
    AddRef: string;
    AwardTitle: string;
    ProjectTitle: string;
    StartDate: Date;
    EndDate: Date;
}

general.component.ts ...

 programmes = new FormControl();
 programmeList: Programme[];

 createRecordFrm() {
        this.recordFrm = this.fb.group({
            Programme : [{}, Validators.required],
            NihrRef: ["", Validators.required],
            AddRef:[""],
            CCFLead: ["", Validators.required],
            AwardTitle: ["", Validators.required],
            ProjectTitle: ["", Validators.required],
            StartDate: Date,
            EndDate: [Date, Validators.required]
        });
    }

    updateRecordFrm(record: Record) {
        this.recordFrm.setValue({
            Programme: record.Programme,
            NihrRef: record.NihrRef,
            AddRef: record.AddRef,
            CCFLead: record.CcfLead,
            AwardTitle: record.AwardTitle,
            ProjectTitle: record.ProjectTitle,
            StartDate: record.StartDate,
            EndDate: record.EndDate
        });
    }

open(content: any, modal?: Record) {
        this.msg = null;
        this.modalMsg = null;

        if (modal != null) {
            this.updateRecordFrm(modal);
            // update recordFrm
        }

        this.activeModal = this.modalService.open(content, { ariaLabelledBy: 'modal-basic-title', backdrop: "static", keyboard: false });
    }

general.component.html

<ng-template #recordWizard let-c="close" let-d="dismiss" width="50%">
    <form novalidate (ngSubmit)="saveRecord(recordFrm.value)" [formGroup]="recordFrm">
        <div class="modal-header">
            <h4 class="modal-title" id="modal-basic-title">New Record</h4>
            <button type="button" class="close" (click)="d('Cross Click')">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        <div class="modal-body">
            <div *ngIf="modalMsg" role="alert" class="alert alert-info alert-dismissible">
                <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <mat-icon>report_problem</mat-icon>
                <span class="sr-only">Error:</span>
                {{modalMsg}}
            </div>

            <div>
                <mat-tab-group>
                    <mat-tab label="First">
                        <div class="form-group">
                            <span>NIHR Reference*</span>
                            <input type="text" class="form-control" readonly formControlName="NihrRef" />
                        </div>
                        <div class="form-group">
                            <span>Additional Reference</span>
                            <input type="text" class="form-control" readonly formControlName="AddRef" />
                        </div>
                        <div class="form-group">
                            <span>Funding Programme:*</span>
                            <mat-select class="form-control" placeholder="Funding Programmes" formControl="programme" multiple [compareWith]="compare">
                                <mat-option *ngFor="let programme of programmeList" [value]="programmeList">{{programme.Description}}</mat-option>
                            </mat-select>
                        </div>
                    </mat-tab>
                    <mat-tab label="Second">
                        Content 2
                    </mat-tab>
                    <mat-tab label="Third">
                        Content 3
                    </mat-tab>
                    <mat-tab label="Fourth">
                        Content 4
                    </mat-tab>
                    <mat-tab label="Fifth">
                        Content 5
                    </mat-tab>
                    <mat-tab label="Sixth">
                        Content 6
                    </mat-tab>
                </mat-tab-group>
            </div>
        </div>
        <div class="modal-footer">
            <div>
                <button type="submit" (click)="c" [disabled]="newRecordFrm.invalid" class="btn btn-primary">Save</button>
                <button type="button" class="btn btn-outline-dark" (click)="c('Save click')">Cancel</button>
            </div>

        </div>
    </form>
</ng-template>

And finally the error console error

UPDATE

The main issue I had was that the dto was incorrect and needed some more values.

There is a new issue where the dropdown is not brought to the front of the view. and instead behind the active model. Is there any css i can apply to resolve this? enter image description here

Many thanks in advance for your help

Lewis


Solution

  • For our application, we use ngModel instead of formControl. We do it like this:

    Filter.html

    <mat-form-field class="ca80">
      <mat-select [(ngModel)]="type_list" multiple name="type_list">
         <mat-option *ngFor="let type of alteration_types" [value]="type.id_type"> {{type.desc}}</mat-option>
      </mat-select>
    </mat-form-field>
    

    and in filter.component.ts

    type_list: string[];
    auxT: any[] = [];
    /**...**/
    
      if (this.type_list != null) {
          for (let t of this.type_list) {
            auxT.push(t);
          }
        }
    

    We don't know if this is the best option, but it works fine