How to filter the data from API json using ionic? - ionic-framework

I would like to have a search bar that filters the results I tried to do it but it does not work. When I'm looking for something, nothing happens, no mistake, so I'm wrong, but I do not know what, I'm new to typescript and I ask for help. Thanks in advance
Home.html
---------
<ion-searchbar (ionInput)="filterItems()"
[showCancelButton]="shouldShowCancel" (ionCancel)="onCancel($event)"></ion-searchbar>
<ion-list>
<ion-item *ngFor="let item of items" (click)="itemClick(item.id)">
<h1>{{item.id}}</h1>
{{item.title}}
</ion-item>
</ion-list>
Home.ts
-------
export class HomePage {
public items:any;
constructor(public http:HttpClient) {
this.loadData();
}
searchTerm: string ;
loadData() {
let data:Observable<any>;
data = this.http.get('https://jsonplaceholder.typicode.com/photos');
data.subscribe(result => {
this.items = result;
this.filterItems= this.items;
})
}
filterItems(ev:any){
this.loadData();
const val = ev.target.value;
this.filterItems = this.items.filter(item =>
{
item.titre.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1;
})
}
itemClick(itemid:number){
alert(itemid);
}
}

so you can do this in your html
<ion-searchbar [formControl]="searchTerm"></ion-searchbar>
Then in your .ts file declare before the constructor
public searchTerm: FormControl;
Then inside your ngOnInit, have this function that listens to user input and waits a while before filtering
this.searchTerm.valueChanges
.pipe(debounceTime(700))
.subscribe(search => {
this.items = this.filterItems(search);
});
Then your final method for the filter
filterItems(search) {
this.items = this.filterItems;
return this.items.filter(item => {
return item.titre.toLowerCase().indexOf(search.toLowerCase()) > -1
});
}
I hope this helps

Related

Search bar (ionInput) event to filter output

I am 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 : {{anime.t}}</h2>
</ion-item>
</ion-list>
My .ts file
getanimelist(){
this.restProvider.getanimelist().subscribe(data => {
this.animelist = data;
console.log('result ' + JSON.stringify(data) );
});
this.items= this.animelist;
}
onSearchChange(evt: any) {
this.getanimelist();
console.log(this.items);
console.log(evt);
const val = evt.srcElement.value;
console.log(val);
if (!val){
return ;
}
this.animelist = this.items.filter((data) => {
// console.log(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 : {{anime.t}}</h2>
</ion-item>
</ion-list>
My .ts file
getanimelist(){
//this.isLoaded = true;
this.restProvider.getpageanimelist().subscribe(data => {
this.animelist = data;
//console.log('result ' + JSON.stringify(data) );
});
this.items= this.animelist;
}
onSearchChange(evt: any) {
this.getanimelist();
const val = evt.srcElement.value;
console.log(this.items);
console.log(evt);
console.log(val);
if (!val){
return ;
}
this.animelist = this.items.filter((data) => {
// console.log(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 stored the filter data in a new array rather than in animelist array (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 the new array in my html and now when i type the name of the anime the list get filtered accordingly without any issue.
Changed 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 newarray" >
<ion-item >
<h2>Name : {{anime.t}}</h2>
</ion-item>
</ion-list>

Filter results with ion-select

I am new to ionic, following some tutorials and trying to learn and apply other stuff. I think what I'm trying to achieve is quite simple, but I can't seem to have it working.
What I'm trying to do is simply to filter results using the ion-select element to display its correspondent pick from the select.
So what I have is this ion-select where I'm using the ngModel and ngFor to filter which options the user should have, and once the user select their option, the app should only display the correspondent results, in this case, a Sport (so if the user picks 'Soccer' in the ion-select, only the 'Soccer' ion-cards should be displayed, I have those connected in the back end.
I'm adding here a piece of the code, but I'm afraid you might need other piece of code to get it more clear, so let me know please. Cheers guys!
<ion-content padding>
<ion-item>
<ion-label>Filter by Sport</ion-label>
<ion-select [(ngModel)]="list" multiple="true">
<ion-option *ngFor="let item of list">{{item.sport}}</ion-option>
</ion-select>
</ion-item>
<ion-card *ngFor="let item of list">
<ion-card-content>
<ion-card-title>{{item.title}}</ion-card-title>
<p>Sport: {{item.sport}}</p>
<p>Participants: {{item.players}}</p>
<p>When: {{item.when}}</p>
<p>{{item.description}}</p>
<p>Location: {{item.location}}</p>
<button ion-button block (click)="joinEvent(item)">Join!</button>
</ion-card-content>
</ion-card>
</ion-content>
Edit: Added .ts code below:
export class JoinEventPage {
filterListBy$
filteredList$
list: IEvent[];
joined = [];
constructor(public navCtrl: NavController,
public navParams: NavParams,
public eventProvider: EventsProvider,
public joinedEventsProvider: JoinedEventsProvider) {
}
ionViewDidEnter(){
// create observable
this.filterListBy$ = Observable.from(this.list)
// pull out just the name of the sport
.map((a: any) => a.sport)
// make sure items are distinct
.distinct()
// return an array
.toArray();
// force the initial filtering of the list
this.changeCategory([])
// this.eventProvider.listEvents().subscribe(res=>{
// this.list = res;
// }, error => {
// console.log("Error: " + error.message);
// });
// this.joinedEventsProvider.getStorage('joined-events').then(res => {
// if(res){
// this.joined = res;
// }
// });
}
ionViewDidLoad() {
console.log('ionViewDidLoad JoinEventPage');
}
joinEvent(item){
for(let event of this.joined){
if(event.id == item.id){
console.log("You already joined this event!")
return;
}
}
this.joined.push(item);
this.joinedEventsProvider.setStorage('joined-events', this.joined);
}
changeCategory(_value) {
// if nothing selected, show all
if (!_value.length) {
return this.filteredList$ = Observable.from(this.list).toArray();
}
// if something selected, filter the list based on the item selected which
// will be in the array parameter "_value"
this.filteredList$ = Observable.from(this.list)
.filter((i) => { return _value.indexOf(i.sport) !== -1 })
.toArray()
}
}
Solution: The only change I did to the .ts file following Aaron's solution is below:
ionViewDidEnter(){
this.eventProvider.listEvents().subscribe(res=>{
this.list = res;
// create observable
this.filterListBy$ = Observable.from(this.list)
// pull out just the name of the sport
.map((a: any) => a.sport)
// make sure items are distinct
.distinct()
// return an array
.toArray();
// force the initial filtering of the list
this.changeCategory([])
this.joinedEventsProvider.getStorage('joined-events').then(res => {
if(res){
this.joined = res;
}
});
});
}
see full answer here, but highlights are below
https://stackblitz.com/edit/ionic-tkqzr6
ngOnInit() {
// create observable
this.filterListBy$ = Observable.from(this.list)
// pull out just the name of the sport
.map((a: any) => a.sport)
// make sure items are distinct
.distinct()
// return an array
.toArray();
// force the initial filtering of the list
this.onChange([])
}
when the user selects an option, we call onChange
onChange(_value) {
// if nothing selected, show all
if (!_value.length) {
return this.filteredList$ = Observable.from(this.list).toArray();
}
// if something selected, filter the list based on the item selected which
// will be in the array parameter "_value"
this.filteredList$ = Observable.from(this.list)
.filter((i) => { return _value.indexOf(i.sport) !== -1 })
.toArray()
}
now in the html
<ion-item>
<ion-label>Filter by Sport</ion-label>
<ion-select multiple="true" (ionChange)="onChange($event)">
<ion-option *ngFor="let item of (filterListBy$ | async)">{{item}}</ion-option>
</ion-select>
</ion-item>

Search Bar and Results from php script

Hello i have created a SearchPage but i don’t know how to return the search results with the php script. I already made an authservice provider to connect with the database and works fine any time i call it to return the session user’s data. I want the user to type in letters on the search bar and the results to be displayed on
<ion-content padding>
<ion-card *ngFor="let item of dataSet; let msgIndex = index">
authservice.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
let apiUrl = "http://localhost/PHP-Slim-Restful1/api/";
#Injectable()
export class AuthService {
constructor(public http: Http) {
console.log('Hello AuthService Provider');
}
postData(credentials, type){
return new Promise((resolve, reject) =>{
let headers = new Headers();
this.http.post(apiUrl+type, JSON.stringify(credentials), {headers: headers}).
subscribe(res =>{
resolve(res.json());
}, (err) =>{
reject(err);
});
});
}
}
SearchPage.ts
#Component({ selector: "page-search", templateUrl: "search.html" })
export class SearchPage {
public userDetails: any;
public resposeData: any;
public dataSet: any;
public noRecords: boolean;
userPostData = {
uid: "",
token: "",
username: "",
bio: "",
profile_pic: "",
message: "",
msg_id: "",
title: "",
description: "",
media_pic: "",
created: "",
uid_fk: ""
};
constructor(
public common: Common,
public navCtrl: NavController,
public app: App,
public menu: MenuController,
public authService: AuthService,
platform: Platform,
statusBar: StatusBar,
splashScreen: SplashScreen
) {
const data = JSON.parse(localStorage.getItem("userData"));
this.userDetails = data.userData;
this.userPostData.uid = this.userDetails.uid;
this.userPostData.token = this.userDetails.token;
this.userPostData.username = this.userDetails.username;
this.userPostData.msg_id = this.userDetails.msg_id;
this.userPostData.message = this.userDetails.message;
this.userPostData.title = this.userDetails.title;
this.userPostData.description = this.userDetails.description;
this.userPostData.media_pic = this.userDetails.media_pic;
this.userPostData.created = this.userDetails.created;
this.userPostData.profile_pic = this.userDetails.profile_pic;
this.userPostData.bio = this.userDetails.bio;
this.noRecords = false
this.SearchResults();
}
SearchResults() {
this.authService.postData(this.userPostData, "userGroupSearch").then(
result => {
this.resposeData = result;
if (this.resposeData.userGroupSearch) {
this.dataSet = this.resposeData.userGroupSearch;
console.log(this.dataSet);
} else {
console.log("No access");
}
},
err => {
//Connection failed message
}
);
}
i call the PHP function in here userGroupSearch is the name of the function
this.authService.postData(this.userPostData, "userGroupSearch").then(
And the JSON returns in here
this.dataSet = this.resposeData.userGroupSearch;
SearchPage.html
<ion-header>
<ion-navbar>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-searchbar [(ngModel)]="myInput"
[showCancelButton]="shouldShowCancel"
(ionInput)="onInput($event)"
(ionCancel)="onCancel($event)"
placeholder="Search for Media, Artists, Flows...">
</ion-searchbar>
</ion-navbar>
<ion-content padding>
<ion-card *ngFor="let item of dataSet; let msgIndex = index"></ion-card>
</ion-content>
well i will assume your authservice provider works fine i will show you this with php no framework and i will be doing no authentication with jwt or oauth or some authentication system but will go straight to your question:
first you may want to trigger a http request when the user presses enter or key up but lets go with key enter.
in the ion-searchbar remove the (ionInput) method and use the key.enter event in angular like this:
<ion-searchbar placeholder="search by name of articles" (keyup.enter)="search()" [(ngModel)]="search_content"></ion-searchbar>
now the search function will send a http get request using your authservice povider for me i called mine HTTPprovider here is the code:
search(){
if(this.search_content==""){
}else{
let loader = this.loader.create({
content: "please wait..."
});
loader.present();
this.HttpProvider.getData("search-post.php?search="+this.search_content).then((res)=>{
this.response_data = res;
if(this.response_data==null){
loader.dismiss();
}else{
this.result = this.response_data;
loader.dismiss();
}
})
}
}
let me explain this a bit, the search content which we binded to the ion-searchbar
will be checked if its empty if yes we do nothing or display nothing then we call our http service provider which sends a http request passing the search_content binded to the element and yes lest i forget we used a LoadingController which we called loader you could create a seperate service provider to handle that and import the provider to your file and then use the loadingcontroller that makes code cleaner, now the next is to return the response value of the http service and assign its value to a global variable called response_data. now this is important after this has been mapped dont use it directly in your view because it will throw an error once your search result returns nothing this seems to be a bug in ionic 3 i guess. once your done check if the response_data object is null if no then assign it to another value called result and finally dismiss our loading controller .......
for our php file:
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
header("Access-Control-Allow-Methods:PUT, GET, POST, DELETE, OPTIONS");
require_once "config/config.php";
require_once "config/error.php";
$conn = new config();
$get_var = htmlspecialchars($_GET["search"]);
$space_checker = preg_match("/\s/",$get_var);
$data = array();
if($get_var==""){
} else {
if($space_checker==0){
$sql = "SELECT * FROM post_content where header LIKE '%$get_var%' LIMIT 3";
$result = $conn->query($sql);
$rowcount = $conn->rowcount($result);
if($rowcount == 0){
}else{
foreach ($result as $key => $value) {
$data[] = $value;
}
print json_encode($data);
}
}elseif ($space_checker > 0) {
$value_explode = explode(" ",$get_var);
foreach ($value_explode as $key => $values) {
$sql = "SELECT * FROM post_content where header LIKE '%$get_var%' OR '%$values%' ";
}
$sql.="LIMIT 3";
$result = $conn->query($sql);
$rowcounts = $conn->rowcount($result);
if($rowcounts == 0){
}else{
foreach ($result as $key => $valuese) {
$data[] = $valuese;
}
print json_encode($data);
}
}
}
?>
for the php file first we check for number of spaces in between words using regular expression after that we then check if the get variable sent equals to an empty string
we display nothing then we check if number of spaces equals zero if it contains some search content and it equals zero basically it has some contents but no space inbetween the search. we search using the like keyword in php after we which we save it in an array and json_encode it i use limit 3 to return 3 contents only ofcourse there will be a pagination which i believe you know also.now if a space exist we explode it and get each of those words and search for the full text entered in the search and thier individual words and then return a json_encoded 3 contents..
and finally in our view we display it using *ngFor:
<ion-list style="margin-top:50px;">
<ion-item *ngFor="let items of result" >
<ion-thumbnail item-left>
<img src="{{ image }}/{{ items.file_name }}">
</ion-thumbnail>
<h4 style="font-weight:bolder;">{{ items.header }}</h4>
<p> <b><span style="font-size:10px;"> <ion-icon name="eye"></ion-icon> {{ items.clicks }} views</span>
<span style="font-size:10px;"> <ion-icon name="clipboard"></ion-icon> {{ items.month }}/{{ items.year }}</span>
</b></p>
</ion-item>
</ion-list>
and that should do.

How can i use *ngIf condition in below code?

Here I want to check the condition but I am not able to check.
<text-avatar id="av" item-start [text]="item.BN" [color]="item.color">
<ion-icon id="check" name="checkmark-circle" float-start></ion-icon>
</text-avatar>
As simple as that, where someBoolean can be any boolean value retrieved through component class
home.tst
. . .
class Home {
var someBoolean: boolean = false;
var myArray: any[];
constructor() {
// compare values with array here or in any other method
if (true) {
someBoolean = true;
}
}
}
home.html
<text-avatar id="av" item-start [text]="item.BN" [color]="item.color" *ngIf="someBoolean">
<ion-icon id="check" name="checkmark-circle" float-start></ion-icon>
</text-avatar>

Dynamically include files (components) and dynamically inject those components

Looking around the next I could not find the answer: How do I dynamicly include a file, based on prop change per say: here some sudo code to intrastate what I'm trying to do!
class Test extends React.Component {
constructor(props){
super(props)
this.state = { componentIncluded: false }
includeFile() {
require(this.props.componetFileDir) // e.g. ./file/dir/comp.js
this.setState({ componentIncluded: true });
}
render() {
return(
<div className="card">
<button onClick={this.includeFile}> Load File </button>
{ this.state.componentIncluded &&
<this.state.customComponent />
}
</div>
)
}
}
so this.props.componetFileDir has access to the file dir, but I need to dynamically include it, and can't really do require() as its seems to running before the action onClick get called. Any help would be great.
Em, Your code looks a bit wrong to me. So I created a separate demo for dynamic inject components.
While in different situation you can use different React lifecycle functions to inject your component. Like componentWillReceiveProps or componentWillUpdate.
componentDidMount() {
// dynamically inject a Button component.
System.import('../../../components/Button')
.then((component) => {
// update the state to render the component.
this.setState({
component: component.default,
});
});
}
render() {
let Button = null;
if (this.state.component !== null) {
Button = this.state.component;
}
return (
<div>
{ this.state.component !== null ? <Button>OK</Button> : false }
</div>
);
}
After you edited your code, it should be something similar to below:
class Test extends React.Component {
constructor(props){
super(props)
this.state = { customComponent: null }
this.includeFile = this.includeFile.bind(this);
}
includeFile() {
System.import(this.props.componetFileDir)
.then((component) => {
this.setState({ customComponent: component.default });
});
}
render() {
return(
<div className="card">
<button onClick={this.includeFile}> Load File </button>
{
this.state.customComponent
}
</div>
)
}
}