I'm using promise and http.get to fetch data from JSON API from Wordpress
After fetching the data, I will show the data on a page..
But the error show because the data is not available while building the page
How to solve that error ?
Here's my service code
loadPost(id) {
return new Promise(resolve => {
this.http.get('http://blog.macg.xyz/api/get_post/?id='+id)
.map(res => res.json())
.subscribe(post => {
this.post = post;
resolve(this.post);
console.log(this.post);
});
});
}
And here's the controller
export class PostPage {
public id:any;
public post: any;
public loading : any;
constructor(public postService: PostService, public navCtrl: NavController, params: NavParams, public loadCtrl: LoadingController) {
this.id = params.get("id");
// this.onPageWillEnter();
}
onPageWillEnter() {
// Starts the process
this.showLoading();
}
showLoading() {
this.loading = this.loadCtrl.create({
content: "Please wait..."
});
// Show the loading page
this.loading.present();
// Get the Async information
this.loadPost();
}
loadPost(){
this.postService.loadPost(this.id) // here where I call the service
.then(data => {
this.post = data;
console.log(this.post);
this.hideLoading();
});
}
hideLoading(){
// Hide the loading component
this.loading.dismiss();
}
}
Here's the html code
<ion-header>
<ion-navbar>
<ion-title>{{id}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
{{post.post.content}}
</ion-content>
And here's the error
Since the error is thrown from your template file, maybe post.post.content is throwing the error. If your post is null (which is true at first run), trying to reach its post variable may throw that error.
You can control whether the post is null or not, such as
<ion-content padding ng-if="post">
{{post.post.content}}
</ion-content>
You can use the elvis operator ? to avoid that error from being thrown when the post property is still null
<ion-header>
<ion-navbar>
<ion-title>{{id}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
{{post?.post.content}}
</ion-content>
Related
I can't make heads or tails of what I'm doing wrong here. I'm calling a new controller I'm setting up using JavaScript fetch(). I'm using MVC 5 within the React template.
The template controller (WeatherForecastController) works, if I call it using fetch, it'll hit the controller. Yet using the exact same implementation but for a new controller it won't touch the new controller. However Network debugger shows that it called and returned OK. If I call the controller directly through the browser, it's as if there isn't a route for it at all! No json is returned from my new controller vs the template controller. I'm simply trying to define a new controller I can fetch data from my Middle tier (.NET 6). Using .Net 6.0 as well.
Naming convention is correct as it ends with Controller in call.
DEFAULT TEMPLATE CONTROLLER CALL FROM JS
async populateWeatherData() {
const response = await fetch('weatherforecast');
const data = await response.json();
this.setState({ forecasts: data, loading: false });
}
DEFAULT TEMPLATE CONTROLLER
using Microsoft.AspNetCore.Mvc;
namespace ReactTest.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
Yet I call my controller I setup with the exact same implementation. If I try to call it I get exactly nothing!
NEW CONTROLLER TEMPLATE CALL FROM JS
async populateWeatherData() {
const response = await fetch('database');
const data = await response.json();
this.setState({ forecasts: data, loading: false });
}
IMPLEMENTATION OF NEW CONTROLLER (That I actually want to call)
using Microsoft.AspNetCore.Mvc;
namespace ReactTest.Controllers
{
[ApiController]
[Route("[controller]")]
public class DatabaseController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<DatabaseController> _logger;
public DatabaseController(ILogger<DatabaseController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
I've tried everything but modifying the default routing (the controller lives in the same folder as the template controller, so this shouldn't be why).
Before anyone asks:
ROUTING CONFIG:
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
ProjectFileDirectory
DatabaseControllerResponseHeader
So what exactly am I doing wrong? Yes I have read the documentation, no it hasn't helped.
Thanks in advance!
Hi i'm building a chat app with angular for a school project i'm using firebase for my backend and i have an issue with my ngfor.
For exemple if i reload the page i will see nothing unless i hover my routerlink on my navbar. However sometime it will work after some time on the page without any action
When i recieve message i need to be on the page to see them ...
When i reload my page in first time my array is empty this may be what makes the ngfor bug
array on reload.
I'm using ngOnInit() to subscribe :
messages: Message[];
messageSubscription: Subscription;
constructor(private messageService: MessageService, private router: Router) {
}
ngOnInit(): void {
this.messageSubscription = this.messageService.messageSubject.subscribe(
(messages: Message[]) => {
console.log(messages)
this.messages = messages;
}
);
this.messageService.getMessage();
this.messageService.emitMessage();
}
ngOnDestroy(): void {
this.messageSubscription.unsubscribe();
}
This is my html template :
<div *ngFor="let message of messages" class="message-box">
<img [src]="message.photoURL" class="profile-picture">
<div class="content-box">
<div class="information">
<p class="username">{{message.displayName}}</p>
<p class="date">{{message.createdAt | date: 'short'}}</p>
</div>
<p class="text">{{message.text}}</p>
</div>
</div>
Here you can find my service with my getMessage() function and emitMessage():
messages:Message[] = [];
messageSubject = new Subject<Message[]>();
constructor() { }
emitMessage(){
this.messageSubject.next(this.messages);
}
saveMessage(newMessage: Message){
firebase.database().ref('/message').push(newMessage);
}
getMessage(){
firebase.database().ref('/message')
.on('value', (data) => {
this.messages = data.val() ? Object.values(data.val()): [];
this.emitMessage();
});
}
And this is the repo of my project: https://github.com/Zuxaw/AngularChatApp
If anyone has a solution I'm interested
Problem is, your firebase library is not Angular specific.
This means you some times need to make sure its code, mostly its event callbacks, run within an Angular zone (google to read about it) to make sure a change detection 'tick' is invoked when data changes.
message.service.ts
import { Injectable, NgZone } from '#angular/core';
// ...
constructor(private zone: NgZone) { }
// ..
getMessage(){
firebase.database().ref('/message')
.on('value', (data) => {
this.zone.run(() => {
this.messages = data.val() ? Object.values(data.val()): [];
this.emitMessage();
});
});
}
I think you might need to use the child_added event instead of value in your getMessage method.
Check if you're receiving data on time in your getMessage method, if not it's most probably, because of the event.
But one thing that I don't understand is why you're calling emitMessage inside getMessage and also calling it inside your component after getMessage, try to evade that.
I got a problem where I cannot load a pdf inside a view of my app.
In my demo app for this I got two views, one "home" and one "result". In the home view I got a button which opens an android document picker with function pickDocument(). After a document has been picked the file name and file path get passed to the "result" view.
In my result view I convert the given path of the document picker to a native path in setPath(), but this path gives me a 404 on my device. I can't seem to load the file I want to display there.
The file has the local path (before converting it using setPath():
content://com.android.providers.downloads.documents/document/22
I get the following error:
Dummy-PDF.pdf:1 GET http://localhost/_app_file_/storage/emulated/0/Download/Dummy-PDF.pdf 404 (OK)
Is there anything I am missing? Or is there a better way to do, what I am trying to do? Could someone please help me to fix this issue.
I included the important code parts below. Thanks a lot.
Code of home.page.ts
...
export class HomePage {
constructor(private chooser: Chooser, private router: Router) { }
pickDocument() {
this.chooser.getFile("application/pdf")
.then(file => {
this.addFile(file.name, file.uri);
}, error => {
console.error(error);
});
}
addFile(fileName: string, fileUri: string) {
let navigationExtras: NavigationExtras = {
queryParams: {
"fileName": fileName,
"fileUri": fileUri
}
};
this.router.navigate(["result"], navigationExtras);
}
}
Code of result.page.ts
...
export class ResultPage implements OnInit {
public fileName: string;
public fileUri: string;
public path: string;
private win: any = window;
constructor(private route: ActivatedRoute, private filePath: FilePath) {
this.route.queryParams.subscribe(params => {
this.fileName = params["fileName"];
this.fileUri = params["fileUri"];
this.setPath();
});
}
ngOnInit() {
}
setPath() {
this.filePath.resolveNativePath(this.fileUri).then(path => {
this.path = this.win.Ionic.WebView.convertFileSrc(path);
});
}
}
Code of result.page.html
<ion-content>
<ion-list>
<ion-item>
<ion-img [src]="path"></ion-img>
</ion-item>
<ion-item>FileName: {{fileName}}</ion-item>
<ion-item>FileUri:{{fileUri}}</ion-item>
<ion-item>FilePath:{{path}}</ion-item>
</ion-list>
</ion-content>
I'm using angular2-jwt to authorize the requests. I've got a get request which retrieves multiple documents from the API.
A document can have multiple images which also need to be fetched using an authorized request.
So obviously calling them directly with doesn't work.
I followed this example: https://stackoverflow.com/a/40862839/909723
I've got two questions:
Without the async i get : GET http://localhost:4200/[object%20Object] 404 (Not Found)
And with the async i get : Invalid argument '[object Object]' for pipe 'AsyncPipe' I tried it with the 'data:image/jpg;' and without
Part of the template
<md-card *ngFor="let document of documents">
<md-toolbar color="accent" *ngIf="getDocName(document)">
<span class="nowrap">{{getDocName(document)}}</span>
<span class="country-full-width"></span>
</md-toolbar>
<md-card-content>
<div *ngFor="let image of getImages(document)">
<img class="image" [src]="getImageSrc(image.image_id) | async" />
</div>
</md-card-content>
</md-card>
I've got a service which uses angular2-jwt - AuthHttp
#Injectable()
export class ImageService {
constructor(public authHttp: AuthHttp, public http: Http, public sanitizer: DomSanitizer) {}
getImageSrc(id, type){
let url = Config.apiUrl + "/images/" + id + "/thumb.jpg"
let headers = new Headers();
headers.append('Content-Type', 'image/jpg');
return this.authHttp.get(url, {
headers: headers,
responseType: ResponseContentType.Blob
})
.map(res => {
return new Blob([res["_body]"]], {
type: res.headers.get("Content-Type")
});
})
.map(blob => {
var urlCreator = window.URL;
return this.sanitizer.bypassSecurityTrustUrl(urlCreator.createObjectURL(blob));
})
}
}
This is the function called in the template
getImageSrc(id)
{
return this.imageService.getImageSrc(id)
//.subscribe (
// data => data,
// err => console.log(err)
//);
}
Hope someone can help
I have faced the same problem and this solution helped: http://blog.jsgoupil.com/request-image-files-with-angular-2-and-an-bearer-access-token
Although you may need to change the way in which options are added to http request (in UrlHelperService) according to your angular version 2/4.
Also you need to change:
Observable
to
Observable<any>
all ower the place.
And
private _result: BehaviorSubject = new BehaviorSubject(null);
to
private _result: BehaviorSubject<any> = new BehaviorSubject('');
Is there a way to refresh only a page i.e. only one screen in ionic2.
I tried :
window.location.reload();
and
location.reload();
but it rebuilds the app .. is there a way to refresh only that page (particular screen).
Also tried:
<ion-input *ngIf="no_internet === 1" (click)="refresh($event)"></ion-input>
in TypeScript:
refresh(refresher) {
console.log('Begin async operation', refresher);
setTimeout(() => {
console.log('Async operation has ended');
refresher.complete();
}, 2000);
}
Try this code :
this.navCtrl.setRoot(this.navCtrl.getActive().component);
You could also use the ionic refresher, to create a pull to refresh action on the page
http://ionicframework.com/docs/v2/api/components/refresher/Refresher/
I would do that : (based on #Ahmad Aghazadeh answer)
this.navCtrl.push(this.navCtrl.getActive().component).then(() => {
let index = this.viewCtrl.index;
this.navCtrl.remove(index);
})
=> Push this page once more (loading it again)
=> Remove the page we were on (using index)
Example of using ion-refresher in an async function in ionic 3:
in your .html file:
<ion-content no-padding >
<ion-refresher (ionRefresh)="doRefresh($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
and in your .ts file:
constructor(...) {
...
samplefuncion(null){
asyncFunction().then(()=>{
...//after success call
...
if (event)
event.complete();
},(error)=>{
....
if (event)
event.complete();
})
}
doRefresh(event) {
samplefuncion(event);
}
If you are willing to follow a common convention, I have found a very easy way to reload the current view (including all of its parameters). I tested this using Ionic3, but it should still apply in Ionic 2
Move all of your initialization code for every page into ionViewDidLoad(), which is run ONCE on the first time the view is loaded
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Api } from '../../providers/api';
import { Movie } from '../../interfaces/movie';
#Component({
selector: 'page-movie-info',
templateUrl: 'movie-info.html'
})
export class MovieInfoPage {
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public api: Api
) {
}
/**
* Run all page initialization in this method so that this page
* can be refreshed simply by re-calling this function
*/
ionViewDidLoad() {
//access any parameters provided to the page through navParams.
var movieId = this.navParams.data.movieId;
this.api.movies.getById(movieId).then((movie) => {
this.movie = movie;
});
}
public movie: Movie;
}
From anywhere else in the app, you can reload the current view with this code
//get the currently active page component
var component = this.navController.getActive().instance;
//re-run the view load function if the page has one declared
if (component.ionViewDidLoad) {
component.ionViewDidLoad();
}
Html:
<ion-refresher (ionRefresh)="doRefresh($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
</ion-content>
TypeScript :
#Component({...})
export class NewsFeedPage {
doRefresh(refresher) {
console.log('Begin async operation', refresher);
setTimeout(() => {
console.log('Async operation has ended');
refresher.complete();
}, 2000);
}
}
source : Ionic doc
Try this, just pop one page and then push that page again.
this.navCtrl.pop();
this.navCtrl.push(NewPage);
Hope this will help.
Try this: $window.location.reload(); $route.reload() use to reload route.
if you are using $stateProvider : $state.go($state.current, {}, {reload: true});
or
var currentPageTemplate = $route.current.templateUrl;
$templateCache.remove(currentPageTemplate);
$route.reload();