I'm developing an Ionic app with angular. It has an API with php. So, I've a service that returns a JSON, the thing is, that the first time it loads the page, it doesn't load the data from the JSON.
The service:
import { Injectable } from '#angular/core';
import { HttpClient, HttpClientModule } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class PlayerService {
posts;
baseURL: String;
constructor(public http: HttpClient) {
this.baseURL = 'http://127.0.0.1:8000/'
}
getPlayers() {
this.http.get(this.baseURL + 'GetPlayers')
.subscribe(data => {
this.posts = data;
});
return this.posts;
}
How I load it:
#Component({
selector: 'app-players',
templateUrl: './players.page.html',
styleUrls: ['./players.page.scss'],
})
export class PlayersPage implements OnInit {
constructor(private playerService: PlayerService) { }
players = this.playerService.getPlayers();
ngOnInit() {
}
}
HTML:
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>Players</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor="let p of players">
<ion-label>
<h2>{{p.name}}</h2>
<h3>{{p.mail}}</h3>
</ion-label>
</ion-item>
</ion-list>
</ion-content>
You should be returning the observable on your component, instead of the service. This will ensure the data is loaded upon initialisation of the component.
#Component({
selector: 'app-players',
templateUrl: './players.page.html',
styleUrls: ['./players.page.scss'],
})
export class PlayersPage implements OnInit {
constructor(private playerService: PlayerService) { }
ngOnInit() {
this.playerService.getPlayers().subscribe(data => {
this.players = data;
});
}
}
And on your service.ts, make the following changes.
getPlayers() {
return this.http.get(this.baseURL + 'GetPlayers');
}
Do try to understand the purpose of services, and components. As stated on the Angular documentation,
Ideally, a component's job is to enable the user experience and
nothing more. A component should present properties and methods for
data binding, in order to mediate between the view (rendered by the
template) and the application logic (which often includes some notion
of a model).
On the other hand, the duty of fetching and saving data (carrying out of HTTP requests) should be delegated to services.
Related
I have a user.service, a list.page.ts and a list.page.html.
And I want to display data from the backend (php). I am getting Data in the console log, but it doesn't display on the website. Please Help.
Thank you!
user.servive
export enum SearchType {
all = '',
name = 'name',
stadt = 'stadt'
}
#Injectable({
providedIn: 'root'
})
export class UserService {
url = 'http://127.0.0.1:8000/getallrestaurants';
constructor(public http: HttpClient) { }
searchData(name: string, type: SearchType): Observable<any> {
return this.http.get('http://127.0.0.1:8000/getallrestaurants')
.pipe(
map(results => {
console.log('RAW: ', results);
return results['Search'];
})
);
}
list.page.ts
export class ListPage implements OnInit {
results: Observable<any>;
searchTerm = '';
type: SearchType = SearchType.all;
constructor(private userService: UserService) { }
ngOnInit() {}
searchChanged() {
this.results = this.userService.searchData(this.searchTerm, this.type);
}
list.page.html
<ion-searchbar [(ngModel)]="searchTerm" (ionChange)="searchChanged($event)"></ion-searchbar>
<ion-item>
<ion-label>Select Searchtype</ion-label>
<ion-select [(ngModel)]="type" (ionChange)="searchChanged($event)">
<ion-select-option value="">All</ion-select-option>
<ion-select-option value="stadt">Stadt</ion-select-option>
<ion-select-option value="name">Name</ion-select-option>
</ion-select>
</ion-item>
<ion-list>
<ion-item button *ngFor="let item of (results | async)" [routerLink]="['/', 'list', item.imdbID ]">
<ion-icon [name]="item.icon" slot="start"></ion-icon>
<p>Hallo User: {{item.name}}</p>
</ion-item>
This is my console.log, as you see i get the data, now i want it to show for example the name on frontend.
Ok I see the problem here in the class user.service you have to change it like this.
searchData(name: string, type: SearchType): Observable<any> {
return this.http.get('http://127.0.0.1:8000/getallrestaurants')
.pipe(
map(results => {
console.log('RAW: ', results);
return results;
})
);
}
You have to remove the ['Search'] because your JSON Response has no entry which is like 'Search'.
If you're seeing console.log update then this is most likely an issue with the html template not knowing some data changed that it needs to re-render and update the view for. Angular has built in change detection strategy but as the developer you can also manually interact with it. Checkout (https://angular.io/api/core/ChangeDetectorRef) for further explanation on this topic.
As for your code, try inserting the change detection reference as so by importing ChangeDetectorRef from #angular/core, and then check for changes of data to tell the view to re-render.
list.page.ts
export class ListPage implements OnInit {
results: Observable<any>;
searchTerm = '';
type: SearchType = SearchType.all;
constructor(private userService: UserService, private ref: ChangeDetectorRef) { }
ngOnInit() {}
searchChanged() {
this.results = this.userService.searchData(this.searchTerm, this.type);
this.ref.detectChanges()
}
Note: this will execute every time the user types and it may slow down your application because you're forcing angular to check for changes every time you call searchChanged(). I would thereby implement some sort of debounce technique to stall redundant or unnecessary calls to searchChanged(). Check out this resources to learn more about debouncing if this issue comes up (https://rxjs-dev.firebaseapp.com/api/operators/debounce).
I have data service that fetch data from my api:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { HttpClient, HttpParams } from '#angular/common/http';
#Injectable()
export class DataService {
constructor(private http: HttpClient) { }
showProducts(){
return this.http.get('http://localhost:8000/api/v1/products');
}
}
and my component
import { Component, OnInit } from '#angular/core';
import { DataService } from '../data.service';
//import { Products } from '../products';
#Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
products;
constructor(private data:DataService) { }
ngOnInit() {
this.showProducts();
}
showProducts() {
this.data.showProducts()
.subscribe(res => this.products = res);
}
}
and my html compopnent:
<div>
<table border="1">
<tr>
<th>Product</th>
<th>Code</th>
<th>Price</th>
<th>Action</th>
</tr>
<tr *ngFor="let product of products">
{{product.product_name}}
</tr>
</table>
</div>
the problem here that i got this error when i run my code in the browser:
1- ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
2- ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 21, nodeDef: {…}, elDef: {…}, elView: {…}}
Try this it may helps and see the console.log value too
showProducts() {
this.data.showProducts().subscribe(res => {
this.products = res;
console.log(this.products);
});
}
I suspect the response comming from the backend.
showProducts() {
this.data.showProducts()
.subscribe(res => this.products = res);
}
Just check the "res" here. It might not be an array hence the products.
Your respond from API must be JSON format, if not you should explicitly declare respondType in your service. something like:
apiUrl = 'http://localhost:8000/api/v1/products'
showProducts() {
return this.http.get<Product[]>(this.apiUrl, {observe: 'response',
resposeType: 'text'});
}
it seems nothing wrong with your DOM or Component.
Try this way it will help and also optimized and check console log value
showProducts(): void {
this.data.showProducts().subscribe(( this.products: any) => {
console.log(this.products);
});
}
I am new to Ionic 3 and mobile development. I am trying to connect a MySQL DB to my Ionic app and a PHP Restful API. I tested the API with Postman and it is working just fine, in order to implement it in Ionic I did the following,
I first made a provider named Authservice:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import 'rxjs/add/operator/map';
let apiUrl = "http://localhost/api/"
/*
Generated class for the AuthServiceProvider provider.
See https://angular.io/guide/dependency-injection for more info on
and Angular DI.
*/
#Injectable()
export class AuthServiceProvider {
constructor(public http: HttpClient) {
console.log('Hello AuthServiceProvider Provider');
}
postData(credentials, type) {
return new Promise((resolve, reject) => {
let headers = new HttpHeaders();
this.http.post(apiUrl + type, JSON.stringify(credentials), { headers: headers })
.subscribe(res => {
resolve(res.json());
}, (err) => {
reject(err);
});
});
}
}
And a Signup page:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { AuthServiceProvider } from '../../providers/auth-service/auth- service';
/**
* Generated class for the SignupPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-signup',
templateUrl: 'signup.html',
})
export class SignupPage {
responseData: any;
userData = {"username": "","password": "", "name": "","email": ""};
constructor(public navCtrl: NavController, public authServiceProvider: AuthServiceProvider) {
}
signUp() {
this.authServiceProvider.postData(this.userData, "signup").then((result) =>{
this.responseData = result;
console.log(this.responseData);
localStorage.setItem('userData', JSON.stringify(this.responseData));
});
}
goToLogin() {
this.navCtrl.pop();
}
}
When running this I am getting an Uncaught (in promise): [object Object] error as can be seen here.
UPDATE
I am now getting the following error:
Object { headers: {…}, status: 404, statusText: "Not Found", url: "http://localhost/PHP-SLIM-RESTFUL/API/signup", ok: false, name: "HttpErrorResponse", message: "Http failure response for http://localhost/PHP-SLIM-RESTFUL/API/signup: 404 Not Found", error: "<html><head><title>404 Page Not Found</title><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{display:inline-block;width:65px;}</style></head><body><h1>404 Page Not Found</h1><p>The page you are looking for could not be found. Check the address bar to ensure your URL is spelled correctly. If all else fails, you can visit our home page at the link below.</p>Visit the Home Page</body></html>" } signup.ts:36:6
postData(credentials, type) {
let headers = new HttpHeaders();
return this.http.post(apiUrl + type, JSON.stringify(credentials), { headers: headers });
}
this will return observable on the signup page, just subscribe it.
You can make use of Typescript's async methods to make your life easier
Your postData method in async
AuthServiceProvider:
public async postData(credentials, type): Promise<any> {
let headers = new HttpHeaders();
await this.http.post(apiUrl + type, JSON.stringify(credentials), { headers: headers }).toPromise();
}
Signup page:
public async signUp(): void {
try {
// request successful
this.responseData = await this.authServiceProvider.postData(this.userData, "signup");
console.log(this.responseData);
localStorage.setItem('userData', JSON.stringify(this.responseData));
}
catch(e) {
// some error occured, handle it here..
console.log(e);
}
}
Don't forget to import toPromise operator in AuthServiceProvider
import 'rxjs/add/operator/toPromise';
Try importing HttpModule in app.module.ts;
{import HttpModule } from '#angular/http'
Then add HttpModule to the imports;
imports :
[BrowserModule,
HttpModule,
IonicModule.forRoot(MyApp)
]
I want to get variable from my getData.php file that is in src/assets folder of angular project.
<?php
...
echo json_encode('test');
?>
get-data.service :
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
#Injectable()
export class GetDataService {
constructor(private http: Http) {}
getTest(): Observable<any> {
return this.http.get('assets/getData.php')
.map(response => response.json());
}
}
app.component :
import { Component } from '#angular/core';
import { GetDataService } from './services/get-data.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private getDataService: GetDataService) { }
title = 'Run Chart Generator';
data;
getTestTwo() {
this.getDataService.getTest()
.subscribe(data => {
this.data = data;
console.log(this.data)
});
}
}
When I call function getTestTwo I've got:
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
When I change php from echo json_encode('test') to echo 'test' and service from .map(response => response.json()) to .map(response => response) then I've got in console:
Object { _body: "<?php include('simple_html_dom.ph…", status: 200, ok: true, statusText: "OK", headers: Object, type: 2, url: "http://localhost:4200/assets/getDat…" }
How can I retrieve a variable from my php file?
#angular/cli: 1.4.1
#angular/core: 4.3.6
Your PHP file won't work under a NodeJS project.
You need to separate your Angular App from your server logic. Use Nginx or Apache to serve your PHP file, then you will be able to call it in your getTest() function.
How would one delete data from a MySql database using PHP code in an Angular2 application? The closest advice is for Angular 1 and is as follows:
$scope.deleteProduct = function(id){
// ask the user if he is sure to delete the record
if(confirm("Are you sure?")){
// post the id of product to be deleted
$http.post('delete_product.php', {
'id' : id
}).success(function (data, status, headers, config){
// tell the user product was deleted
Materialize.toast(data, 4000);
// refresh the list
$scope.getAll();
});
}
}
Is it possible to use the post method similarly:
import { Injectable } from '#angular/core';
import { Http, Response, Headers } from '#angular/http';
import 'rxjs/Rx';
#Injectable()
export class HttpService {
constructor(private http: Http) {}
deleteData() {
return this.http.post('delete_record.php')
}
}
Any insight/experience with Angular2/PHP would be appreciated.
Yes, the http post works similarly in angular2. Since you want to use post, i guess you also want to add a body to the request.
import { Injectable } from 'angular/core';
import { Http } from 'angular/http';
#Injectable()
export class HttpService {
constructor(private http: Http) {}
deleteData(data: SomeObject) {
let url = "delete_record.php";
let body = JSON.stringify(data);
return this.http.post(url, body)
.subscribe(
result => console.log(result),
error => console.error(error)
);
}
}
You can also send a delete request, which would be "best practice".
return this.http.delete(url)
.subscribe(
result => console.log(result),
error => console.error(error)
});
More about the http-client here https://angular.io/docs/ts/latest/guide/server-communication.html