My aim is to display a list of individuals to in a table component and filter and or search based on certain criteria. My template code is as follows:
<div class="flex flex-col bg-gray-100 p-6 mx-auto w-auto">
<header class="bg-white shadow p-4 flex items-center justify-between">
<h1 class="text-lg font-bold">East Portland Constituency Voters </h1>
<div>
<button class="bg-blue-600 text-white px-4 py-2 rounded">Logout</button>
</div>
</header>
<br>
<div class="mt-8 bg-white p-6 rounded shadow mb-4">
<div class="card">
<p-table #dt
[value]="voters"
dataKey="id"
[rows]="10"
[globalFilterFields]="['firstName', 'lastName', 'email', 'affiliation', 'role', 'gender']"
[rowsPerPageOptions]="[10, 25, 50]"
[paginator]="true"
[tableStyle]="{ 'min-width': '75rem' }">
<ng-template pTemplate="caption">
<div class="flex justify-between">
<p-button label="Clear" [outlined]="true" icon="pi pi-filter-slash" (onClick)="clear(dt)" />
<span class="p-input-icon-left ml-autod">
<i class="pi pi-search"></i>
<input pInputText type="text" [(ngModel)]="searchValue"
(input)="dt.filterGlobal(getEventValue($event), 'contains')" placeholder="Search for voter" />
</span>
</div>
</ng-template>
<ng-template pTemplate="header">
<tr>
<th style="min-width:10rem">
<div class="flex align-items-center">
First Name
</div>
</th>
<th style="min-width:10rem">
<div class="flex align-items-center">
Last Name
</div>
</th>
<th style="min-width:15rem">
<div class="flex align-items-center">
Email
</div>
</th>
<th style="min-width:15rem">
<div class="flex align-items-center">
Affiliation
</div>
</th>
<th style="min-width:15rem">
<div class="flex align-items-center">
Role
</div>
</th>
<th style="min-width:15rem">
<div class="flex align-items-center">
Gender
</div>
</th>
</tr>
<tr>
<th></th>
<th></th>
<th></th>
<th style="min-width:15rem">
<div class="flex align-items-center">
<p-columnFilter field="affiliation" matchMode="in" [showMenu]="false">
<ng-template pTemplate="filter" let-filter="filterCallback" >
<p-multiSelect [(ngModel)]="selectedAffils" [options]="affiliations" placeholder="Any"
(onChange)="filter($event.value)">
</p-multiSelect>
</ng-template>
</p-columnFilter>
</div>
</th>
<th style="min-width:15rem">
<div class="flex align-items-center">
<p-columnFilter field="role" matchMode="in" [showMenu]="false">
<ng-template pTemplate="filter" let-filter="filterCallback">
<p-multiSelect [(ngModel)]="selectedRoles" [options]="roles" placeholder="Any"
(onChange)="filter($event.value)" >
</p-multiSelect>
</ng-template>
</p-columnFilter>
</div>
</th>
<th style="min-width:10rem">
<div class="flex align-items-center">
<p-columnFilter field="gender" matchMode="in" [showMenu]="false">
<ng-template pTemplate="filter" let-filter="filterCallback">
<p-dropdown [(ngModel)]="selectedGender" [options]="genders" placeholder="Any"
(onChange)="filter($event.value)" >
</p-dropdown>
</ng-template>
</p-columnFilter>
</div>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-voter>
<tr>
<td>
{{ voter.firstName }}
</td>
<td>
{{ voter.lastName }}
</td>
<td>
{{ voter.email }}
</td>
<td>
{{ voter.voterAffiliation }}
</td>
<td>
{{ voter.supporterRole }}
</td>
<td>
{{ voter.gender }}
</td>
</tr>
</ng-template>
<ng-template pTemplate="emptymessage">
<tr>
<td colspan="6">No voters found.</td>
</tr>
</ng-template>
</p-table>
</div>
</div>
</div>
Component Code:
import { VoterServiceService } from './../services/voter-service.service';
import { Component, inject, OnInit } from '@angular/core';
import { SUPPORT_ROLE, Voter, VOTER_AFFILIATION } from '../data/data.schema';
import { Table, TableModule } from 'primeng/table';
import { MultiSelect, MultiSelectChangeEvent } from 'primeng/multiselect';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-search-voters',
standalone: true,
imports:[TableModule, MultiSelect,CommonModule,FormsModule],
templateUrl: './search-voters.component.html',
styleUrl: './search-voters.component.css'
})
export class SearchVotersComponent implements OnInit {
selectedAffils: string[]
selectedRoles: string[]
selectedGender: string;
voter: Voter | undefined;
layout: string = 'list'
voters!: Voter[] | undefined;
genders: string[] | undefined;
roles: string[] | undefined;
affiliations: string[] | undefined;
private voterServiceService = inject(VoterServiceService);
searchValue:string | undefined;
loading:boolean;
ngOnInit(): void {
this.voters = this.voterServiceService.getVoters();
this.genders = [
'Male' ,
'Female',
];
this.roles = [
SUPPORT_ROLE.CLUSTER_SUPERVISOR ,
SUPPORT_ROLE.PD_CAPTAIN ,
SUPPORT_ROLE.INDOOR_AGENT ,
SUPPORT_ROLE.OUTDOOR_AGENT ,
SUPPORT_ROLE.COUNCILLOR ,
SUPPORT_ROLE.MINISTER_OF_PARLIAMENT ,
SUPPORT_ROLE.RUNNER ,
SUPPORT_ROLE.DRIVER ,
];
this.affiliations = [
VOTER_AFFILIATION.JLP,
VOTER_AFFILIATION.PNP,
VOTER_AFFILIATION.NK,
VOTER_AFFILIATION.DEAD,
];
}
viewSelect(select : MultiSelectChangeEvent){
console.log(select)
}
clear(table:Table){
table.clear();
this.selectedAffils = []
this.selectedGender = ''
this.selectedRoles = []
}
getEventValue(e: Event ){
return (e.target as HTMLInputElement).value
}
}
contents are being rendered but the input search functionality is working as it should. My issue is with the column filtering using the Multiselect and dropdown. Previously I tried implementing this following the documentation’s approach:
<p-columnFilter field="status" matchMode="equals" [showMenu]="false">
<ng-template pTemplate="filter" let-value let-filter="filterCallback">
<p-dropdown
[(ngModel)]="value"
[options]="statuses"
(onChange)="filter($event.value)"
placeholder="Select One"
[showClear]="true">
</p-dropdown>
</ng-template>
</p-columnFilter>
Utilizing the value on the ngmodel directive gave resulting in a Cannot use a non-signal variable ‘value’ in a two-way binding expression. Template variables are read-only.ngtsc(-99) error within the code. Not sure what could be the issue. Some help would be greatly appreciated.