Iam using search bar ionInput event to search among the list but filtered output is shown for one list and not shown for other list on other page?

my first list code :-
HTML

<ion-searchbar class="ion-no-padding" showcancelbutton="true" (ionInput)="onSearchChange($event)" placeholder="search manga"></ion-searchbar>
     <ion-list no-lines *ngFor="let anime of animelist" >
          <ion-item  >
           <h2>Name : &nbsp; {{anime.t}}</h2>   
    </ion-item>
        </ion-list>

My .ts file

getanimelist(){
  this.restProvider.getanimelist().subscribe(data => {
    this.animelist =   data;
  });
  this.items= this.animelist;
}

onSearchChange(evt: any) {
  this.getanimelist();
  const val = evt.srcElement.value;
  if (!val){
   return ;
  }
 this.animelist = this.items.filter((data) => {
    if (data.t && val){
      if (data.t.toLowerCase().indexOf(val.toLowerCase()) > -1){
   return true;
      }
      return false;
   
    }
  })
}

my api call for this:-

apiUrl= 'https://www.mangaeden.com/api';
getanimelist(){
    return this.http.get(this.apiUrl+'/list/0').pipe(
      map(result => {
        return result['manga'];
    })
    )}

the output for this list does get filter and my list do get updated on the page as per the value enterd but for my second list on other page iam using the same concept same code but my output is not getting filtered on the page, inside the console log i see the filtered result but my page list is not getting updated
second list code below :-
HTML

<ion-searchbar class="ion-no-padding" showcancelbutton="true" (ionInput)="onSearchChange($event)" placeholder="search manga"></ion-searchbar>
     <ion-list no-lines *ngFor="let anime of animelist" >
          <ion-item  >
           <h2>Name : &nbsp; {{anime.t}}</h2>   
    </ion-item>
        </ion-list>

My .ts file

getanimelist(){
  this.restProvider.getanimelist().subscribe(data => {
    this.animelist =   data;
  });
  this.items= this.animelist;
}

onSearchChange(evt: any) {
  this.getanimelist();
  const val = evt.srcElement.value;
  if (!val){
   return ;
  }
 this.animelist = this.items.filter((data) => {
    if (data.t && val){
      if (data.t.toLowerCase().indexOf(val.toLowerCase()) > -1){
   return true;
      }
      return false;
   
    }
  })
}

my api call for the 2nd list:-

getpageanimelist(){
      return this.http.get(this.apiUrl+'/list/0/?p=0&l=26').pipe(
        map(result => {
          return result['manga'];
      })
      )}

hope someone can help why is the filtered result not shown for my 2nd list ?

I find your code rather hard to read with all the weird spacing and debug prints and whatnot, but you seem to be trying to program imperatively in a reactive world, and that is a recipe for pain.

When data is coming from an asynchronous source (such as an HTTP request), the only place you can know that the result has arrived is inside the subscription block. What this means in practice is that if you’re assigning that result to controller properties (this.anything), you should treat those controller properties as write-only in your controller code (i.e. the rest of your .ts file). Never read from them unless you are OK with that read getting potentially stale data. Thanks to the magic of Angular change detection, you can read from these properties in the template, because Angular will do the right thing in terms of updating the template display when appropriate. Don’t try to read from them yourself in the controller until you have a much firmer grasp of how reactive programming feels.

So, the following line almost certainly isn’t doing anything useful, as you have no way of knowing what is sitting in animelist when it executes (specifically, it is extremely unlikely to execute after the lexically previous assignment to animelist inside the above subscription block).

this.items= this.animelist;

apologies for the ugly code , i edited it to be more readable and understandable.

i was able to fix this issue just 5 minutes ago but the above line certainly helps bcoz it sets the data stored in the animelist inside the the items array and if i dont set the data after the subscribe block it wont filter as when the data is set after which when i call the items.filter to filter out the data according to the user input i was able to search through the array with dynamic list filtering occurring simultaneously.
Also iam calling the method again inside my search event function so it does set the data what i fetch inside the items array , i can just make the whole thing one single method to avoid confusion but it helps me sort things out according to my need.

all i did was in the below code

i stored the filter data in a new array rather than in animelist (which is getting data from the api in the subscribe block) which was causing the whole array to call again and hence no filtered data can be viewed

my changed code in .ts

onSearchChange(evt: any) {
  this.getanimelist();
  const val = evt.srcElement.value;
  if (!val){
   return ;
  }
 this.newarray = this.items.filter((data) => { //stored data in new array
    if (data.t && val){
      if (data.t.toLowerCase().indexOf(val.toLowerCase()) > -1){
   return true;
      }
      return false;
   
    }
  })
}

and hence i call that array in my html and now when i type the name of the anime the list get filtered accordingly without any issue. it is not the accurate way of filtering the data form async source but it works.

Here’s what I’m trying to say. Try the following experiment:

$ mkdir /usr/local/src/node/scratch
$ cd /usr/local/src/node/scratch
$ echo '{}' > package.json
$ npm i --save typescript rxjs
$ npm i -g ts-node

If you’re on windows, hopefully it will be clear for you how to do something similar. Now put the following in main.ts in that folder:

import {Observable, of} from "rxjs";
import {delay} from "rxjs/operators";

class Service {
  getanimelist(): Observable<string[]> {
    return of(["dragonball", "gundam", "ultraman"])
      .pipe(delay(1000));
  }
}

class Page {
  animelist = ["moomin", "piglet", "eeyore"];
  items = ["flintstones", "jetsons", "scooby"];
  restProvider = new Service();

  getanimelist() {
    this.restProvider.getanimelist().subscribe(data => {
      this.animelist = data;
    });
    console.log("items were ", JSON.stringify(this.items));
    this.items = this.animelist;
    console.log("items now ", JSON.stringify(this.items));
  }
}

let page = new Page();
page.getanimelist();

To run it, ts-node main.ts.

Now move the bottom three lines of Page.getanimelist up to the top of the function, above the service call and subscribe block. Run it again. You should see the exact same result as before, and in neither case should the Japanese anime coming from the service be involved at all. That’s what I mean when saying that assignment isn’t doing what it looks like it is intended to do.

1 Like

now i understood what you are trying to say, it got confusing but I get it that assignment is not needed as the data coming from the subscribe block does not get involved . thank you for clearing the code and doubt.