Get data from subscribe in Ionic - ionic-framework

I'm having difficulty getting data with subscribe in the constructor of an Ionic page, basically I need to do the subscribe to get a list and show to the user, but I get undefinied
In my constructor, I do this:
this.getUser(this.auth.currentUser().uid);
console.log(this.user);
My getUser():
getUser(uid) {
const self = this;
this.auth.getUserData(uid).subscribe(function(doc) {
if (doc.exists) {
self.user = doc.data();
} else {
console.log("No such document!");
}
});
};
But, when i call other function with button, i get the data:
userf(){
console.log(this.user);
}
Obs: I use Firestore

The reason it gives you undefined is because your method “getUser” is async and when you call console.log the user value is not yet obtained.
So you should access user value inside your getUser method after it is received.
Now also you are trying to pass “this” into the getUser method with const. start using fat arrow functions which do not create their own scope (this):
getUser(uid) {
this.auth.getUserData(uid).subscribe((doc) => {
if (doc.exists) {
this.user = doc.data();
} else {
console.log("No such document!");
}
});
};

Related

Http get request URL shows [object promise]

I am trying to use web api call get method to access data and display in my page. My url would be something like: https://localhost:44399/api/APIOrder/GetUserOrder?email=xxx#gmail.com to be able to display the data.
However, when I combine my url with a variable,it doesn't display anything and console log shows the url in https://localhost:44399/api/APIOrder/GetUserOrder?email=[object Promise]. Is there any way to let the url read my this.User variable?
please review my getUserOrder()
User = this.storage.get('currentUser');
constructor(private http:Http,public storage: Storage){
}
public getUserOrder()
{
var url="https://localhost:44399/api/APIOrder/GetUserOrder?email=";
console.log(url+this.User);
return this.http.get(url+this.User).map(res=>res.json());
}
I am really new to this. Pls tell me if i am unclear. Any help would be much appreciated..
UPDATE
It shows undefined because it accessed the variable value on top but not from ionViewWillEnter
User:string;
constructor(private http:Http,public storage: Storage){
}
async ionViewWillEnter()
{
this.User = await this.storage.get('currentUser');
}
public getUserOrder()
{
var url="https://localhost:44399/api/APIOrder/GetUserOrder?email=";
console.log(url+ this.User);
return this.http.get(url+this.User).map(res=>res.json());
}
You should await the return of the Promise. You can do this inside the constructor or inside a lifecyle like ionViewWillEnter()
User: string;
async ionViewWillEnter() {
this.User = await this.storage.get('currentUser');
}
Answer here: "This is the expected result."
UPDATE
This is a different approach: if your function is directly called somehow, you can create a function which returns the variable from storage. If the data is found, proceed with the http request.
async getUserOrder() {
const user = await this.getUserFromStorage();
if (user) {
var url="https://localhost:44399/api/APIOrder/GetUserOrder?email=";
return this.http.get(url + user).map(res=>res.json());
}
}
async getUserFromStorage(): Promise<string> {
return await this.storage.get('currentUser');
}

Ionic Storage : Strange behavior?

I try to use the Ionic Storage module to store some values, for example my authentication token :
/**
* Get Token
*/
public get token(): string {
this.storage.get(this.LS_TOKEN).then((val) => {
console.log(val);
this._token.next(val);
console.log( this._token.getValue());
});
return this._token.getValue();
// return 'testtttt';
}
I try multiple things, return directly the value, set the value and return the variable...
But I always got a null, and the thing that is strange is that if I return a string directly it works, when I console.log the val it show the string that I want, but the return is always null..
What am I doing wrong ?
Edit :
In response of the first answer I have tried this :
/**
* Get Token
*/
public get token() {
this.tokenPromise().then(yourToken => {
console.log(yourToken);
return yourToken;
});
}
public tokenPromise() {
return new Promise((resolve, reject) => {
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex => {
reject(ex);
});
});
}
My problem is the same, in my components when I try to use : console.log(this.sharedService.token);
It's still null
It is not working with your new token() method.
It is still asnychron. Im gonna show you:
public get token() {
return new Promise((resolve, reject)=>{
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex=>{
reject(ex);
});
});
}
Now you can use your token from the sharedservice like this:
this.sharedService.token.then(token=>{
//use token here;
});
or you can use await, but the function who is calling it, must be async:
async useTokenFromService(){
let token = await this.sharedService.token;
console.log(token);
}
You are getting a Promise from the storage.get() method.
This means it is running asynchron.
You can return Promise.
public get token() {
return new Promise((resolve, reject)=>{
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex=>{
reject(ex);
});
});
}
And you can receive this with an async function and await the result:
async loadToken(){
let loadedToken = await this.token();
// use your loadedToken here...
}
Or you can use the .then method from the promise like this:
loadToken(){
this.token().then(yourToken=>{
// use the token yourToken here...
});
}

localstorage value visible only after page reload

When the user login I want to display the username of that user at the navbar. I have set the token and username to the localStorage after user succesfully login. My issue is username is not displayed at the navbar unless I refresh the page.
I am not sure how can I fix this problem.
Can anybody help me
Thank You.
login component
onSubmit = function () {
this.userService.loginUser(this.loginUserData).subscribe(
res => {
this.tokenService.handle(res);
this.authService.changeAuthStatus(true);
},
error => console.log(error)
);
}
auth service
export class AuthService {
private loggedIn = new BehaviorSubject<boolean>(this._tokenService.loggedIn());
authStatus = this.loggedIn.asObservable();
user = this.tokenService.getUser();
changeAuthStatus(value: boolean) {
this.loggedIn.next(value);
}
constructor(private tokenService: TokenService) {}
}
token service
handle(res) {
this.setToken(res);
}
setToken(res) {
localStorage.setItem('token', res.access_token);
localStorage.setItem('user', res.user);
}
getToken() {
return localStorage.getItem('token');
}
getUser() {
return localStorage.getItem('user');
}
}
navbar component
ngOnInit() {
this.authService.authStatus
.subscribe(
value => {
this.loggedIn = value
}
);
//set the username on navbar
this.user = this.tokenService.getUser();
}
You auth service function is a callback that will fire success or failure event when all operations are complete hence the code this.user = this.tokenService.getUser(); executed before the localstorage is populated. Try moving this code inside subscribe method of authService.authStatus.
ngOnInit() {
this.authService.authStatus
.subscribe(
value => {
this.loggedIn = value
}
);
//set the username on navbar
this.user = this.tokenService.getUser();
}
like this.
ngOnInit() {
this.authService.authStatus
.subscribe(
value => {
this.loggedIn = value
this.user = this.tokenService.getUser();
}
);
}
Try making the call
this.user = this.tokenService.getIser()
inside the subscribe.

Save records into the same collection in Mongo DB using Meteor js

Being new to Meteor JS, I'm confused on how to update a record. I have 2 templates AddSchoolLayout and Schoolcontactlayout, AddSchoollayout creates the record in Mongo db, now, for the same school I want to add its address still on the same DB NewSchoolDB but as I tried this I keep getting the error below about wrong ID. What wrong am I to right?
Note that my language might not correlate with Mongo's; I'm still fresh, coming from the SQL background.
This is the method.js where the record is been saved.
//methods.js
if (Meteor.isServer) {
Meteor.methods({
SchoolRegister: function (phone, schoolemail) {
if (!Meteor.userId()) {
throw new Meteor.error('Not authorized');
return false;
}else{
NewSchoolDB.insert({
authorId: Meteor.userId(),
phone: phone,
schoolemail
});
}
}
});
}
This is the event for saving a new school
//add school
Template.AddSchoolLayout.events({
'submit .addnewschool': function (event, template) {
event.preventDefault();
var newschoolname = trimInput(event.target.newschoolname.value);
if (isNotEmpty(newschoolname)) {
Meteor.call('SchoolRegister', newschoolname,
function (error, response) {
if (error) {
Bert.alert(error.reason, 'danger', 'growl-top-right');
return false;
}else{
Bert.alert("School successfully created", "success", "growl-top-right");
FlowRouter.redirect('/schoolcontact');
}
});
}
return false;
}
});
This is where I want to update the school address
//school contact
Template.SchoolContactLayout.events({
'submit .contactschool': function (event) {
event.preventDefault();
var phone = trimInput(event.target.phone.value);
if (isNotEmpty(phone)) {
Meteor.call('SchoolRegister', phone, function (error, response) {
if (error) {
Bert.alert(error.reason, 'danger', 'growl-top-right');
return false;
}else{
Bert.alert('School address updated successfully', 'success', 'growl-top-right');
FlowRouter.redirect('/logo-upload');
}
});
}
return false;
}
});
Error logged on the console
I20170524-17:44:14.051(1)? at packages/ddp-server/livedata_server.js:559:43
I20170524-17:51:54.678(1)? Exception from sub NewSchoolDB id onFTu2j3xRmbqC5WF TypeError: this.userId is not a function
I20170524-17:51:54.710(1)? at [object Object]._handler (lib/pulbish/published.js:3:13)
I20170524-17:51:54.712(1)? at maybeAuditArgumentChecks (packages/ddp-server/livedata_server.js:1737:12)
I20170524-17:51:54.713(1)? at [object Object]._.extend._runHandler (packages/ddp-server/livedata_server.js:1035:17)
I20170524-17:51:54.714(1)? at [object Object]._.extend._startSubscription (packages/ddp-server/livedata_server.js:853:9)
I20170524-17:51:54.715(1)? at [object Object]._.extend.protocol_handlers.sub (packages/ddp-server/livedata_server.js:625:12)
I20170524-17:51:54.719(1)? at packages/ddp-server/livedata_server.js:559:43
Your SchoolRegister method accepts 2 arguments: phone and schoolmail. When you create the school you call the methods with one argument called newschoolname. So something is wrong here with your naming convention, but it shouldn't really matter regarding your question.
With MongoDB, you use insert to add a new record to your collection. If you need to update it, use update. So one way to solve your problem is to:
In AddSchoolLayout, call your method to insert the document the first time. NewSchoolDB.insert(...) will return the ID of the created record. Keep that ID and pass it to your next page, for exemple in the URL.
In your next page, SchoolContactLayout, you need to call a new method which is going to update your school, using the ID returned by the previous method. This new method will look something like this:
SchoolUpdate: function (schoolId, phone) {
if (!Meteor.userId()) {
throw new Meteor.error('Not authorized');
return false;
}else{
NewSchoolDB.update(schoolId, { $set: { phone } });
}
}
The first argument of the update MongoDB function is the ID of the record you want to update. The second arguments are the modifiers you want to use to update your record. Here is the full list of modifier you can use: update modifiers
EDIT: how to pass ID from one layout to another:
I didn't use FlowRouter for a while and I can't test it right now so you may have to do some correction, but here is how I would do it to give you an idea:
First you need to define your route SchoolContactLayout with something like this:
FlowRouter.route('/schoolcontact/:schoolId', {
name: 'schoolContact',
});
This adds a schoolId parameter to the route.
In your SchoolRegister method, get the return ID and return it:
var id = NewSchoolDB.insert({
authorId: Meteor.userId(),
schooleName
});
return { id }
Edit your redirection FlowRouter.redirect('/schoolcontact'); with FlowRouter.go('/schoolcontact/' + response.id);
You can then edit your contactSchool event with something like this:
Template.SchoolContactLayout.events({
'submit .contactschool': function (event) {
event.preventDefault();
var schoolId = FlowRouter.getParam('schoolId');
var phone = trimInput(event.target.phone.value);
if (isNotEmpty(phone)) {
Meteor.call('SchoolUpdate', schoolId ,phone, function (error, response) {
if (error) {
Bert.alert(error.reason, 'danger', 'growl-top-right');
return false;
}else{
Bert.alert('School address updated successfully', 'success',
'growl-top-right');
FlowRouter.redirect('/logo-upload');
}
});
}
return false;
}
});
Notice the var schoolId = FlowRouter.getParam('schoolId'); to get the ID from URL parameter so I can use it in the update method.

How to retrieve value from Storage and user it somewhere else in Ionic 2

I am new to Ionic 2 and Promises and having some issues.
My Ionic 2 app saves an auth_token to the local storage:
this.storage.set('auth_token', auth_token);
Then later in my secured component I want to check if a token is set, but I don't know how to do this.
I tried this:
authenticate() {
var auth_token = this.storage.get('auth_token').then((val) => {
return val;
});
}
Then from somewhere else I called:
console.log(this.auth.authenticate);
But it won't work, it just returns the function itself.
How do I return the token from my authenticate method?
Check here for chaining of promises.
In your authenticate() function return the original promise call and use then in the function in the other location
authenticate() {
return this.storage.get('auth_token').then((val) => {
return val;
});
}
When caling authenticate...
this.auth.authenticate().then((val)=>{
console.log(val);
}).catch(error=>{
//handle error
});
You just want to check or do you need to return it?
If it's only checking you can do this:
authenticate() {
this.storage.get('auth_token').then((val) => {
if(val){ ... } // or console.log it if it's just what you need.
}
}
If you need to return, create a promise like this:
authenticate = (): Promise<{exists: boolean, auth: any}> =>{
return new Promise<{exists: boolean, auth: any}>(res =>{
this.storage.get('auth_token').then((val) => {
if(val){
res({exists: true, auth: val});
} else {
res({exists: false, auth: val});
}
}
})
}
and later call authenticate().then(res =>{}) and access the object returned in res.
EDIT
As commented by Suraj and tested now, it doesn't need to be encapsulated inside a new promise, so if you need to return it just use the method Suraj suggested.