1
votes

I have implemented ng2-search-filter in angular 10 application which works perfectly fine and need to store the search criteria in ngrx/store. In the code below, the search variable is read into the template using ngModel. As per my understanding, action needs to be dispatched and generally is done via a method.How do I dispatch action in this scenario. I have written the dispatch logic below but not sure where to call it.I just hope I am doing it right.

Html

<div class="container">
  <div class="row">
    <div class="form-group">
      <input type="text" class="form-control" placeholder="Search Here" [(ngModel)]="term">
    </div>
    <div>
      <button class="btnAddCustomer" (click)="addCustomer()"> Add Customer (Template Driven) </button>
    </div>
  </div>
  <div class="row">
    <div class="col-12">
      <table id="customerdetails-table" class="table table-bordered table-striped table-responsive-md" *ngIf="customerDetails">
          <thead>
            <th>Customer</th>
            <th>Company Name</th>
            <th>Contact Name</th>
            <th>Contact Title</th>
            <th>Address</th>
            <th>City</th>
            <th>Region</th>
            <th>Postal Code</th>
            <th>Country</th>
            <th>Phone</th>
            <th>Fax</th>
            <th>Edit</th>
            <th>Delete</th>
          </thead>
          <tbody>
            <tr *ngFor="let custDetails of customerDetails.slice((currentPage - 1) * itemsPerPage,currentPage * itemsPerPage ) | filter:term ">
              <td>{{custDetails.customerId}}</td>
              <td>{{custDetails.companyName}}</td>
              <td>{{custDetails.contactName}}</td>
              <td>{{custDetails.contactTitle}}</td>
              <td>{{custDetails.address}}</td>
              <td>{{custDetails.city}}</td>
              <td>{{custDetails.region}}</td>
              <td>{{custDetails.postalCode}}</td>
              <td>{{custDetails.country}}</td>
              <td>{{custDetails.phone}}</td>
              <td>{{custDetails.fax}}</td>
              <td>
                <a [routerLink]="'/customers'" class="table-row-action edit-action"  (click)="editCustomer(custDetails)">
                  edit
                </a>
              </td>
              <td>
                <a [routerLink]="'/customers'" class="table-row-action edit-action"  (click)="deleteCustomer(custDetails.customerId)">
                  delete
                </a>
              </td>
            </tr>
          </tbody>
        </table>

     
      <pagination [(ngModel)]="currentPage" (pageChange)="pageChanged($event)" [totalItems]="totalItems" [itemsPerPage]="itemsPerPage" [maxSize]="maxSize"></pagination>

    </div>
  </div>
</div>

Component

export class CustomerComponent implements OnInit, OnDestroy  {
  customerDetails: ICustomer[];
  customer: ICustomer;
  public modal: any;
  totalItems: number;
  maxSize = 5;
  currentPage = 1;
  itemsPerPage = 8;
  term: string;
  isEdit: boolean;
  completed$ = new Subject<any>();

  constructor(private customerService: CustomerService,
              public modalService: NgbModal, private store: Store<any>
              ) {
  }

  ngOnInit(): void {
    this.getCustomerDetails();
  }

  getCustomerDetails(): void {
    this.customerService.getCustomerDetails()
      .subscribe(data => {
        this.customerDetails = data;
        this.totalItems = data.length;
      }
      );
  }

  ngOnDestroy(): void {
    this.completed$.next();                      // <-- close impending subscriptions
    this.completed$.complete();
  }

  pageChanged(currentPageIndex: number): void {
    this.currentPage = currentPageIndex;
 }
}

Reducer and Action

import { createReducer, createAction, on } from '@ngrx/store';

 export const customerReducer = createReducer(
    {term: '' },
    on(createAction('[Customer] Search Term'), state => {
      console.log('original state: ' + JSON.stringify(state));
      return {
        ...state,
         term: state.term
      };
    })
 );

Dispatching the action

  this.store.dispatch(
      {type: '[Customer] Search Term'}
    );

Screenshot of the devtools

enter image description here

1

1 Answers

0
votes

First you need to define what event you are going to use to fire the action.

Let say you pick change, then you could do something like this

html

<input type="text" class="form-control" placeholder="Search Here" [(ngModel)]="term" (change)="searchTermChange()">

ts

searchTermChange() {
  this.store.dispatch(customerChangeSearchTerm({ term: this.term }));
}

Where customerChangeTerm is the action. BTW, is a good practice to separete actions, reducers, selectors, effects into separate files.

One last thing, probably the more usual use case is to handle input event. In this case you will wait for x characters and then execute search.

UPDATE

Yeah I realize now that there are many things missing or wrong in your state process. First you are not passing the term in the action, second you are not updating the state with the new term.

Ok, so let review the process:

customers.actions.ts

import { createAction, props } from '@ngrx/store';

export const customerChangeSearchTerm = createAction(
  '[Customer] Change Search Term',
  props<{ term: string }>()
);

customers.reducers.ts

import {
  customersChangeSearchTerm
} from './auth.actions';
import { createReducer, on, Action } from '@ngrx/store';

export const initialState: CustomersState = {
  term: null
};

const reducer = createReducer(
  initialState,
  on(customerChangeSearchTerm, (state, payload) => ({
    ...state,
    term: payload.term
  }))
)

BTW, I change termChange to searchTermChange.