invalidpipeargument: '[object object']: error showing - firebase

So I am relatively new to Ionic and Firebase, and I am trying to display user data that already exists in Firebase.
Here is the error that I am getting:
invalidpipeargument: '[object object']: error showing.
I do know what the issue is after looking at other questions similar to mine. It seems I cannot assign the async function as database.object does not return an observable. So I have tried to add .valueChanges(); to make it an observable, but I believe this is clashing with the angularfireobject as that is already assigned to the variable profile.data so this would not work.
I have also tried this:
// get (): AngularFireObject<any[]>{
//return this.afDatabase.list`/profile/${data.uid}`;
//}
If you point me in the right direction that would be great.
Here is my code:
.ts file
import { Component } from '#angular/core';
import { NavController, ToastController } from 'ionic-angular';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFireDatabase, AngularFireObject} from 'angularfire2/database';
import { Profile } from '../../model/profile';
import { DEFAULT_INTERPOLATION_CONFIG } from '#angular/compiler';
#Component({
selector: 'page-about',
templateUrl: 'about.html'
})
export class AboutPage {
profileData: AngularFireObject<Profile>
// get (): AngularFireObject<any[]>{
//return this.afDatabase.list`/profile/${data.uid}`;
//}
constructor(private afAuth:AngularFireAuth, private afDatabase: AngularFireDatabase,
public navCtrl: NavController, private toast: ToastController) {
}
ionViewDidLoad() {
this.afAuth.authState.take(1).subscribe(data =>{
if (data && data.email && data.uid){
this.toast.create({
message: `Welcome to MatchMyFighter ${data.email}`,
duration: 3000,
}).present();
// this.profileData = this.afDatabase.object(`profile/${data.uid}`)
this.profileData = this.afDatabase.object(`/profile/${data.uid}`).valueChanges();;
}
else{
this.toast.create({
message:`could not autenticate`,
duration:3000
}).present;
}
})
}
}
.html
<p>
Username: {{(profileData | async)?.username}}
</p>

The call to valueChanges() converts the AngularFireObject<Profile> to an observable.
You have to change the type to Observable<Profile> like so:
profileData: Observable<Profile>;
constructor(private db: AngularFireDatabase) { } // other stuff emitted ...
ionViewDidLoad() {
// ...
this.profileData = this.db.object<Profile>(`/profile/${data.uid}`).valueChanges();
// ...
}

Related

The dom is not reflective of the actual value wen using onPush strategy with ngrx store subscription

component file:
// Angular and 3rd party libs imports
import { ChangeDetectionStrategy, Component, OnInit } from '#angular/core';
import { Store } from '#ngrx/store';
import { UntilDestroy, untilDestroyed } from '#ngneat/until-destroy';
// Utils
import { ApiLoadInfo, ApiStateEnum } from 'src/app/shared/utils/states';
// Services
import { TestPortalService } from '../../../testportal.service';
import { SharedClient } from 'src/app/shared/services/shared.service';
// Redux
import {
CandidateInstructionsState,
Quiz,
Instruction,
PageEnum,
LandingPageData
} from '../redux/candidate-instructions.state';
import * as instructionActions from '../redux/candidate-instructions.action';
import * as instructionSelects from '../redux/candidate-instructions.selector';
import { ActivatedRoute } from '#angular/router';
#UntilDestroy()
#Component({
selector: 'candidate-instructions-landing',
templateUrl: './instructions-landing.component.html',
styleUrls: ['./instructions-landing.component.scss', '../common.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CandidateInstructionsLandingComponent implements OnInit {
// Exposing constants to html template
ApiStateEnum = ApiStateEnum;
PageEnum = PageEnum;
// Variables
initDataLoadState: ApiLoadInfo;
data: LandingPageData;
constructor(private _store: Store<CandidateInstructionsState>,
private _activatedRoute: ActivatedRoute,
private _testPortalService: TestPortalService,
) {
_store
.select(instructionSelects.selectInitDataLoadState)
.pipe(untilDestroyed(this))
.subscribe((initDataLoadState) => {
console.log('is same ref?:', this.initDataLoadState === initDataLoadState)
this.initDataLoadState = initDataLoadState;
console.log(initDataLoadState)
console.log('----------')
});
_store
.select(instructionSelects.selectLandingData)
.pipe(untilDestroyed(this))
.subscribe((data) => {
this.data = data;
});
}
ngOnInit() {
this.loadInstructions();
}
loadInstructions() {
this._store.dispatch(instructionActions.setInitData()); // sets state to 'loading'
this._testPortalService.getTestInstructions(
this._activatedRoute.snapshot.params.quizOrInviteId,
(error, response) => {
if (error) {
// sets state to 'error'
this._store.dispatch(instructionActions.setInitDataFail({ errmsg: error.toString() }));
} else {
// sets state to 'loaded'
this._store.dispatch(instructionActions.setInitDataSuccess({ instructions: response }));
console.log(response);
}
}
);
}
}
html:
{{ initDataLoadState.state }}
console output:
ui:
I thought when onPush is set, the template will re-render if the variable ref is changed. And since redux store is immutable that is always supposed to happen (confirmed by logging in the console). But still the actual component data is not in sync with the UI ie. component value = "loaded" but value in ui = "loading". Why is it so?
If you don't want to or can't use the pushPipe you could do something like this to subscribe to the store data:
import { Component, OnDestroy, OnInit } from '#angular/core';
import { Subscription } from 'rxjs';
import { Store } from '#ngrx/store';
import { getData } from 'path/to/store';
import { YourType } from 'path/to/type';
#Component({
selector: 'subscribing-component',
templateUrl: './subscribing.component.html'
})
export class SubscribingComponent implements OnInit, OnDestroy {
data: YourType;
dataSubscription: Subscription;
constructor(store: Store) {}
ngOnInit(): void {
this.dataSubscription = this.store.select(getData).subscribe((data) => {
this.data = data;
});
}
// don't forget to unsubscribe
ngOnDestroy(): void {
if (this.dataSubscription) {
this.dataSubscription.unsubscribe();
}
}
}

retrieve data from firebase in ionic 3 and angular 5

Pls I need help in retrieving user data from firebase with AngularFireObject on logging in.
I have been able to save data to firebase but having issues retrieving it. Pls someone help out.
Many thanks in advance.
Ok, first you've to configure your AngularFireModule (I think you already do that). AngularFireModule.initializeApp(FIREBASE_CONFIG).
So, is a good way to create a model/service to handle your entities requests with firebase, something like this:
Model:
export interface Cutom {
key?: string,
name: string,
quantity: number,
price: number
}
Service:
import { Injectable } from '#angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Custom } from './../../models/custom.model';
#Injectable()
export class CustomService {
private customListRef;
constructor(private db: AngularFireDatabase) {
this.customListRef = this.db.list<Custom>('your-endpoint-at-firebase');
}
getCustomList() {
return this.customListRef;
}
}
In Component you will use your recently created service:
...
export class HomePage implements OnInit {
// remember to import the correct model
customList$: Observable<Custom[]>
constructor(
public navCtrl: NavController,
private customService: CustomListService
) {}
ngOnInit() {
this.customList$ = this.customService
.getCustomList()
.valueChanges();
}
or if you need the metadata too (like the ID):
ngOnInit() {
this.customList$ = this.customService
.getCustomList()
.snapshotChanges()
.pipe(
map(items => { // this needs to be imported with: import { map } from 'rxjs/operators';
return items.map(a => {
const data = a.payload.val();
const key = a.payload.key;
return {key, ...data};
});
}));
}
...
And the finally at your template:
<ion-item *ngFor="let item of customList$ | async">
{{item.name}}
</ion-item>
I hope it helps.

working with FirestoreDocument

I am working with FirestoreDocument and I am trying to retrieving document data.I am getting the post undefined.Below is my code for service and Component
PostService.ts
import { Injectable } from '#angular/core';
import { AngularFirestore,AngularFirestoreCollection,AngularFirestoreDocument} from 'angularfire2/firestore'
import {Post} from './post';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';
#Injectable()
export class PostService {
postsCollection: AngularFirestoreCollection<Post>
postDoc: AngularFirestoreDocument<Post>
constructor(private afs:AngularFirestore) {
this.postsCollection = this.afs.collection('posts',ref => ref.orderBy('published','desc'));
}
getPosts(){
return this.postsCollection.snapshotChanges().map(actions=>{
return actions.map(a=>{
const data=a.payload.doc.data() as Post
const id=a.payload.doc.id
return {id, ...data}
})
})
}
getPostData(id: string){
this.postDoc=this.afs.doc<Post>(`posts/${id}`)
return this.postDoc.valueChanges()
}
}
PostDetailComponent.ts
import { PostService } from './../post.service';
import { Component, OnInit } from '#angular/core';
import {ActivatedRoute} from '#angular/router';
import {Post} from '../post';
#Component({
selector: 'app-post-detail',
templateUrl: './post-detail.component.html',
styleUrls: ['./post-detail.component.css']
})
export class PostDetailComponent implements OnInit {
post: Post
constructor(
private route:ActivatedRoute,
private postService:PostService
) { }
ngOnInit() {
this.getPost();
console.log(this);
}
getPost(){
const id= this.route.snapshot.paramMap.get('id')
return this.postService.getPostData(id).subscribe(data=>this.post=data)
}
}
PostDetailComponent from console
PostDetailComponent {route: ActivatedRoute, postService: PostService}
post:undefined
postService:PostService {afs: AngularFirestore, postsCollection: AngularFirestoreCollection, postDoc: AngularFirestoreDocument}
route:ActivatedRoute {url: BehaviorSubject, params: BehaviorSubject, queryParams: BehaviorSubject, fragment: BehaviorSubject, data: BehaviorSubject, …}
__proto__:Object
My post from PostDetailComponent is undefined.
The rest of your code looks right, I think it's just that your console.log(this) is in the wrong spot.
ngOnInit() {
this.getPost(); <----- your getPost() function is asynchronous
console.log(this); <----- meaning this console.log runs before you get data from Firebase
so when this runs, posts is still undefined.
If you would console.log(this) *AFTER* you get data
from Firebase, then you should see the values OK.
}
getPost(){
const id= this.route.snapshot.paramMap.get('id')
return this.postService.getPostData(id).subscribe(data=>this.post=data)
^^^^^^^^^^^
ASYNC portion is right here
}
To fix it, move your console.log inside your subscription:
ngOnInit() {
this.getPost();
<--- From here
}
getPost(){
const id= this.route.snapshot.paramMap.get('id')
return this.postService.getPostData(id).subscribe(data=> {
this.post=data;
console.log(this); <--- To here
});
}
EDIT - Additional troubleshooting ref comments below.
getPost(){
const id= this.route.snapshot.paramMap.get('id')
console.log('id from route params is: ' + id); <---- log the *id* too
return this.postService.getPostData(id).subscribe(data=> {
this.post=data;
console.log(data); <--- log *data* instead
});
}
Since angular 6 there were changes on rxjs
// replace import 'rxjs/add/operator/map';
with import { map } from 'rxjs/operators';
Then include .pipe() inside PostService.ts file in getPosts() function
like this:
getPosts() {
return this.postCollection.snapshotChanges().pipe(map(actions => {
return actions.map( a => {
const data = a.payload.doc.data() as Post
const id = a.payload.doc.id
return { id, ...data }
})
})
)
}
Home someone helps, cheers !!!

Angular 6 http not working with single JSON item

Trying to get Wordpress data into my Angular 6 component.
When I return a single post via Wordpress REST API it produces the right data (http://w3stage.com/tricap/wp-json/wp/v2/properties/174), but the data is not making it through to my template.
service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class WordpressService {
constructor(private http: HttpClient) { }
getProperty(id): Observable<any[]> {
return this.http.get<any[]>('http://w3stage.com/tricap/wp-json/wp/v2/properties/'+id);
}
}
component:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { Location } from '#angular/common';
import { Observable } from 'rxjs';
import { WordpressService } from '../wordpress.service';
#Component({
selector: 'app-property-detail',
templateUrl: './property-detail.component.html',
styleUrls: ['./property-detail.component.scss']
})
export class PropertyDetailComponent implements OnInit {
property: Observable<any[]>;
constructor(
private route: ActivatedRoute,
private location: Location,
private wp: WordpressService
) {
this.getProperty();
}
getProperty(): void {
const id = +this.route.snapshot.paramMap.get('id');
this.property = this.wp.getProperty(id);
console.log(this.property);
}
ngOnInit(): void {
}
}
template:
{{ property.title.rendered }}
This generates the following error:
ERROR TypeError: Cannot read property 'rendered' of undefined
at Object.eval [as updateRenderer] (PropertyDetailComponent.html:8)
at Object.debugUpdateRenderer [as updateRenderer] (core.js:10782)
at checkAndUpdateView (core.js:10158)
at callViewAction (core.js:10394)
at execComponentViewsAction (core.js:10336)
at checkAndUpdateView (core.js:10159)
at callViewAction (core.js:10394)
at execEmbeddedViewsAction (core.js:10357)
at checkAndUpdateView (core.js:10154)
at callViewAction (core.js:10394)
However, when I adapt the code to return a bunch of posts from wordpress, I can get the data to work just fine in conjunction with an *ngFor loop. When I try an *ngFor loop with the single post result, same thing - no go.
You need to use safe navigation operator or *ngIf inorder to handle the delay of response from your asynchronous request,
change your template as,
{{ property?.title?.rendered }}
also you need to subscribe to the observable,
this.wp.getProperty(id).subscribe(data => {
this.property = data;
});

Data from firebase don't load?

I am trying to get data of a certain userId out of a firebase Database. But nothing happens? I am creating an AngularFireObject of typ Profile
like this:
profileData: AngularFireObject<Profile>;
There is no error in the code. the HTML is shown how i prefer it but without the data.
the only thing what isn't correct, is that the Methode ionViewDidLoad is shown as unused. But when i pass the code inside the constructor it doesn't has any effect.
Can someone help me with that? Thanks a lot!
import { Component } from '#angular/core';
import {IonicPage, NavController, NavParams, ToastController} from 'ionic-angular';
import {AngularFireAuth} from 'angularfire2/auth';
import {AngularFireDatabase, AngularFireObject} from 'angularfire2/database';
import {Profile} from '../../shared/models/profile';
/**
* Generated class for the HomePage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-home',
templateUrl: 'home.html',
})
export class HomePage {
profileData: AngularFireObject<Profile>;
constructor(private afAuth: AngularFireAuth, private afDatabase: AngularFireDatabase, private toast: ToastController,
public navCtrl: NavController, public navParams: NavParams) { }
ionViewDidLoad() {
this.afAuth.authState.subscribe(data => {
console.log(data.uid);
if (data && data.email && data.uid) {
console.log(data.email);
console.log(data.uid);
this.toast.create({
message: `Welcome to The APP, ${data.email}`,
duration: 5000
}).present();
this.profileData = this.afDatabase.object(`/profile/${data.uid}`)
console.log(this.profileData);
} else {
this.toast.create({
message: `Could not find authentication details`,
duration: 3000
}).present();
}
})
}
}
This is the HTML where i would like to load the data.
profile.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import {AngularFireAuth} from 'angularfire2/auth';
import {Profile} from '../../shared/models/profile';
import {AngularFireDatabase} from 'angularfire2/database';
#IonicPage()
#Component({
selector: 'page-profile',
templateUrl: 'profile.html',
})
export class ProfilePage {
profile = {} as Profile;
constructor(private afAuth: AngularFireAuth, private afDatabase: AngularFireDatabase,
public navCtrl: NavController, public navParams: NavParams) {
}
/*ionViewDidLoad() {
console.log('ionViewDidLoad ProfilePage');
}*/
createProfile(){
this.afAuth.authState.take(1).subscribe(auth => {
this.afDatabase.object(`profile/${auth.uid}`).set(this.profile)
.then(() => this.navCtrl.setRoot('HomePage'))
})
}
}
<p>Username: {{(profile | async)?.username }}</p>
<p>First Name: {{(profile | async) ?.lastName }}</p>
<p>Last Name: {{(profile | async) ?.firstName}}</p>
There is a issue in the path. your path has a userid which concatenated with profile without separating it using slash (/)
Try to re correct path,
this.afDatabase.object(`/profile/${data.uid}`)
To retrieve data and view, do this way
this.afAuth.authState.subscribe(data => {
if (data && data.email && data.uid) {
this.afDatabase.database.ref().child(`/profile/${data.uid}`).once('value', (snapshot) => {
let result = snapshot.val();
for (let k in result) {
this.profileData = result[k];
}
});
}
});
**This is the html **
<p>Username: {{ profileData.username }}</p>
<p>First Name: {{ profileData.lastName }}</p>
<p>Last Name: {{( profileData.firstName}}</p>
in Homepage.ts
you only have to add take(1) in ligne 27 just like that :
this.afAuth.authState.take(1).subscribe(data => {

Resources