2

I have a table which I successfully filter using a custom pipe. The filter is based on two inputs which are together a form. The functionality I want to add is for the filtering not to happen until a submit button is clicked. So it's more like a search button. I've found plenty of information on pipes, but nothing about activating them upon button clicks.

mainpage.component.html:

<div>
  <label>Start Date:</label>
  <input type="text" [(ngModel)]="startDateValue">
</div>
  <label>End Date:</label>
  <input type="text" [(ngModel)]="endDateValue">
</div>
//'let idx=index' and 'let even=even' are used to change color of the rows but I took out that code. The 'onClick' function just takes the row and uses an EventEmitter to output it.
<tr *ngFor="let dPoint of theData | searchDates:startDateValue:endDateValue; let idx=index; let even=even;" (click)="onClick(dPoint, idx)">
  <td>{{dPoint.tDataPoint}}</td>
  <td>{{dPoint.tICCP}}</td>
  <td>{{dPoint.tStartDate}}</td>
  <td>{{dPoint.tEndDate}}</td>
</tr>
//the button that will execute the filtering
<button type="submit" class="btn icon-search" [disabled]="!secondForm.valid" (click)="submit(secondForm.value)"></button>

mainpage.component.ts:

@Component({
  selector: 'main-page',
  styleUrls: ['../app.component.css'],
  templateUrl: 'mainpage.component.html',
  providers: [DataTableService, DatePipe]
})

export class MainPageComponent implements OnInit {
  secondForm : FormGroup;
  theData:DataTable[] = [];

  constructor(fb: FormBuilder, private datePipe: DatePipe, private dataService: DataTableService, private cdRef:ChangeDetectorRef){
    this.secondForm = fb.group({
      'startDate' : [null, Validators.required],
      'endDate' : [null, Validators.required]
    }, {validator: this.endDateAfterOrEqualValidator})
  }

  getTable(): void {
    this.dataService.getTable().then(theData => this.theData = theData);
    this.cdRef.detectChanges();
  }

  submit(value: any){
      //where I'd want to trigger the filtering/pipe
  }
}

search-pipe.ts:

import { Pipe, PipeTransform } from "@angular/core";

@Pipe({
  name: "searchDates"
})

export class SearchPipe implements PipeTransform {
  transform(value, minDate , maxDate){
    return value.filter(row => {
      return row.tStartDate >= minDate && row.tEndDate <= maxDate;
    });
  }
}
4
  • update your post with mainpage.component.html Commented Dec 29, 2016 at 19:54
  • @Aravind I tried to include minimal code, just enough so the question was understood. What part(s) of mainpage.component.html do you find confusing? Or what do you think is missing? Commented Dec 29, 2016 at 19:59
  • since your question is all about button click and custom pipe. where is the button triggering the click event? Commented Dec 29, 2016 at 20:00
  • @Aravind in my button tag where it says (click)="submit(secondForm.value)". I edited my question by adding the submit function, but it has nothing in it since that is what my question is asking. Commented Dec 29, 2016 at 20:04

2 Answers 2

5

You could consider dropping the pipe and instead just filtering the data yourself when the user clicks the button.

First, define a second property that represented the filtered result

let theFilteredData: DataTable[]

Change your binding to bind to theFilteredData instead:

*ngFor="let dPoint of theFilteredData;" //rest of *ngFor not included

In the submit function:

this.theFilteredData = this.theData.filter(row => 
      return row.tStartDate >= minDate && row.tEndDate <= maxDate);
Sign up to request clarification or add additional context in comments.

2 Comments

this gives me console error value.filter is not a function when I click my submit button which triggers submit function.
I think it's because value is the value of my form, which is from the two inputs. I need to filter the table, not the form
0

You can toggle the filtered for loop with a boolean value that is toggled when you click submit:

*.html:

<div>
    <label>Start Date:</label>
      <input type="text" [(ngModel)]="startDateValue">
    </div>
    <label>End Date:</label>
      <input type="text" [(ngModel)]="endDateValue">
    </div>
    <tr *ngIf="filterToggle" *ngFor="let dPoint of theData | searchDates:startDateValue:endDateValue; let idx=index; let even=even;" (click)="onClick(dPoint, idx)">
      <td>{{dPoint.tDataPoint}}</td>
      <td>{{dPoint.tICCP}}</td>
      <td>{{dPoint.tStartDate}}</td>
      <td>{{dPoint.tEndDate}}</td>
    </tr>
    <tr *ngIf="!filterToggle" *ngFor="let dPoint of theData; let idx=index; let even=even;" (click)="onClick(dPoint, idx)">
      <td>{{dPoint.tDataPoint}}</td>
      <td>{{dPoint.tICCP}}</td>
      <td>{{dPoint.tStartDate}}</td>
      <td>{{dPoint.tEndDate}}</td>
    </tr>
    //the button that will execute the filtering
    <button type="submit" class="btn icon-search" [disabled]="!secondForm.valid" (click)="submit()"></button>
</div>

*.ts:

submit() {
  this.filterToggle = !this.filterToggle;
}

Doesnt keep the template code down, but It should work.

Another idea would be to send a boolean 'filterToggle' through the pipe as well, so the pipe itself will not filter unless 'filterToggle' is true. So if you click submit, the toggle should change to true, and the pipe will filter.

so your *ngFor would look like this:

<tr *ngFor="let dPoint of theData | searchDates:startDateValue:endDate:filterToggle; let idx = index; let even=even">
  ...
</tr>

Or, you could just filter your actual data instead of putting it through a pipe.

submit(){
  this.theData = this.theData.filter(data => 
    return data.tStartDate >= this.startDateValue && data.tEndDate <= this.endDateValue);
}

So when you click submit, change your original theData array by filtering it. You may have to play around with the boolean expression that determines what will be filtered. It should keep only the 'data' that has a start date greater or equal to your 'this.startDateValue' and less or equal to your 'this.endDateValue'. However, this would be overwriting your original theData array. So I would create a temporary array so you can revert back to your unfiltered theData.

2 Comments

your first solution is more of work around than solution which I'd rather not try, but appreciate. Your solution to toggle a boolean works though! Also, how exactly would I filter the data instead of using pipe? I tried it like @DeborahK 's solution but that didn't work, as you'll see in the comments for her answer.
Yeah I am aware. I just love the power of the ngIf. I added the filtering solution to my response. Which is pretty much the same as Deborahs. I also think keeping this functionality in a pipe is better. So you can easily reuse else where in your project.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.