I'm trying to push data to firebase database by userId , even each user he can modify has post or has information . the pushed data is successfully , but the problem is when l am try to getting data in html dose not show .
database
html
code for getting data :
items: Observable<any[]>;
itemsRef: AngularFireList<any>;
constructor(public fire: AngularFireAuth,public db: AngularFireDatabase)
{
this.itemsRef = db.list(`report/`);
// Use snapshotChanges().map() to store the key
this.items = this.itemsRef.snapshotChanges().pipe(
map(changes =>
changes.map(c => ({ key: c.payload.key, ...c.payload.val() }))
)
);
}
html
<ion-list *ngFor="let item of items | async">
<ion-item-sliding>
<ion-item>
<h2>{{itemstitle}}</h2>
<p>{{item.name}}</p>
<p>{{item.username}}</p>
<p>{{item.dateadded}}</p>
</ion-item>
<ion-item-options side="right">
<button ion-button color="danger" (click)="deletReport(item.key)">
<ion-icon ios="ios-trash" md="md-trash" item-end large></ion-icon>
</button>
<button ion-button color="primary" (click)="updatereport(item.key,item.name,item.title)">
<ion-icon ios="ios-create" md="md-create"></ion-icon>
</button>
</ion-item-options>
</ion-item-sliding>
</ion-list>
my push data :
name :string='';
title :string='';
Email:string='';
dateadded:string='';
userId: string;
reports: AngularFireList<any>;
items: Observable<any[]>;
constructor(db: AngularFireDatabase,public alertCtrl: AlertController,public loadingCtrl: LoadingController,
public navCtrl: NavController,public fire: AngularFireAuth) {
var newPostKey = db.database.ref().child('report').push().key;
this.reports = db.list(`report/${this.userId=fire.auth.currentUser.uid}/`);
console.log(this.userId=fire.auth.currentUser.uid)
}
formatDate (date): string{
const day = new Date().getDate();
const month = new Date().getMonth()+1;
const year = new Date().getFullYear();
return `${day}-${month}-${year}`
}
// dateaddread(dateadded){
// this.dateadded = this.formatDate(dateadded)
// }
Publish(name,title,dateadded){
if (name.trim().length === 0) {
console.log(this.name);
let alert = this.alertCtrl.create({
title: 'Error',
message: 'Please fill report blank ',
buttons: ['OK']
});
alert.present();
}else if (title.trim().length === 0){
let alert = this.alertCtrl.create({
title: 'Error',
message: 'Please fill title blank ',
buttons: ['OK']
});
alert.present();
}else {
this.reports.push({
name:name,
title:title,
Email:this.fire.auth.currentUser.email,
dateadded:this.formatDate(dateadded)
}).then(Newreport=>{
let alert = this.alertCtrl.create({
title: 'Successful',
message: 'Successfully posted',
buttons: [
{
text: 'Ok',
handler: () => {
let navTransition = alert.dismiss();
// start some async method
navTransition.then(() => {
this.navCtrl.pop().then(data => {
this.navCtrl.setRoot(FeedPage)
});
});
return false;
}
}]
});
alert.present()
})
}
}
any idea please with simple code ?
this.reports = db.list(`report/${this.userId=fire.auth.currentUser.uid}/`);
this.reports.push({
name:name,
title:title,
Email:this.fire.auth.currentUser.email,
dateadded:this.formatDate(dateadded)
})
and for displaying the data in HTML, you just need to modify your query to get only the data of logged in user
this.itemsRef = db.list(`report/` + fire.auth.currentUser.uid);
Related
I'm trying to build a crud vuejs3 application (book store), and in the update operation I didn't figure out how to get the document id in order to update the book details, following are some of my code snippets where I'm currently working on:
UpdateDcoment.js
const updatingDoc = (collection, id) => {
const isPending = ref(false);
const error = ref(null);
let documentRef = db.collection(collection).doc(id);
const handleUpdateDoc = async (updates) => {
isPending.value = true;
error.value = null;
try {
const response = await documentRef.update(updates);
isPending.value = false;
console.log("update was successfully!", response);
return response;
} catch (err) {
err.value = err.message;
console.log(err.value);
error.value = err.message;
isPending.value = false;
}
};
return { error, isPending, handleUpdateDoc };
};
export default updatingDoc;
BookDetails.vue
<template>
<div>
<div v-if="document" class="book-detail-view">
<div class="book-cover">
<img :src="document.coverUrl" :alt="`${document.title} book cover`" />
</div>
<div class="book-details">
<h4 class="book-title">
{{ document.title }}
</h4>
<div class="book-description">
<p>{{ document.description }}</p>
</div>
<div class="book-author">
<p>{{ `Author: ${document.author}` }}</p>
</div>
<div v-if="currentAuthenticatedUser">
<button v-if="!isDeleting" #click="handleDelete">
Delete the book
</button>
<button v-else disabled>processing...</button>
<router-link :to="{ path: `/books/${document.id}/update` }">
Update here
</router-link>
</div>
</div>
</div>
<div v-else class="error">{{ error }}</div>
</div>
</template>
<script>
import { computed } from "#vue/runtime-core";
import getDocument from "../../controllers/getDocument";
import getUser from "../../controllers/getUser";
import deleteDocument from "../../controllers/deleteDocument";
import getStoredBook from "../../controllers/userStorage";
import { useRouter } from "vue-router";
export default {
props: ["id"],
setup(props) {
const { error, document } = getDocument("books", props.id);
const { user } = getUser();
const { removeDoc, isDeleting } = deleteDocument("books", props.id);
const { handleDeleteCover } = getStoredBook();
const router = useRouter();
const currentAuthenticatedUser = computed(() => {
return (
document.value && user.value && user.value.uid === document.value.userId
);
});
const handleDelete = async () => {
await handleDeleteCover(document.value.filePath);
await removeDoc();
router.push({ name: "home" });
};
return {
document,
error,
currentAuthenticatedUser,
handleDelete,
isDeleting,
};
},
};
</script>
UpdateBook.vue
<template>
<form #submit.prevent="handleSubmit">
<h4>Update book:</h4>
<input type="text" required placeholder="book name" v-model="title" />
<input type="text" required placeholder="author name" v-model="author" />
<textarea
required
placeholder="book description"
v-model="overview"
></textarea>
<label for="bookCover">Upload the cover book</label>
<input type="file" id="bookCover" #change="handleAddCoverBook" />
<label for="book">Upload the book</label>
<input type="file" id="book" #change="handleAddBook" />
<button v-if="!isPending">Update</button>
<button v-else disabled>Updating...</button>
<div v-if="fileError" class="error">{{ fileError }}</div>
</form>
</template>
<script>
import { ref } from "vue";
import userStorage from "#/controllers/userStorage";
import getUser from "#/controllers/getUser";
import { createdAtTime } from "#/firebase/firebaseConfig";
import { useRouter } from "vue-router";
import updatingDoc from "#/controllers/updateDocument";
export default {
setup() {
const { url1, url2, handleUploadBook, bookCoverPath, bookPath } =
userStorage();
const { user } = getUser();
const { error, isPending, handleUpdateDoc } = updatingDoc(
"books",
document.id
);
const router = useRouter();
const title = ref("");
const author = ref("");
const overview = ref("");
const bookCover = ref(null);
const book = ref(null);
const fileError = ref(null);
const handleSubmit = async () => {
if (bookCover.value) {
// Truthy value will show 'uploading...' text whenever the adding books process is processing
isPending.value = true;
await handleUploadBook(bookCover.value, book.value);
// log the result of the event listener wherever the upload was successful
console.log("book uploaded successfully", url1.value, url2.value);
const response = await handleUpdateDoc({
title: title.value,
author: author.value,
description: overview.value,
createdAt: createdAtTime(),
userId: user.value.uid,
userName: user.value.displayName,
coverUrl: url1.value,
bookUrl: url2.value,
bookCover: bookCoverPath.value,
book: bookPath.value,
});
// Truthy value will remove 'uploading...' text whenever the adding books process is finished
isPending.value = false;
if (!error.value) {
console.log("updating process successful");
router.push({ name: "BookDetail", params: { id: response.id } });
}
}
};
// Upload Cover Book
const bookCoverTypes = ["image/png", "image/jpg", "image/jpeg"];
const handleAddCoverBook = (e) => {
const newBookCover = e.target.files[0];
if (newBookCover && bookCoverTypes.includes(newBookCover.type)) {
bookCover.value = newBookCover;
fileError.value = null;
} else {
bookCover.value = null;
fileError.value = "Please add a cover book (png, jpg or jpeg)";
}
};
// Upload book
const bookTypes = ["application/pdf", "application/epub"];
const handleAddBook = (e) => {
const newBook = e.target.files[0];
if (newBook && bookTypes.includes(newBook.type)) {
book.value = newBook;
fileError.value = null;
} else {
book.value = null;
fileError.value = "Please add a book (pdf or epub)";
}
};
return {
title,
author,
overview,
handleSubmit,
handleAddCoverBook,
handleAddBook,
fileError,
isPending,
};
},
};
</script>
I'm trying to get the document id from the bookDetails.vue and then use it inside the updateBook.vue but whenever I hit the update button in the UpdateBook.vue I have the following log:
No document to update: projects/books-store-71c7f/databases/(default)/documents/books/pVIg6OytEKE4nEUE8uqd
I appreciate your hints and help guys!
SOLVED!
So, the trick was to use the params for the current URL in order to get the document id and update the document fields:
here I passing the router-link to redirect to update form:
<router-link
:to="{ name: 'UpdateBook', params: { id: document.id } }"
>
Update here
</router-link>
And here inside the setup() of the updateBook.vue component I use params to access the document id:
const router = useRouter();
// Get the current document id from the route id
const id = router.currentRoute.value.params.id;
// And here I pass the document id as parameter
const { error, isPending, handleUpdateDoc } = updatingDoc("books", id);
My setUser
setUser(state, payload) {
state.user = {...payload}
}
my payload in setUser for random data is
user ===
payload{"uid":"pQOQL9AqMHNsozDE2EFGbMfHZlt1","refreshToken":"AEu4IL3c4doh1ON1ywqNEIXPjijktxAyQsYusC5twuvM61bHK6PpLHENyqKRKGCvNPR5IxBRC7JLQhkjv1qqiVUPdatRVM2Q8VdBCnvxyKkBjOEt_kM6bHCiJI6cdESdmFWZf2B7EjG9MwUJ7l8ASOpdbQLLVs9NtuW94dpNg1dkQShtUXB-sVCafvgtSnluGyZSWGhkt8uJ","photoURL":null,"displayName":null,"email":"yyy#test.com"}
My signUserUp
signUserUp(context, payload) {
//name , email , and password are in payload
context.commit("setLoading", true);
context.commit("clearError");
context.commit("setUserAvatar")
firebase
.auth()
.createUserWithEmailAndPassword(payload.email, payload.password)
.then((data) => {
data.user.updateProfile({
displayName: payload.name ,
photoURL: 'https://avataaars.io/?avatarStyle=Circle&topType=ShortHairDreads01&accessoriesType=Prescription01&hairColor=BlondeGolden&facialHairType=BeardMedium&facialHairColor=BrownDark&clotheType=Hoodie&clotheColor=Gray01&eyeType=Squint&eyebrowType=AngryNatural&mouthType=Sad&skinColor=Light'
})
return data
})
.then((data) => {
context.commit("setLoading", false);
db.collection("profilesInfo")
.add({
id: data.user.uid,
registeredMeetups: []
})
.then(function() {
context.commit("setProfilesInfo",
{
id: data.user.uid,
registeredMeetups: []
}
)
console.log("Document successfully written!");
})
.catch(function(error) {
console.error("Error writing document: ", error);
});
context.commit("setUser", {
name: payload.name ,
id: data.user.uid,
photoURL: 'https://avataaars.io/?avatarStyle=Circle&topType=ShortHairDreads01&accessoriesType=Prescription01&hairColor=BlondeGolden&facialHairType=BeardMedium&facialHairColor=BrownDark&clotheType=Hoodie&clotheColor=Gray01&eyeType=Squint&eyebrowType=AngryNatural&mouthType=Sad&skinColor=Light',
email: data.user.email
})
router.push("/");
})
.catch(function(error) {
// Handle Errors here.
context.commit("setLoading", false);
context.commit("setError", error);
});
},
In signUserUp
an user will be created and upon creation value of photoURL and displayName get updated by updateProfile
and after that db is connected again in order to create profilesinfo related to the user which is about showing what meetup groups the user is registered already
It works when in my setUser, I set the value of payload inside setUser and photoURL and displayName will be populated right and I can use it in my profile vue component
I debugged everything inside the console and I cannot understand why this part does not pass photoURL and displayName right
context.commit("setUser", {
name: payload.name ,
id: data.user.uid,
photoURL: 'https://avataaars.io/?avatarStyle=Circle&topType=ShortHairDreads01&accessoriesType=Prescription01&hairColor=BlondeGolden&facialHairType=BeardMedium&facialHairColor=BrownDark&clotheType=Hoodie&clotheColor=Gray01&eyeType=Squint&eyebrowType=AngryNatural&mouthType=Sad&skinColor=Light',
email: data.user.email
})
Note: I cleared my storage very often
or In second thought, can my issue is because of using persistent data?
const vuexLocalStorage = new VuexPersist({
key: 'devmeetup-it', // The key to store the state on in the storage provider.
storage: window.localStorage, // or window.sessionStorage or localForage
// Function that passes the state and returns the state with only the objects you want to store.
// reducer: state => ({
// keepLoadedMeetups : store.getters.loadedMeetups,
// keepUser: store.getters.user,
// keepProfilesInfo: state.profilesInfo
// // getRidOfThisModule: state.getRidOfThisModule (No one likes it.)
// })
// Function that passes a mutation and lets you decide if it should update the state in localStorage.
// filter: mutation => (true)
})
Note: after reloading and visiting other pages and come back to profile page, the photo is shown I guess the info became available then?
My Profile.vue
<template >
<div>
<v-card
class="mx-auto"
max-width="434"
tile
>
<v-img
height="100%"
src="https://cdn.vuetifyjs.com/images/cards/server-room.jpg"
>
<v-row
align="end"
class="fill-height"
>
<v-col
align-self="start"
class="pa-0"
cols="12"
>
<v-avatar
class="profile"
size="164"
tile
>
<img :src="imgUrl" alt="">
</v-avatar>
</v-col>
<v-col class="py-0">
<v-list-item
color="rgba(0, 0, 0, .4)"
dark
>
<v-list-item-content>
<v-list-item-title class="title">Name: {{owner_name}}</v-list-item-title>
<v-list-item-subtitle>Email: {{user_info.email}}</v-list-item-subtitle>
<template v-if="meetups.length> 0 ">
<v-list-item-subtitle>Meetup organizer :</v-list-item-subtitle>
<v-card color="rgba(255, 0, 0, 0.5)">
<ol start="1" v-for="(meetup,i) in meetups" v-bind:key="i">
<span >{{i+1}}. {{meetup.title}}</span>
</ol>
</v-card>
</template>
<template>
<div v-if="registeredMeetups.length> 0 ">
<v-list-item-subtitle>Meetup Registred :</v-list-item-subtitle>
<v-card color="rgba(255, 0, 0, 0.5)">
<ol start="1" v-for="(meetup,i) in registeredMeetups" v-bind:key="i">
<span >{{i+1}}. {{meetup.title}}</span>
</ol>
</v-card>
</div>
</template>
</v-list-item-content>
</v-list-item>
</v-col>
</v-row>
</v-img>
</v-card>
<!--<h3>orginzer meetups: {{this.meetups}}</h3>
<h3>registered meetups: {{this.registeredMeetups}}</h3>
<h3>All the meetups: {{this.$store.getters.loadedMeetups}} </h3>
<div style="word-wrap: break-word"> {{imgUrl}} </div>-->
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
data(){
return {
imgUrl: this.$store.state.user.photoURL
}
},
created(){
// this.$store.subscribe((mutation, state) => {
// if (mutation.type === "setUserAvatar") {
// //debugger; // eslint-disable-line no-debugger
// this.imgUrl = state.user.photoURL
// }
// });
},
computed: {
...mapState({
owner_name: state => state.user.displayName,
user_info: state => state.user
}),
registeredMeetups(){
let rm= this.$store.getters.currentUserProfileInfo.registeredMeetups
let allm = this.$store.getters.loadedMeetups
let meetupsInfo = []
let i , j
console.log("rm and all meetups are " + JSON.stringify(allm))
for (i = 0; i < rm.length; i++) {
console.log("rm=" + rm[i].toString() )
for ( j = 0 ; j < allm.length; j++){
console.log("lm= " + JSON.stringify(allm[j]))
if(allm[j].id == rm[i].toString())
meetupsInfo.push(allm[j])
}
}
console.log("meetupsInfo " + JSON.stringify(this.$store.state.photoURL))
return meetupsInfo
},
meetups(){
return this.$store.getters.loadedMeetups
.filter( meetup => meetup.creatorId === this.$store.getters.user.uid )
},
profilesInfo(){
// let currentUserProfile = this.$store.state.profilesInfo
// .find( userProfile =>
// userProfile.id === this.$store.getters.user.uid )
return this.$store.getters.currentUserProfileInfo
}
}
}
</script>
or May be, using then clause inside another the clause will have different effect ?
please take a look at my signUserUp then clauses.
my github repo
github.com/KickButtowski80/devmeetup/tree/setting-avataaars
please if more info is needed let me know
thank you
I see there is some different parameter passed in setUser()
In your signUserUp(context, payload):
...
context.commit("setUser", {
name: payload.name ,
id: data.user.uid,
photoURL: 'https://avataaars.io/?avatarStyle=Circle&topType=ShortHairDreads01&accessoriesType=Prescription01&hairColor=BlondeGolden&facialHairType=BeardMedium&facialHairColor=BrownDark&clotheType=Hoodie&clotheColor=Gray01&eyeType=Squint&eyebrowType=AngryNatural&mouthType=Sad&skinColor=Light',
email: data.user.email
});
router.push("/");
...
You also said :
It works when in my setUser, I set the value of payload inside setUser
and photoURL and displayName will be populated right and I can use it
in my profile vue component
Does it mean you put it in /store/index.js :
setUser(state, payload) {
const {uid, refreshToken, photoURL, displayName, email} = payload;
console.log('user === payload' + JSON.stringify(payload))
console.log('payload detail info ' + payload.uid + " " + payload.refreshToken
+ " " + payload.photoURL + " " + payload.displayName + " " + payload.email )
// payload = {
// displayName:"test7",
// email:"test7#test.com",
// photoURL:"https://avataaars.io/?avatarStyle=Circle&topType=ShortHairDreads01&accessoriesType=Prescription01&hairColor=BlondeGolden&facialHairType=BeardMedium&facialHairColor=BrownDark&clotheType=Hoodie&clotheColor=Gray01&eyeType=Squint&eyebrowType=AngryNatural&mouthType=Sad&skinColor=Light",
// refreshToken:"AEu4IL0tC9-fuEO-KZNwq953YDo2V7FBpjqB62FT6nXJ5d3r5u3Fzk1RYDzbjkO885rz0LrLyvIjHKHIDemiZsVPeio5XPXK5ntuRyFtLYcu-QOV4xnYYMn18mFxjo6P_TeqrnGIBuwpoto0ceTPxNfYFmedNyuxbNIU6MUVRp5WvnI7OWxVO5404RHIsnLrBsABoigDZgxs",
// uid:"XAhAqlBbs5VZCredSDqdWqKze6C3",
// }
state.user = {...{uid, refreshToken, photoURL, displayName, email}}
So, if you uncomment the line it works ?
Try to pass all the params used with the same key:
...
context.commit("setUser", {
uid: data.user.uid, // id => uid,
displayName: payload.name , // name=> displayName
refreshToken: 'your-token',
photoURL: 'https://avataaars.io/?avatarStyle=Circle&topType=ShortHairDreads01&accessoriesType=Prescription01&hairColor=BlondeGolden&facialHairType=BeardMedium&facialHairColor=BrownDark&clotheType=Hoodie&clotheColor=Gray01&eyeType=Squint&eyebrowType=AngryNatural&mouthType=Sad&skinColor=Light',
email: data.user.email
});
router.push("/");
...
Does it work ?
i'm working on firebase and vuejs with vuex as well. so in onauthStateChanged() method i try to get all the data form posts collection. its takes some time to display, In meanwhile i want to display spinner that specifies the user where some something is being loading.
i tried and its works cool, but the problem with code is
<loadingSpinner v-if="loading"></loadingSpinner>
<div v-if="posts.length">
<div v-for="post in posts" v-bind:key=post.id class="post">
<h5>{{ post.userName }}</h5>
<span>{{ post.createdOn | formatDate }}</span>
<p>{{ post.content | trimLength }}</p>
<ul>
<li><a #click="openCommentModal(post)">comments {{ post.comments }}</a></li>
<li><a #click="likePost(post.id, post.likes)">likes {{ post.likes }}</a></li>
<li><a #click="viewPost(post)">view full post</a></li>
</ul>
</div>
</div>
<div v-else>
<p class="no-results">There are currently no posts</p>
</div>
Spinner component responsible for spin animation:
<loadingSpinner v-if="loading"></loadingSpinner>
And the below html code is for displaying data from firebase
Where posts and loading variables are the computed properties from vuex state
problem is when is reload the page, spinner showing along the
<div v-else>
<p class="no-results">There are currently no posts</p>
</div>
I want to restrict the v-else condition when the spinner is being loaded.
By the way, the loading computed properties is a boolean that reacts based on onAuthstateChanged() firebase method
this is my entire vuex store file :
import Vue from 'vue'
import Vuex from 'vuex'
const fb = require('./firebaseConfig.js')
Vue.use(Vuex)
// handle page reload
fb.auth.onAuthStateChanged(user => {
if (user) {
store.commit('setCurrentUser', user)
store.dispatch('fetchUserProfile')
fb.usersCollection.doc(user.uid).onSnapshot(doc => {
store.commit('setUserProfile', doc.data())
})
// realtime updates from our posts collection
fb.postsCollection.orderBy('createdOn', 'desc').onSnapshot(querySnapshot => {
// check if created by currentUser
let createdByCurrentUser
if (querySnapshot.docs.length) {
createdByCurrentUser = store.state.currentUser.uid == querySnapshot.docChanges[0].doc.data().userId ? true : false
}
// add new posts to hiddenPosts array after initial load
if (querySnapshot.docChanges.length !== querySnapshot.docs.length
&& querySnapshot.docChanges[0].type == 'added' && !createdByCurrentUser) {
let post = querySnapshot.docChanges[0].doc.data()
post.id = querySnapshot.docChanges[0].doc.id
store.commit('setHiddenPosts', post)
} else {
store.commit('setLoading', true)
let postsArray = []
querySnapshot.forEach(doc => {
let post = doc.data()
post.id = doc.id
postsArray.push(post)
})
store.commit('setPosts', postsArray)
store.commit('setLoading', false)
}
})
}
})
export const store = new Vuex.Store({
state: {
currentUser: null,
userProfile: {},
posts: [],
hiddenPosts: [],
loading: true
},
actions: {
clearData({ commit }) {
commit('setCurrentUser', null)
commit('setUserProfile', {})
commit('setPosts', null)
commit('setHiddenPosts', null)
},
fetchUserProfile({ commit, state }) {
fb.usersCollection.doc(state.currentUser.uid).get().then(res => {
commit('setUserProfile', res.data())
}).catch(err => {
console.log(err)
})
},
updateProfile({ commit, state }, data) {
let name = data.name
let title = data.title
fb.usersCollection.doc(state.currentUser.uid).update({ name, title }).then(user => {
// update all posts by user to reflect new name
fb.postsCollection.where('userId', '==', state.currentUser.uid).get().then(docs => {
docs.forEach(doc => {
fb.postsCollection.doc(doc.id).update({
userName: name
})
})
})
// update all comments by user to reflect new name
fb.commentsCollection.where('userId', '==', state.currentUser.uid).get().then(docs => {
docs.forEach(doc => {
fb.commentsCollection.doc(doc.id).update({
userName: name
})
})
})
}).catch(err => {
console.log(err)
})
}
},
mutations: {
setLoading(state, payload){
state.loading = payload
},
setCurrentUser(state, val) {
state.currentUser = val
// console.log(val)
},
setUserProfile(state, val) {
state.userProfile = val
// console.log(val)
},
setPosts(state, val) {
if (val) {
state.posts = val
} else {
state.posts = []
}
},
setHiddenPosts(state, val) {
if (val) {
// make sure not to add duplicates
if (!state.hiddenPosts.some(x => x.id === val.id)) {
state.hiddenPosts.unshift(val)
}
} else {
state.hiddenPosts = []
}
}
},
})
any suggestions?
I would tweak your v-if/v-else logic at bit.
<loadingSpinner v-if="loading" />
<div v-else-if="posts.length"></div>
<div v-else>
<p class="no-results">There are currently no posts</p>
</div>
The difference is v-else-if on posts.length, instead of v-if. This way, there are 3 distinct states.
Loading, show spinner.
Not loading, show posts.
Not loading, there are no posts, show no results.
I have a simple structure in my Database:
The app logic here: I create a list with some data with the function to delete each list item separately.
I´m using the angularefire2 plugin for database communication. The code to get data looks like this in component:
// Set variables
currentUserID: any;
visits: any[] = [];
selectedVisit: any;
constructor(public navCtrl: NavController, public navParams: NavParams, private dbAction: DbActionsProvider, private afDatabase: AngularFireDatabase) {
// Build Current User ID
this.currentUserID = this.dbAction.currentUserID().subscribe(data => {
this.currentUserID = data.uid;
});
}
ngOnInit() {
// Get data
this.afDatabase.object('data/users/' + this.currentUserID + '/visits')
.snapshotChanges().map(action => {
const data = action.payload.toJSON();
return data;
})
.subscribe(result => {
Object.keys(result).map(key => {
this.visits.push({ 'key': key, 'data':result[key]
});
}); console.log(this.visits)
})
}
The code in my view:
<ion-item-sliding *ngFor="let visit of visits | orderBy:'date' : false" (ionDrag)="onSelectedVisit(visit)">
<ion-item>
<ion-icon ios="ios-man" md="md-man" item-start></ion-icon>
<strong>{{ !visit.data.name == '' ? visit.data.name : 'Unbekannt' }}</strong>
<p>Musterstraße 8, 66130 Saarbrücken</p>
</ion-item>
<ion-item-options side="right">
<button ion-button>Bearbeiten</button>
<button ion-button color="danger" (click)="deleteVisit()">Löschen</button>
</ion-item-options>
<ion-input [(ngModel)]="visit.id"></ion-input>
</ion-item-sliding>
Ok..now I want that the user can delete items. For this I need access to the key reference ($key in firebase, but not works.....)...so I had to build my own object with this key field in the top. Not a pretty solution...do you have another idea?
The problem:
If the user swipe an item to see the Delete-Option, I pass data with (ionDrag)="onSelectedVisit(visit). My code in component for this function:
onSelectedVisit(visit) {
this.selectedVisit = visit.key;
console.log(this.selectedVisit);
}
deleteVisit() {
this.afDatabase.list('data/users/' + this.currentUserID + '/visits').remove(this.selectedVisit);
this.navCtrl.setRoot(VisitsPage);
}
If I not navigate back to VisitsPage (same page) I´ll see duplicates in my list because of the own builded object before.....so I need a more elegant solution..
Found a pretty solution:
export class AppComponent {
itemsRef: AngularFireList<any>;
items: Observable<any[]>;
constructor(db: AngularFireDatabase) {
this.itemsRef = db.list('messages');
// Use snapshotChanges().map() to store the key
this.items = this.itemsRef.snapshotChanges().map(changes => {
return changes.map(c => ({ key: c.payload.key, ...c.payload.val() }));
});
}
addItem(newName: string) {
this.itemsRef.push({ text: newName });
}
updateItem(key: string, newText: string) {
this.itemsRef.update(key, { text: newText });
}
deleteItem(key: string) {
this.itemsRef.remove(key);
}
deleteEverything() {
this.itemsRef.remove();
}
}
Reference: Github - Angularfire2 Docs
Does anyone know how to reset the "ion-option" values of "ion-select". I have two ion-select controls and i want my first ion-select(selectedPLocation) to change the values of my 2nd ion-select(selectedLocation) on ionChange. I am able to remove selected by setting null but i am not able to change the values of selectedLocation. Does anyone know how to reset the value of my ion-options ?
I'm currently using VS2015 s my IDE.
HTML:
<ion-list>
<ion-item>
<ion-label>Parent Location</ion-label>
<ion-select [(ngModel)]="selectedPLocation" (ionChange)="loadLocation()">
<ion-option *ngFor="let parentLocation of parentLocations; let i=index" [value]="parentLocation.Key">{{parentLocation.Id}}</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Location</ion-label>
<ion-select [(ngModel)]="selectedLocation">
<ion-option id="locationID" *ngFor="let location of locations; let i=index" [value]="location.Key">{{location.Id}}</ion-option>
</ion-select>
</ion-item>
</ion-list>
TypeScript:
public loadLocation() {
let loader = this.loadingCtrl.create({
content: "Please wait..."
});
loader.present();
this.selectedLocation = null; //Reset selected value only
this.locations = null; //Tried this but can't seem to reset the values
this.locationService.GetLocations(this.global.getApiUrl(), this.selectedSite, this.selectedPLocation).then(data => {
loader.dismiss();
this.locations = data;
}).catch((err) => {
loader.dismiss();
let alert = this.alertCtrl.create({
title: 'Error',
subTitle: err,
buttons: ['OK']
});
alert.present();
});}
I solved my own error, it is due to my Typescript codes call to my web service API (GetLocation).
Previous TypeScript Code:
public GetLocations(apiUrl, siteKey, pLocationKey) {
return new Promise((resolve, reject) => {
this.http.get(apiUrl + "site/" + siteKey + "/location/" + pLocationKey)
.map(res => res.json())
.subscribe(data => {
this.Locations = data; //Error Here
resolve(this.Locations);; //Error Here
},
err => {
reject(err);
});
});
}
Correct TypeScript Code:
public GetLocations(apiUrl, siteKey, pLocationKey){
return new Promise((resolve, reject) => {
this.http.get(apiUrl + "site/" + siteKey + "/location/" + pLocationKey)
.map(res => res.json())
.subscribe(data => {
resolve(data); //Corrected
},
err =>{
reject(err);
});
});
}