Search code examples
htmlangularinputmat-form-field

how to place text input beside of chips in Angular


I'm trying to make the mat form field that can show tags, input and drop down like the design below but I'm not sure how to achieves that so can anybody help me out. I've tried different methods for a few hour now but still can't find a way to make it work. will be really appreciated if somebody can give me suggestion or help.

I'm just trying to place the text input to be always beside of Chips (maybe expand like what I have right now if user put a lot of chips) and also have drop down options (icon) on the side like the design below.

<mat-chip-list *ngIf="editMode">
    <mat-form-field class="form" appearance="fill">

        <!--show Tags-->
        <ng-container *ngFor="let chip of chips" class="add-tag-chip" (click)="displayTagInput()">
                <mat-chip [selectable]="selectable" [removable]="removable" (removed)="removeTags(chip)">
                    {{chip.tag}}
                    <mat-icon matChipRemove *ngIf="chip.pending !== true && removable" matTooltip="Remove a tag">cancel</mat-icon>
                    <mat-spinner *ngIf="chip.pending === true" [diameter]="16" mode="indeterminate"></mat-spinner>
                </mat-chip>
        </ng-container>

        <!--Text Input (supposed to be on the side of Tags)-->
            <input matInput [(ngModel)]="tagIn" [matAutocomplete]="auto" placeholder="New Tag"  (keyup.enter)="addTag()" />

        <!--For Drop Down List-->
            <mat-autocomplete #auto="matAutocomplete">
                <mat-option *ngFor="let tag of filteredTags | async" [value]="tag">
                    {{tag}}
                </mat-option>
            </mat-autocomplete>

    </mat-form-field>
</mat-chip-list>

This is the design I'm trying to do

enter image description here

enter image description here

This is what I have right now

enter image description here


Solution

  • Why don't you use it as it is represented in the documentation ? I also found this stackblitz that is exactly what you want. Here is the html code :

    <mat-form-field class="demo-chip-list">
      <mat-chip-list #chipList>
        <mat-chip
          *ngFor="let fruit of fruits"
          [selectable]="selectable"
          [removable]="removable"
          (removed)="remove(fruit)">
          {{fruit}}
          <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
        </mat-chip>
        <input
          placeholder="New fruit..."
          #fruitInput
          [formControl]="fruitCtrl"
          [matAutocomplete]="auto"
          [matChipInputFor]="chipList"
          [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
          [matChipInputAddOnBlur]="addOnBlur"
          (matChipInputTokenEnd)="add($event)"
        />
      </mat-chip-list>
      <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
        <mat-option *ngFor="let fruit of filteredFruits | async" [value]="fruit">
          {{ fruit }}
        </mat-option>
      </mat-autocomplete>
    </mat-form-field>
    

    Note that there is no ng-container ( they don't seems mandatory in your code) and the mat-form-field tag wrap the whole thing. In your code you have it as a child of mat-chip-list.


    [Edit]: I got it. Here is the code :

    .css :

    /* ::ng-deep needed to only target your component (it's deprecated but have not replacement for the moment) */
    .your-component ::ng-deep .mat-form-field-infix {
      display: flex !important
    }
    
    /* Change the placeholder to stick to the same position as if your input is focused, not really good */
    .your-component ::ng-deep.mat-form-field-label {
        transform: translateY(-1.28125em) scale(.75) perspective(100px) translateZ(.001px) !important;
    }
    

    .html:

    <mat-chip-list>
        <mat-form-field>
        <!-- ng-container is now a span -->
            <span *ngFor="let fruit of fruits" (click)="displayTagInput()">
                <mat-chip [selectable]="selectable" [removable]="removable" (removed)="removeTags(chip)">
                    {{fruit}}
                    <mat-icon matChipRemove matTooltip="Remove a tag">cancel
                    </mat-icon>
                </mat-chip>
            </span>
    
            <input matInput [(ngModel)]="tagIn" [matAutocomplete]="auto2" placeholder="New Tag..."  (keyup.enter)="addTag()" />
    
            <mat-autocomplete #auto2="matAutocomplete" (optionSelected)="selected($event)">
                <mat-option *ngFor="let fruit of filteredFruits | async" [value]="fruit">
                    {{ fruit }}
                </mat-option>
            </mat-autocomplete>
    
        </mat-form-field>
    </mat-chip-list>
    

    Here is the demo ons tackblitz. Note that it does not work perfectly. I had to force the shrink effect of the placeholder with the css (I think it's because mat-form-field is inside mat-chip-list).

    Also, since i removed some come to make it clearer, you will have to test it with your own code, chip remove methods etc.

    Hope it helps :)