0

I have a search bar functionality where I use ngOnChanges to detect the search term change, enabling me to filter through some data. However, if I use the previous search term value again, this change will not be caught. Now I know this makes sense because, effectively, there was no change to the search term property.

It seems when I use the 'x' clear button in the search bar, I can use the same search term once again. However, it's not working if I am to remove focus from the search bar and then try to repeat the search term.

My .ts:

@Component({
    selector: 'app-orders-list',
    templateUrl: './orders-list.component.html',
    styleUrls: ['./orders-list.component.css'],
})
export class OrdersListComponent implements OnChanges, AfterViewInit{
    
    @Input() searchTerm: string; // <----

    ngOnChanges(changes: SimpleChanges): void {
        // searchTerm comes from parent component, if it changes then a new search is active
        // want to detect when the current value equals previous value
        if (changes.searchTerm) {
            if(changes.searchTerm.currentValue === "") {
                /* do stuff */
            }
            else{
                /* do stuff */
            }
        }
    ...
    }
...
}

The search bar .ts:

@Component({
    selector: 'app-toolbar',
    templateUrl: './orders-toolbar.component.html',
    styleUrls: ['./orders-toolbar.component.css'],
})
export class OrdersToolbarComponent implements OnInit {

    @ViewChild('searchInput') searchInput: ElementRef;
    @Output() searchTerm = new EventEmitter<string>();
    @Output() isSearchActive = new EventEmitter<boolean>();
    hideSearchBar: boolean;
    searchString: string;
    searchStringUpdate = new Subject<string>();

    ngOnInit(): void {
        this.searchString = "";
        this.hideSearchBar = true;
        this.searchStringUpdate.pipe(
            debounceTime(500),
            distinctUntilChanged())
            .subscribe(() => {
                this.onSearchChange();
            }
        );
    }

    resetSearchBar() {
        this.searchString = "";
        this.onSearchChange();
        this.hideSearchBar = true;
        this.onSearchBarContext(false);
    }

    showSearchBar() {
        this.searchInput.nativeElement.focus();
        this.hideSearchBar = false;
        this.onSearchBarContext(true);
    }

    onSearchChange() {
        this.searchTerm.emit(this.searchString);
    }

    onSearchBarContext(isActive: boolean){
        this.isSearchActive.emit(isActive);
    }

    clearSearch(){
        this.searchString = "";
        this.onSearchChange();
    }
}

And for the search bar .html:

<div id="search" class="hide-searchbar" [ngClass]="{'show-searchbar': this.hideSearchBar === false}">
    <input
        id="searchbar"
        type="search"
        autocomplete="off"
        [(ngModel)]="searchString"
        (ngModelChange)="this.searchStringUpdate.next($event)"
        (blur)="resetSearchBar()"
        (search)="clearSearch()"
        (keydown.escape)="searchInput.blur()"
        #searchInput
    />
</div>
...
...

Thanks in advance.

double-beep
  • 5,031
  • 17
  • 33
  • 41
Manuel Brás
  • 413
  • 7
  • 21
  • 1
    Just like there being `currentValue`, I think there is another property called `previousValue`. Could that help? – AliF50 May 24 '21 at 20:18
  • @AliF50 Yeah, but the issue is that it doesn't go into `if (changes.searchTerm)` in the first place if `currentValue === previousValue`. Since I can't detect the change I can't apply the logic. Awkward situation. – Manuel Brás May 24 '21 at 20:24
  • 1
    I see. Can you remove that `if`? – AliF50 May 24 '21 at 20:25
  • @AliF50 I've tried it but it isn't triggered. It doesn't even go inside `ngOnChages` whatsoever. – Manuel Brás May 24 '21 at 20:28
  • 1
    https://stackoverflow.com/a/57557429/7365461 I think you can use a `setter` on the `input` instead of worry about it on the `ngOnChanges`. This way you should get notified even if the values are the same. – AliF50 May 24 '21 at 20:30
  • @AliF50 Still not working believe it or not. I've noticed this only happens when I remove focus from the search bar. When I press the clear 'x' button in the search bar it allows me to repeat the search term value. I'll post the search bar code. Tell me if you see something I don't. – Manuel Brás May 24 '21 at 20:38
  • 1
    Where is the `[searchTerm]="..."` in the HTML? And this issue is strange where `blur` behaves differently than `x`. Are you sure `resetSearchBar` gets called? – AliF50 May 24 '21 at 20:44
  • @AliF50 `resetSearchBar` is being called indeed. The search term is emitted to the parent component like so : `onSearchInserted(searchTerm: string){ this.searchTerm = searchTerm; }`. This `searchTerm` is then sent to the child `OrdersListComponent` through data binding. – Manuel Brás May 24 '21 at 20:50
  • @AliF50 Parent has `(searchTerm)="onSearchInserted($event)"` (emitted from search bar component). And then has `[searchTerm]="searchTerm"` (sent to the component in my question. – Manuel Brás May 24 '21 at 20:53
  • 1
    Shouldn't it be `[searchTerm]="searchString"`? – AliF50 May 24 '21 at 21:01
  • @AliF50 It works the way it is. It only doesn't work when I blur and use the same search value as the previous one. When I blur the search bar and use a different input it works, lol. This is so weird. – Manuel Brás May 24 '21 at 21:09
  • @AliF50 Finally managed to [solve it](https://stackoverflow.com/a/67679778/15822615). I appreciate your help nonetheless. – Manuel Brás May 24 '21 at 22:58
  • Awesome, glad you figured it out – AliF50 May 25 '21 at 00:47

1 Answers1

0

Removing distinctUntilChanged operator from the subscription inside ngOnInit did the trick.

Like so:

ngOnInit(): void {
    this.searchString = "";
    this.hideSearchBar = true;
    this.searchStringUpdate.pipe(
        debounceTime(500))
        .subscribe(() => {
            this.onSearchChange();
        }
    );
}

As the name would suggest, distinctUntilChanged only emits when the current value is different than the last.

Manuel Brás
  • 413
  • 7
  • 21