I am new to Ionic and I have a problem trying to push a rootpage on Ionic 3
On app.component.ts
import { Component } from '#angular/core';
import { LoginPage } from '../pages/login/login';
import { LoggedinPage } from '../pages/loggedin/loggedin';
import firebase from 'firebase';
#Component({
template: `<ion-nav [root]="rootPage"></ion-nav>`
})
export class MyApp {
rootPage: any;
var state = firebase.auth().onAuthStateChanged(function(user) {
if (user) {
this.rootPage = LoginPage;
//console.log(this.rootPage);
//from here i can see that the this.rootpage is defined.
} else {
this.rootPage = LoggedinPage;
}
console.log(this.rootPage);
//the rootpage is not defined outside of the funtion
});
}
What I want to do, id to redirect users that are already loggedin to the LoggedIn Page.
in app.component.ts
rootPage: any; is mistake, can you use rootPage: any = 'targetPage';
if you use menu rootPage: any = 'menuPage'; and chose rootPage in menuPage.ts ;
export class MenuPage {
rootPage = 'targetPage';
Need to change code following manner:
import {Component, ViewChild} from '#angular/core';
import {Nav} from 'ionic-angular';
import { LoginPage } from '../pages/login/login';
import { LoggedinPage } from '../pages/loggedin/loggedin';
import firebase from 'firebase';
#Component({
template: `<ion-nav [root]="rootPage"></ion-nav>`
})
export class MyApp {
rootPage: any;
#ViewChild(Nav) nav: Nav;
var state = firebase.auth().onAuthStateChanged(function(user) {
if (user) {
this.nav.setRoot(LoginPage);
//console.log(this.rootPage);
//from here i can see that the this.rootpage is defined.
} else {
this.nav.setRoot(LoggedinPage);
}
console.log(this.rootPage);
//the rootpage is not defined outside of the funtion
});
}
You should set userdata after login and clear on logout. and while setting rootPage you can check whether userdata does exist or not. And on initializeApp function of app.component.ts
initializeApp() {
this.platform.ready().then(() => {
this.rootPage = localStorage.getItem('userData') ? MyDashboardPage : LoginPage;
});
}
Related
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();
}
}
}
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 !!!
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();
// ...
}
I'm using React Native 0.36 and Firebase. How do I make the homepage of the app change if a user is logged in. I tried an if statement in renderScene but it gives this error:
index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
Navigator,
} from 'react-native';
import firebase from 'firebase';
import Login from './Login';
import Home from './Home';
function renderScene(route, navigator) {
return <route.component route={route} navigator={navigator} />;
}
export default class Snip extends Component {
renderScene(route, navigator){
return <route.component navigator={navigator} />
}
render() {
var that = this;
firebase.auth().onAuthStateChanged(function(user) {
if(user) {
return (
<Navigator
initialRoute={{component: Home}}
renderScene={that.renderScene}/>
)
} else{
return (
<Navigator
initialRoute={{component: Login}}
renderScene={that.renderScene}/>
)
}
});
}
}
There are two things that are wrong with the code from the question.
You cannot return a react element inside of a firebase callback
Firebase takes a moment to return if the user exists. So I have to create a loading state that get updated. When firebase is done.
index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
Navigator,
View,
Text,
} from 'react-native';
import firebase from 'firebase';
import Login from './Login';
import Home from './Home';
function renderScene(route, navigator) {
return <route.component route={route} navigator={navigator} />;
}
export default class Snip extends Component {
constructor(props) {
super(props);
this.state = {
user: null,
loading: false
};
}
componentWillMount() {
var that = this;
firebase.auth().onAuthStateChanged(function(user) {
if(user) {
that.setState({
user: user,
loading: false
})
}else{
that.setState({
loading: false
})
}
});
}
renderScene(route, navigator){
return <route.component navigator={navigator} />
}
render() {
if(this.state.loading){
return <View><Text>loading</Text></View>;
}else if(this.state.user){
return(
<Navigator
initialRoute={{component: Home}}
renderScene={this.renderScene}/>
)
}else{
return (
<Navigator
initialRoute={{component: Login}}
renderScene={this.renderScene}/>
)
}
}
}
I have been trying to display the Username of a Logged in user using Tracker React.
I have removed the auto-publish package.
/Client/components/dashboard/sidebar.jsx
import React, {Component} from 'react'
import TrackerReact from 'meteor/ultimatejs:tracker-react';
export default class Sidebar extends TrackerReact(Component) {
constructor() {
super();
this.state = {
subscription: {
users: Meteor.subscribe('users')
}
};
}
render() {
return(
<div>
<h1>{Meteor.user().username}</h1>
</div>
);
}
/Server/publications/userPublications
Meteor.publish("users", function () {
return Meteor.users.find();
});
I am getting a null object while console.log(Meteor.user()). However, I can see the current username using the Meteor DevTools for chrome.
What block of puzzle am I missing?
I doubt you can use Meteor.user(). username
Try this instead
<h1>{{currentUser}}</h1>
You can use createContainer in order to manage it.
import { Meteor } from 'meteor/meteor';
import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';
export class Sidebar extends Component {
static propTypes = {
loggedIn: PropTypes.bool.isRequired,
loggingIn: PropTypes.bool.isRequired,
currentUser: PropTypes.shape({
username: PropTypes.string
})
}
render() {
const { loggingIn, loggedIn } = this.props;
return (
<div>
{(() => {
if (loggingIn) {
return <Loading />
} else if (loggedIn) {
// whatever you want here.
} else {
<h1>Please Log In</h1>
}
})()}
</div>
)
}
}
export default createContainer(() => ({
user: Meteor.user(),
loggedIn: !Meteor.userId(),
loggingIn: Meteor.loggingIn()
}), Sidebar);
A few details here:
Meteor.loggingIn() is a reactive variable that is run while the user is logging in. When this is happening, there will not be a user object.
You should create a reactive container