I'm trying to save changes to an existing node in my Firebase DB, but I'm getting this error here:
Reference.update failed: First argument contains a function in property 'matatu-list.-L-RMcqjnladFM5-V80b.payload.node_.children_.comparator_' with contents = function NAME_COMPARATOR(left, right) {
return util_1.nameCompare(left, right);
}
I want to edit an item basing on its respective key (which is passed from another page through navParams).
Here is the interface I used to structure the DB:
interface.ts
export interface Matatu {
$key?: string;
matNumberPlate: string;
matSacco: string;
matDriver: string;
matAccessCode: string;
matStatus: string;
matTracker: string;
matLocation: string;
//Optionals
payload?:any;
key?:any;
}
The .ts and .html code that's meant to update the record:
.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { AngularFireObject, AngularFireDatabase } from 'angularfire2/database';
import { Matatu } from '../../models/matatu/matatu.interface';
import { Subscription } from 'rxjs/Subscription';
#IonicPage()
#Component({
selector: 'page-edit-ma3',
templateUrl: 'edit-ma3.html',
})
export class EditMa3Page {
matatuRef$: AngularFireObject<Matatu>;
matatuAsync$: any;
matatu = {} as Matatu;
sub: Subscription;
constructor(public navCtrl: NavController, public navParams: NavParams, private database: AngularFireDatabase) {
const matKey = this.navParams.get('matKey');
this.matatuRef$ = this.database.object(`matatu-list/${matKey}`);
this.matatuAsync$ = this.matatuRef$.snapshotChanges();
//console.log(matKey);
this.sub = this.matatuAsync$.subscribe(
matatu => this.matatu = matatu
)
}
editMatatu(matatu : Matatu){
this.matatuRef$.update(matatu);
this.navCtrl.pop();
}
ionViewWillLeave(){
this.sub.unsubscribe();
}
}
.html
<ion-content>
<ion-list>
<ion-list-header>
Matatu Details
</ion-list-header>
<ion-item>
<ion-label>Sacco</ion-label>
<ion-input type="text" [(ngModel)]="matatu.matSacco"></ion-input>
</ion-item>
<ion-item>
<ion-label>Driver</ion-label>
<ion-input type="text" [(ngModel)]="matatu.matDriver"></ion-input>
</ion-item>
<ion-item>
<ion-label> Access Code</ion-label>
<ion-input type="password" [(ngModel)]="matatu.matAccessCode"></ion-input>
</ion-item>
</ion-list>
<ion-list radio-group [(ngModel)]="matatu.matTracker">
<ion-list-header>
Preferred Tracking
</ion-list-header>
<ion-item>
<ion-label>GPS</ion-label>
<ion-radio checked="true" value="GPS"></ion-radio>
</ion-item>
<ion-item>
<ion-label>Driver's Location</ion-label>
<ion-radio value="Driver's Location"></ion-radio>
</ion-item>
</ion-list>
<div padding>
<button ion-button block (click)="editMatatu(matatu)">Save Changes</button>
</div>
</ion-content>
How do I go about rectifying this? I'd appreciate it if it was pointed out to me where I went wrong, and what other approaches can get this done(even the dirty ones!).
You can pass the key in a placeholder variable or you could just concatenate it like so:
this.matatuRef$ = this.database.object(`matatu-list/`+ matKey);
Do keep in mind this is not a good approach, but it'll do the trick.
Firebase fires this error when you try to push data that contains a function, or a datatype instead of data values.
Basing on your interface, and the values you are passing from you template, your
update method should be like this:
editMatatu(matatu : Matatu){
this.matatuRef$.update({
matDriver: this.matatu.matDriver,
matAccessCode: this.matatu.matAccessCode,
matSacco: this.matatu.matSacco
});
}
Related
This question already has an answer here:
Object returned from Firebase signIn
(1 answer)
Closed 4 years ago.
I am trying to register with firebase and ionic,
but I face the problem from the beginning of the day,
ERROR Error: Reference.child failed: First argument was an invalid path = "undefined". Paths must be non-empty strings and can't contain ".", "#", "$", "[", or "]",
can anyone help me with that
this is the provider:
import * as firebase from 'firebase';
import { Injectable } from '#angular/core';
/*
Generated class for the UserServiceProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
#Injectable()
export class UserServiceProvider {
public data: any;
public fireAuth: any;
public userProfile: any;
constructor() {
console.log('Hello UserServiceProvider Provider');
this.fireAuth = firebase.auth();
this.userProfile = firebase.database().ref(`email`);
}
signupUserService(account: {}){
return this.fireAuth.createUserWithEmailAndPassword(account[`email`], account[`password`]).then((newUser) => {
//sign in the user
this.fireAuth.signInWithEmailAndPassword(account[`email`], account[`password`]).then((authenticatedUser) => {
//successful login, create user profile
this.userProfile.child(authenticatedUser.uid).set(
account
);
});
});
}
}
------------------------------------------------------
this is my signUp page
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, LoadingController, ToastController } from 'ionic-angular';
import { UserServiceProvider } from '../../providers/user-service/user-service';
import { HomePage } from '../home/home';
/**
* Generated class for the LoginPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-login',
templateUrl: 'login.html',
})
export class LoginPage {
public skills : string;
public email : string;
public phone : any;
public password : any;
public first_name : any;
public last_name : any;
public city : any;
public state : any;
public country : any;
public isJobSeeker : boolean;
constructor(public navCtrl: NavController,
public navParams: NavParams,
public usersserviceProvider : UserServiceProvider,
public toastCtrl: ToastController, public loadingCtrl: LoadingController) {
}
ionViewDidLoad() {
console.log('ionViewDidLoad LoginPage');
}
doSignup(){
var account = {
first_name: this.first_name,
last_name: this.last_name || '',
skills: this.skills || '',
email: this.email,
phone: this.phone || '',
password: this.password,
city: this.city || '',
state: this.state || '',
country: this.country || '',
isJobSeeker : this.country || ''
};
var that = this;
var loader = this.loadingCtrl.create({
content: "Please wait...",
});
loader.present();
this.usersserviceProvider.signupUserService(account).then(authData => {
//successful
loader.dismiss();
that.navCtrl.setRoot(HomePage);
}, error => {
loader.dismiss();
// Unable to log in
let toast = this.toastCtrl.create({
message: error,
duration: 3000,
position: 'top'
});
toast.present();
that.password = ""//empty the password field
});
}
}
this my html
<ion-list>
<ion-item >
<ion-label stacked>Skill Set (separate with comma)</ion-label>
<ion-input type="text" [(ngModel)]="skills" name="skills" placeholder="eg. PHP, Writing, Chef" required="required"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Email</ion-label>
<ion-input type="email" [(ngModel)]="email" name="email" placeholder="eg. john#doe.com"></ion-input>
</ion-item>
<ion-item >
<ion-label stacked>Phone</ion-label>
<ion-input type="text" [(ngModel)]="phone" name="phone" placeholder="eg. 0802222222" required="required"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Password</ion-label>
<ion-input type="password" [(ngModel)]="password" name="password"></ion-input>
</ion-item>
<hr/>
<ion-item>
<ion-label stacked>First name</ion-label>
<ion-input type="text" [(ngModel)]="first_name" name="first_name"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Last name</ion-label>
<ion-input type="text" [(ngModel)]="last_name" name="last_name"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>City</ion-label>
<ion-input type="text" [(ngModel)]="city" name="city"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>State/Province</ion-label>
<ion-input type="text" [(ngModel)]="state" name="state"></ion-input>
</ion-item>
<ion-item>
<ion-label>Looking for Job?</ion-label>
<ion-toggle [(ngModel)]="isJobSeeker" name="phone" checked="false"></ion-toggle>
</ion-item>
<div padding text-center>
<button ion-button color="danger" round (click)="doSignup()" >Signup</button>
</div>
</ion-list>
Thanks in advance,
If you check the documentation of signInWithEmailAndPassword, you will see that it returns a UserCredential. Checking the documentation for that shows that it has no uid property, which explains why you get undefined.
You'll want to use authenticatedUser.user.uid, so:
this.fireAuth.signInWithEmailAndPassword(account[`email`], account[`password`]).then((userCredential) => {
this.userProfile.child(userCredential.user.uid).set(
account
);
});
Creating a new user account with createUserWithEmailAndPassword automatically signs them in, so the nesting of those calls is not needed. If you (only) want to store the user profile when creating the account, createUserWithEmailAndPassword also returns a UserCredential. So there too, you need to indirect to user.uid:
return this.fireAuth.createUserWithEmailAndPassword(account[`email`], account[`password`]).then((userCredential) => {
return this.userProfile.child(userCredential.user.uid).set(
account
);
});
I'm trying to create a simple chat application with Ionic 3 and Firebase. Registering, logging in users, sending, and displaying their messages work. This is a common chat room for all users.
I'd like a message to appear in the chat room when a user is logged in or logged out to let other users know. When test user is logged in, this message appears:
"has joined the room"
When test user is logged out, this message appears:
"test#gmail.com has left the room"
I'd like the username (email address) to show when the user is logged in as well. I'd like this message to appear: "test#gmail.com has joined the room"
I tried to write this.username on the console, but it doesn't write anything to the console.
chat.ts:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';
import { Storage } from '#ionic/storage';
import { Subscription } from 'rxjs/Subscription';
import $ from 'jquery';
#IonicPage()
#Component({
selector: 'page-chat',
templateUrl: 'chat.html',
})
export class ChatPage {
username: string= '';
message: string= '';
obsRef: AngularFireObject<any>;
obsToData: Subscription;
messages: object[]= [];
constructor(public db: AngularFireDatabase, public navCtrl: NavController, public navParams: NavParams, private storage: Storage) {
this.storage.get('username').then((val) => {
if (val != null) {
this.username= val;
}
});
this.obsRef = this.db.object('/chat');
this.obsToData = this.obsRef.valueChanges().subscribe( data => {
var data_array= $.map(data, function(value, index) {
return [value];
});
this.messages= data_array;
});
}
sendMessage() {
this.db.list('/chat').push({
username: this.username,
message: this.message
}).then( () => {
this.message= '';
});
}
ionViewWillLeave() {
console.log('user is about to go');
this.obsToData.unsubscribe();
this.db.list('/chat').push({
specialMessage: true,
message: `${this.username} has left the room`
})
}
ionViewDidLoad() {
console.log(this.username);
this.db.list('/chat').push({
specialMessage: true,
message: this.username + `has joined the room`
})
}
}
chat.html:
<ion-header>
<ion-navbar>
<ion-title>Chat</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<div id="chatMessages">
<div *ngFor="let message of messages" [class]="message.specialMessage ? 'message special': 'message'">
<div [class]="message.username == username ? 'innerMessage messageRight': 'innerMessage messageLeft'">
<div class="username"> {{ message.username }} </div>
<div class="messageContent"> {{ message.message }} </div>
</div>
</div>
</div>
</ion-content>
<ion-footer>
<div id="footer">
<ion-input type="text" [(ngModel)]= "message"> </ion-input>
<button ion-button icon-only (click)= "sendMessage()">
<ion-icon name="send"></ion-icon>
</button>
</div>
</ion-footer>
I stored profile data in firebase and
trying to retrieve them and show them in template with slides.
(I am making a matching service.)
But it seems the template is loaded before data is assigned to variable.
When I am just retrieving one data, not list,
it works fine.
I tried all the solutions on the goole,
like using 'NgZone', *ngIf, etc but nothing worked.
Please help me.
My Error message.
FindMatePage.html:21 ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed
at DefaultIterableDiffer.diff (core.es5.js:7083)
at NgForOf.ngDoCheck (common.es5.js:1699)~~
My find-mate.ts file.
export class FindMatePage implements OnInit{
#ViewChild('profileSlide') slider: Slides;
profileList = [] as Profile[];
constructor(public navCtrl: NavController, public navParams: NavParams,
private databaseService: DataServiceProvider, private auth:
AuthServiceProvider,
) {}
ngOnInit(){
this.auth.getActiveUser().getIdToken()
.then((token: string) => (
this.databaseService.fetchProfileList(token)
.subscribe((list: Profile[]) => {
if(list) {
this.profileList = list;
console.log(this.profileList)
} else {
this.profileList = [];
}
})
))//then ends
}
My find-mate.html file
<ion-content class="tutorial-page">
<ion-slides *ngIf="profileList" #profileSlide pager
(ionSlideDidChange)="slideChanged()">
<ion-slide>
<h2 class="profile-title">Ready to Play?</h2>
<button ion-button large clear icon-end color="primary">
Continue
<ion-icon name="arrow-forward"></ion-icon>
</button>
</ion-slide>
<ion-slide *ngFor="let profile of profileList">
<ion-buttons block>
<button ion-button color="primary">채팅하기</button>
</ion-buttons>
<ion-item> {{profile.username}}</ion-item>
<ion-item> {{profile.gym}</ion-item>
<ion-item> {{profile.goal}}</ion-item>
<ion-item> {{profile.level}}</ion-item>
</ion-slide>
My part of data-service.ts file
//프로필 목록 가져오기
fetchProfileList(token: string) {
return this.http.get('https://fitmate-16730.firebaseio.com/profile-list.json?auth=' + token)
.map((response: Response) => {
return response.json();
})
.do((profileList: Profile[]) => {
if (profileList) {
console.log(profileList);
return this.profileList = profileList;
} else {
return this.profileList = null;
}
});
}
I'm developing a mobile app using Ionic 2, Angularfire 2 and Firebase, but I'm stuck, this is my Firebase data structure:
I need to create a list from carrito, but at the same time I need to get the precio field and link it to another collection - precios, and get with the key value (as shown in the image above), the fields related (opcion & precio).
The code : list.ts
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import {AngularFire, FirebaseListObservable} from 'angularfire2';
#Component({
selector: 'page-lista',
templateUrl: 'lista.html',
})
export class Lista {
public restaName:any;
serviceData: string;
carrito: FirebaseListObservable<any>;
precios: FirebaseListObservable<any>;
constructor(public navCtrl: NavController, public navParams:
NavParams, af: AngularFire, private shareService: ShareService) {
this.serviceData = shareService.getRestaName();
this.restaName = this.serviceData
this.carrito = af.database.list('/carrito', {
query: {
orderByChild: 'restaname',
equalTo: this.restaName
}
});
this.precios = af.database.list('/precios', {
query: {
orderByKey: true,
equalTo: this.precio ???? ---> HERE BEGIN MY DOUBTS
}
});
}
Here is part of lista.html
<ion-content padding>
<ion-list>
<ion-item *ngFor="let item of carrito | async ">
<p> {{item.prodname}} - {{item.cantidad}}</p>
</ion-item>
<ion-item *ngFor="let precio of precios | async "> ??? HOW CAN I GET THE FIELDS precio and opcion
<p>${{precio.precio}}</p>
</ion-item>
</ion-list>
</ion-content>
Any tips or comments will be appreciated !
You could use an Array of FirebaseObjectObservable instead of
precios: FirebaseListObservable<any>;
public precios :Array<FirebaseObjectObservable<any>>
this.carrito.subscribe(carrito => carrito.forEach(singleCarrito=>
precios.push(af.database.object('/precios/'+singleCarrito.precio))
New to ionic2 want to know what is post method , where to use, where to write a code???
Here is the sample code
//ts code
constructor(public formBuilder: FormBuilder,
) {
this.signupForm = formBuilder.group({
firstName: ['', Validators.compose([Validators.maxLength(20), Validators.pattern('[a-zA-Z ]*'), Validators.required])]
});
//html code
<form [formGroup]="signupForm">
<ion-item>
<ion-label floating>FIRST NAME</ion-label>
<ion-input formControlName="firstName" type="text"></ion-input>
</ion-item>
</form>
-- want to post the signupForm!!
Well, let's keep it short for basic understanding of post method.
import { Http } from '#angular/http'; import { Observable } from 'rxjs';
then
doPost(someData: any): Observable<any> {
this.http.post('auth/login').map(response => {
return response.json();
});
}
then you call it with
doPost(myData).subscribe(response => console.log(response));