Search by field that contains button and mat-menu not showing inside of table

I am working on creating a Search by field that when clicked on will have a check box to search by address. It is a button with mat-menu component. I want to add it inside of the app-table-actions components. Any time I try to add it inside of the app-table-actions tags it doesn’t show at all but if I move it outside of the tags it shows above the table as seen in the image. I want the Search By field to be next to Filter Tags.

In the angular html file, I currently have the button and mat-menu inside of div tags above the app-table actions.

<div aria-label="View columns"
  class="d-flex align-content-center view-columns mr-3">
  <button class="mr-0 btn btn-outline-secondary d-flex flex-nowrap text-nowrap"
          [disabled]="searchFields.length === 0"
        [matMenuTriggerFor]="searchByMenu">
    <mat-icon>filter_alt</mat-icon>
    <span class="mx-1">{{ 'Search by field' }}</span>
 </button>

 <mat-menu
    #searchByMenu="matMenu"
    [overlapTrigger]="false">
    <ng-template [ngForOf]="searchFields" let-column ngFor>
        <div *ngIf="(column.field !== undefined)"
             mat-menu-item>
            <mat-checkbox [checked]="selectedSearchFields.isSelected(column)"
                          (change)="selectedSearchFields.toggle(column); 
        getUnitList()"
                          (click)="$event.stopPropagation()"
            >
                <span class="select-column-label">{{ column.label }}</span>
            </mat-checkbox>
        </div>
    </ng-template>
</mat-menu>
</div>
  <app-table-actions actionsType="primary"
               [(searchValue)]="searchValue"
               (searchValueChange)="searchValue = $event; searchChanged.emit()">


<lf-tags taggableType="Owner"
         taggableMode="Filter"
         placeholder="Filter Tags..."
         [hasArchived]="membersStatusFilter === 'archived'"
         (itemAdded)="selectedTags.select($event); loadPeople.emit()"
         (itemChange)="selectedTags.updateFilter($event); loadPeople.emit()"
         (itemRemoved)="selectedTags.deselect($event); loadPeople.emit()"
         (itemsCleared)="selectedTags.clear(); loadPeople.emit()">
</lf-tags>


<app-selection-button *ngIf="selection.hasValue()"
                      (onClick)="showSelectedMembers.emit()">
    {{ selection.selected.length }}
</app-selection-button>

<app-button *ngIf="jwt.admin || jwt.superUser"
            [svg]="'settings'"
            [iconClasses]="['mr-1']"
            [routeTo]="'/app/settings/organization/permissions'">
    {{ 'Manage Permissions' }}
</app-button>

<app-add-button *ngIf="hasWriteAccess"
                [buttonClasses]="['mr-0']"
                [routeTo]="['/app/owner/create']">
    {{ 'Add Owners' }}
</app-add-button>

<ng-container *mobileActions>
    <button *ngIf="jwt.admin || jwt.superUser" 
  [routerLink]="'/app/settings/organization/permissions'" mat-menu-item>{{ 'Manage 
  Permissions' }}</button>
    <button *ngIf="hasWriteAccess" [routerLink]="['/app/owner/create']" mat-menu- 
       item>.  {{ 'Add Owners' }}</button>
</ng-container>
 </app-table-actions>

 <div class="payhoa-table-responsive fadeIn animated" [class.no-scroll]="(isLoading || 
     (tableDataSource.loading$ | async))">
 <mat-table [dataSource]="tableDataSource"
           [trackBy]="trackMember"
           class="payhoa-table"
           matSort
           matSortActive="name"
           matSortDirection="asc"
           matSortDisableClear="true"
           (contentChanged)="loadingState$.next(false); contentChanged.emit()">
    <!-- render templates -->
    <ng-template #emptyCell><span class="add-ashy-blue">--</span></ng-template>

    <ng-container matColumnDef="select">
        <mat-header-cell *matHeaderCellDef>
            <mat-checkbox [checked]="isAllSelected()"
                          [indeterminate]="hasASelection() && !isAllSelected()"
                          (change)="$event ? masterToggle() : null"></mat-checkbox>
        </mat-header-cell>
        <mat-cell *matCellDef="let row">
            <mat-checkbox [checked]="selection.isSelected(row)"
                          (change)="$event ? toggleSelection(row) : null"></mat- 
    checkbox>
        </mat-cell>
    </ng-container>

    <!-- columns -->
    <ng-container matColumnDef="name">
        <mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'Name' }}</mat-header- 
     cell>
        <mat-cell *matCellDef="let row">
            <app-button type="link"
                        [buttonClasses]="['mr-0']"
                        [routerLink]="['/app/members/' + row.id]">
                {{ row.name }}
            </app-button>
        </mat-cell>
    </ng-container>

    <ng-container matColumnDef="email">
        <mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'Email' }}</mat-header- 
     cell>
        <mat-cell *matCellDef="let row">
            <span *ngIf="row.email; else emptyCell" class="w-100">
                {{ row.email }}
            </span>
        </mat-cell>
    </ng-container>

    <ng-container matColumnDef="status">
        <mat-header-cell *matHeaderCellDef class="mat-column-shorter" mat-sort-header> 
    {{ 'Owner Status' }}</mat-header-cell>
        <mat-cell *matCellDef="let row" class="mat-column-shorter">{{ row.status }} 
   </mat-cell>
    </ng-container>

    <ng-container matColumnDef="permission">
        <mat-header-cell *matHeaderCellDef class="mat-column-shorter" mat-sort-header 
      >{{ 'Permissions' }}</mat-header-cell>
        <mat-cell *matCellDef="let row" class="mat-column-shorter">
            {{ row.permission }}
        </mat-cell>
     </ng-container>

    <ng-container matColumnDef="lastLogin">
        <mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'Last login' }}</mat- 
    header-cell>
        <mat-cell *matCellDef="let row">
            <ng-template #neverLoginCell><span class="add-ashy-blue">{{ 'Never' }} 
    </span></ng-template>
            <span *ngIf="row.lastLogin; else neverLoginCell">{{ row.lastLogin | 
     legfiDate:'MM/DD/YYYY' }}</span>
        </mat-cell>
    </ng-container>

    <ng-container matColumnDef="unitsString">
        <mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'Units' }}</mat-header- 
      cell>
        <mat-cell *matCellDef="let row">
            <ng-container *ngIf="row.units.length > 0; else emptyCell">
                <span class="d-flex flex-column align-items-start">
                    <ng-container *ngFor="let unit of row.units">
                        <app-unit-button [unit]="unit"
                                         [isDisabled]="!hasUnitAccess"
                                         [routeTo]="'/app/unit/detail/' + unit.id"> 
      </app-unit-button>
                    </ng-container>
                </span>
            </ng-container>
        </mat-cell>
    </ng-container>

    <ng-container matColumnDef="tags">
        <mat-header-cell *matHeaderCellDef>{{ 'Tags' }}</mat-header-cell>
        <mat-cell *matCellDef="let member">
             <lf-tags *ngIf="!isLoading && !(tableDataSource.loading$ | async)"
                      taggableType="Owner"
                      taggableMode="Table"
                      [doSuppressHoverButton]="true"
                      [taggableId]="member.id"
                      [isEditable]="true"
                      [hasArchived]="membersStatusFilter === 'archived'"
                      [(items)]="member.tags">
             </lf-tags>
        </mat-cell>
    </ng-container>

    <ng-container matColumnDef="actions">
        <mat-header-cell *matHeaderCellDef>{{ 'Actions' }}</mat-header-cell>
        <mat-cell *matCellDef="let row">
            <ng-container *ngIf="actionsTemplate">
                <ng-container *ngTemplateOutlet="actionsTemplate; context: { member: 
       row }"></ng-container>
            </ng-container>
        </mat-cell>
    </ng-container>

    <div *matNoDataRow class="table-row mat-empty">
        <app-jumbotron [headerText]="isLoading || (tableDataSource.loading$ | async) ? 
      ' ' : 'No owners to display.'"
                       [classList]="['mx-5']"
                       [showEmptyImg]="false">
        </app-jumbotron>
    </div>

    <mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat-header- 
  row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>


<!-- loading -->
<div *ngIf="isLoading || (tableDataSource.loading$ | async)" class="payhoa-loading 
      animate fadeIn">
    <mat-spinner [diameter]="60"
                 [strokeWidth]="8"></mat-spinner>
  </div>
</div>

   <mat-paginator [disabled]="isLoading || (tableDataSource.loading$ | async)"
           [length]="totalRecords"
           [pageSizeOptions]="pageSizeOptions" [pageSize]="pageSize"
           (page)="loadingState$.next(true)">
   </mat-paginator>

app-table-actions component typescript

@Directive({
    selector: '[bulkActions]',
   })
 export class TableBulkActionsDirective
   {
   constructor(public templateRef: TemplateRef<unknown>) {
   }
 }

@Component({
   selector: 'app-table-actions',
   templateUrl: './table-actions.component.html',
   })
export class TableActionsComponent implements OnChanges
 {
// search, if applicable
 @Input() searchValue: string;
 @Output() searchValueChange: EventEmitter<string> = new EventEmitter<string>();

// columns menu
@Input() tableType: TableTypeNames;
@Input() columnMap: ColumnMap[];
@Input() newColumnButton = false;
@Input() selectedColumns: SelectionModel<TableColumn>;
@Output() selectedColumnsChange: EventEmitter<SelectionModel<TableColumn>> = new 
EventEmitter<SelectionModel<TableColumn>>();

// actions menu
@Input() selectionCount = 0;
@Input() actionsType: ButtonType = 'default';

// ng-content for mat-menu-items and bulk actions
@ContentChild(TableActionsDirective) items!: TableActionsDirective;
@ContentChild(TableActionsMobileDirective) mobileItems!: TableActionsMobileDirective;
@ContentChild(TableBulkActionsDirective) bulkActionItems!: TableBulkActionsDirective;

showSearch = false;

constructor(private _host: HostListenerService) {
}

get availableColumns() {
    return this.columnMap.filter((column) => {
        if (!column.title) {
            return false;
        }

        if (column.disabled) {
            return !column.disabled();
        }

        return true;
    });
}

get actionsLabel() {
    return `Actions${this.selectionCount > 0 ? ' (' + this.selectionCount + ')' : 
 ''}`;
}

get mobileMode$() {
    return this._host.isMobileMode();
}

get tabletMode$() {
    return this._host.isTabletMode();
}

ngOnChanges(changes: SimpleChanges) {
    if (changes && changes.hasOwnProperty('searchValue')) {
        this.showSearch = true;
    }

    if (changes && changes.hasOwnProperty('columnMap')) {
        const keys = ColumnService.read(this.tableType);
        if (keys) {
            const values = this.columnMap.filter((column) => {
                return keys.indexOf(column.key) > -1;
            });

            this.selectedColumns.select(...values);
        } else {
            this.resetColumns();
        }
    }
}

search(term = '') {
    this.searchValue = term;
    this.searchValueChange.emit(term);
}

resetColumns() {
    const values = this.columnMap.filter((column) => {
        if (column.defaultShow) {
            return !!column.defaultShow();
        }

        return true;
    });

    this.selectedColumns.select(...values);
    ColumnService.clear(this.tableType);
}

storeColumns() {
     ColumnService.store(this.tableType, this.selectedColumns.selected);
   }
 }

I’ve tried moving the div tags at the beginning inside the app-table-actions tag it doesn’t show on the page. I tried moving just the button and mat-menu without the div tags and it doesn’t show. Do I need to create a separate component for the button and mat-menu? Or could it be an issue with the app-table-actions?

It looks like the issue might be with how Angular handles content projection within the app-table-actions component. Try wrapping the button and mat-menu inside an ng-container to ensure Angular treats them correctly within the component’s structure. If that doesn’t work, creating a separate component for the button and mat-menu might be the best solution to maintain clarity and reusability. Similar to how factors like the sonic route 44 price vary by location, certain Angular elements behave differently based on their placement and structure.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.