How to load Firebase data before drawing Vue component - firebase

I have a firebase database connection. I can upload data. I can get data.
But during mounted cycle, my build_view jsonz = undefined. Nothing gets drawn. When I navigate to another page and then back to build_view, the data from the db is present and drawn.
build_view.vue
<template>
<div **v-if="jsonz"** id="outerdivFullPage" class="roundedz d-block my-0 w-100 float-center mx-auto">
<div class="row mx-1 mb-5">
<div class="col-4 mb-3">
<img class="icon-xl mx-auto d-block" src="../img/main/professions/guardian.png">
<builder v-for="x in this.jsonz.guardian[0]"
class=""
:key="x"
:name="x.name"
:link="x.link"
:chatCode="x.chatCode"
:type="x.type"
:support="x.support"
:profession="x.profession"
></builder>
</div>
</div>
</template>
<script>
import builder from '../components/build_component.vue'
import crudService from "../services/crudService";
export default {
name: 'build_view',
data(){
return{
jsonz: false,
clazz: "",
profession: "",
name: "",
link: "",
chatCode: "",
type: "",
support: "",
hover: false
}
},
methods: {
**async getAll()**{
this.jsonz = crudService.getAll();
}
},
components: {
builder
},
created(){
console.log("CREATED");
this.**getAll()**;
},
mounted: function(){
console.log("MOUNTED");
console.log(**this.jsonz**); // undefined
}
}
</script>
CrudService.js
import firebase from "../firebase";
let db = firebase.ref("/array");
class CrudService {
**getAll()** {
var childData;
db = firebase.ref("/array")
db.on('value',function(snapshot){
snapshot.forEach(function(childSnapshot){
childData = childSnapshot.val();
})
})
return childData;
}
}
export default new CrudService();
More details here:

Related

vue3 page doesnt scroll until refresh

I have a vue3 web app. My issue is that once I try to navigate to a page using <router-link to ="/Dashboard"/>
Below is the Dashboard.vue
<template>
<div class="enquiry">
<div class="row">
<div class="col-6" v-for="(p, index) in keyAreas" :key="index">
<div class="card" style="margin-bottom: 10px">
<div class="card-body">
<h2 class="card-title">
{{ p.number }}
<span class="card-title" style="float: right">{{ p.title }}</span>
</h2>
<h5 class="card-text">
Properties for rent
<span class="card-title" style="float: right; margin-top: -5px">
<Doughnut
:chart-data="updateChartData(p.number, totalPropertiesNumber)"
:width="80"
:height="80"
/>
</span>
</h5>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref } from "vue";
import { projectDatabase } from "../../firebase/config";
import getUser from "../../composables/getUser";
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
ArcElement,
CategoryScale,
} from "chart.js";
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale);
export default {
setup() {
//to get user info e.g email and display name
const { user } = getUser();
const company = ref("");
const keyAreas = ref([]);
//all LGAs
const allLGAs = ref([
{ title: "Abuja", number: 0 },
{ title: "Banana Island", number: 0 },
{ title: "Bluewaters Lagos", number: 0 },
{ title: "Benin City", number: 0 },
{ title: "Eko Atlantic", number: 0 },
]);
//Query Function for Specific Locations
const filterLocation = (item, query, filter) => {
if (item[filter] === query) {
return true;
}
return false;
};
//reference from firebase for user company
projectDatabase
.ref("users")
.child(user.value.uid)
.child("company")
.on("value", (snapshot) => {
company.value = snapshot.val();
//loop through all LGAs array and update dashboard by filtering each LGA for its properties in its field
allLGAs.value.forEach(function (p) {
p.number = Object.keys(snapshot.val())
.map((key) => {
snapshot.val()[key].id = key;
return snapshot.val()[key];
})
.filter((item) => {
return filterLocation(item, p.title, "location");
}).length;
if (p.number > 0) {
keyAreas.value.push(p);
}
});
});
return {
allLGAs,
company,
keyAreas,
};
},
};
</script>
The problem is every time i move to a new page, the page freezes and I have to refresh to see all the items in the v-for loop. This happens to about 3 pages on the web app. Is there a way to solve this?
I have also tried disabling all my browser extensions and things of that nature yet the problem still persists. Could it be because of the size of the array being loaded in the v-for?
OP solved his issue by finding out that Bootstrap v5 adds a class called offcanvas with
overflow: hidden;
overflow-x: hidden;
overflow-y: hidden;
Enabling the scrolling makes it functional again.

How do I display a route parameter (Vue / Firebase)

I'm creating a blog with free sewing patterns as content. I'm using route parameters to receive each blog individually. However, I'm getting a blank page when trying to retrieve its data from firebase firestore. Please help.
The blog's id appears on my address bar:
http://localhost:8080/#/admin/single-pattern/4LIS362IEWa7RKEv79g8
But it renders a blank page. I cant see my blog content.
This is my route path code. I've added a parameter of :id in my singlepattern. The SinglePattern component is where I will get the individual blog's data:
{
path: "/admin",
name: "admin",
component: Admin,
meta: {
auth: true,
},
children: [
{
path: "dashboard",
name: "dashboard",
component: Dashboard,
},
{
path: "manage-patterns",
name: "manage-patterns",
component: ManagePatterns,
},
{
path: "single-pattern/:id",
name: "single-pattern",
component: SinglePattern,
},
],
},
Here is my "ListPattern" component's code. ListPattern is where all my sewing blogs are displayed.
<template>
<div class="list-blogs">
<h1>LIST BLOG TITLES</h1>
<br />
<input type="text" v-model="search" placeholder="search blogs" />
<div
class="blog-cover"
v-for="pattern in filteredPatterns"
:key="pattern.id"
>
<div>
<router-link v-bind:to="'/admin/single-pattern/' + pattern.id">
<h3 style="cursor: pointer" v-rainbow>
{{ pattern.title | uppercase }}
</h3></router-link
>
</div>
<p
:style="'background-color: var(--lightgrey)'"
:inner-html.prop="pattern.description | snippet"
></p>
</div>
</div>
</template>
<script>
import firebase from "firebase";
import searchMixin from "../mixins/searchMixin";
// Basic Use - Covers most scenarios
import { VueEditor } from "vue2-editor";
import Quill from "quill";
const AlignStyle = Quill.import("attributors/style/align");
Quill.register(AlignStyle, true);
// import $ from "jquery";
import Swal from "sweetalert2";
window.Swal = Swal;
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
});
window.Toast = Toast;
export default {
name: "ManagePatterns",
components: { VueEditor },
data() {
return {
patterns: [],
pattern: {
title: null,
description: null,
image: null,
},
search: "",
};
},
firestore() {
return {
patterns: firebase.firestore().collection("free-patterns"),
};
},
computed: {},
},
};
</script>
And this is my 'SinglePattern' component where the clicked blog/pattern is displayed.
<template>
<div class="single-pattern">
<div class="blog-cover">
<div>
</div>
<div v-if="pattern">
<h3 style="cursor: pointer">
{{ pattern.title }}
</h3>
<div v-if="pattern.description">
<p
:style="'background-color: var(--lightgrey)'"
:inner-html.prop="pattern.description"
></p>
</div>
</div>
</div>
</div>
</template>
<script>
import firebase from "firebase";
import searchMixin from "../../mixins/searchMixin";
export default {
data() {
return {
id: this.$route.params.id,
patterns: [],
pattern: {
title: null,
description: null,
image: null,
},
};
},
firestore() {
return {
patterns: firebase.firestore().collection("free-patterns"),
};
},
mixins: [searchMixin],
created() {
console.log(this.$route.params.id);
var pat = this;
firebase
.firestore()
.collection("free-patterns")
.doc(this.$route.params.id)
.get()
.then(function(doc) {
if (doc.exists) {
pat.pattern = doc.data().pattern;
} else {
console.log("no such doc");
}
});
},
methods: {},
};
</script>
It works. I just had to change the code in my created() hook in 'SingePattern' component.
created() {
console.log(this.$route.params.id);
var docRef = firebase
.firestore()
.collection("free-patterns")
.doc(this.$route.params.id);
docRef
.get()
.then((doc) => {
if (doc.exists) {
this.pattern = doc.data();
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
})
.catch((error) => {
console.log("Error getting document:", error);
});

VUE - FIREBASE | How to get the user profile from the realtime database

I got the user profile from the Realtime database but when I have more than 1 account I get the second user profile too.
Here below you see the data from 2 users. But I want to get the user that is loggend in and that is the currentUser
The ID is the currentUser
This is the Realtime database:
This is my Profile.vue page:
<div class="container" v-for="profileData of profile" :key="profileData['.key']">
<div v-if="seen" class="row">
<div class="col">
<div class="card card-border" style="width: 30rem;">
<div class="card-body">
<h4 class="card-title text-center mb-4">Personal information</h4>
<p class="card-text">ID: {{profileData.CurrentUser}}</p>
<p class="card-text">First name: {{profileData.firstName}}</p>
<p class="card-text">Last name: {{profileData.lastName}}</p>
<p class="card-text">Phone number: {{profileData.phoneNumber}}</p>
<p class="card-text">Adress: {{profileData.adress}}</p>
<p class="card-text">Citizenship: {{profileData.citizenship}}</p>
<p class="card-text">Personal email: {{profileData.personalEmail}}</p>
</div>
</div>
</div>
<div class="col"></div>
<div class="col">
<div class="card card-border" style="width: 30rem;">
<div class="card-body">
<h4 class="card-title text-center mb-3">Business information</h4>
<p>Company name: {{profileData.companyName}}</p>
<p>Chamber Of Commerce Number: {{profileData.chamberOfCommerceNumber}}</p>
<p>Street: {{profileData.street}}</p>
<p>House number: {{profileData.houseNumber}}</p>
<p>ZIP code: {{profileData.zipCode}}</p>
<p>Location: {{profileData.location}}</p>
<p>Company email: {{profileData.companyEmail}}</p>
</div>
</div>
</div>
</div>
</div>
I added a if/else in the created() section below.
And this is the script:
<script>
import firebase from "firebase";
import { db } from '../../config/db';
export default {
data() {
return {
email: "",
password: "",
profileData: [],
isHidden: true,
seen: true,
isLoggedIn: false
}
},
firebase: {
profile: db.ref('profile')
},
methods: {
resetPassword() {
const auth = firebase.auth();
auth.sendPasswordResetEmail(auth.currentUser.email).then(() => {
console.log('Email send');
// Email sent.
}).catch((error) => {
// An error happened.
console.log(error);
});
}
},
created() {
if(firebase.auth().currentUser) {
this.isLoggedIn = true;
this.currentUser = firebase.auth().currentUser.email;
}
var user = firebase.auth().currentUser;
if (this.user == this.profileData.CurrentUser) {
this.seen = true;
} else {
this.seen = false;
}
}
};
</script>
In this Profile.vue page I have the add function:
AddProfile() {
console.log(JSON.stringify(this.profileData) + this.currentUser)
this.$firebaseRefs.profile.push({
firstName: this.profileData.firstName,
lastName: this.profileData.lastName,
phoneNumber: this.profileData.phoneNumber,
adress: this.profileData.adress,
citizenship: this.profileData.citizenship,
personalEmail: this.profileData.personalEmail,
companyName: this.profileData.companyName,
chamberOfCommerceNumber: this.profileData.chamberOfCommerceNumber,
street: this.profileData.street,
houseNumber: this.profileData.houseNumber,
zipCode: this.profileData.zipCode,
location: this.profileData.location,
companyEmail: this.profileData.companyEmail,
CurrentUser: this.currentUser
})
this.profileData.firstName = '';
this.profileData.lastName = '';
this.profileData.phoneNumber = '';
this.profileData.adress = '';
this.profileData.personalEmail = '';
this.profileData.companyName = '';
this.profileData.chamberOfCommerceNumber = '';
this.profileData.street = '';
this.profileData.houseNumber = '';
this.profileData.zipCode = '';
this.profileData.location = '';
this.profileData.companyEmail = '';
this.CurrentUser = '';
window.scrollTo(0,0, 0,0);
console.log('Added to database');
/* Waiting for 2 seconds here */
this.$router.push('/internship')
},
Apparently you are using Vuefire.
As you will see in the Vuefire documentation, by doing
firebase: {
profile: db.ref('profile')
},
you are using a declarative biding on the profile Realtime Database node and therefore it is normal that you get all the children of this node.
If you just want to display the node corresponding to the current user, you could use the programmatic binding, along the following lines:
<template>
<div class="home">
{{user}}
<ol></ol>
</div>
</template>
<script>
import { db } from "../firebase";
const profile = db.ref("profile");
export default {
name: "demo",
data() {
return {
user: null,
id: null
};
},
watch: {
id: {
immediate: true,
handler(id) {
this.$rtdbBind("user", profile.child(id));
}
}
},
created() {
if (firebase.auth().currentUser) {
this.id = currentUser.uid;
}
}
};
</script>

Vuex state change does not trigger reactivity on the page

I'm making a captcha component using vue. I try to fetch the captcha when the component created. When I do this in a async manner, the page will not be reactive, although the state has already been updated. But I when do it in sync manner, everything is fine. So, I'm wondering why async manner won't work?
This works
<template>
<section>
<div class="captcha-container">
<div v-if="captcha" v-html="captcha.data"></div>
</div>
</section>
</template>
<script>
import { mapState, mapActions } from "Vuex";
export default {
created: function() {
this.$store.commit('setCaptcha', {id: 'xx', data:'Hi'});
},
computed: {
...mapState(["captcha"])
},
};
</script>
This does not work
<template>
<section>
<div class="captcha-container">
<div v-if="captcha" v-html="captcha.data"></div>
</div>
</section>
</template>
<script>
import { mapState, mapActions } from "Vuex";
export default {
created: function() {
setTimeout(() => {
this.$store.commit('setCaptcha', {id: 'xx', data:'Hi'});
}, 1000);
},
computed: {
...mapState(["captcha"])
},
};
</script>

WP Rest API with vue.js

I am not sure what I am doing wrong here, still pretty noob at vue js so that might be the problem.
The problem is that it does not display anything. I got it to work with older vue version with a bit different code, but yeah...
var App = Vue.extend({});
var postList = Vue.extend({
template:'#post-list-template',
data: function(){
return {
posts: ''
}
},
mounted: function(){
posts = this.$http.get('/wp-json/wp/v2/posts?per_page=10');
posts.get(function(posts){
this.$set('posts', posts);
})
}
});
var router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: postList}
]
});
new Vue({
el: '#app',
router: router,
template: '<router-view></router-view>'
});
HTML is here if that makes things a bit easier to understand :
<div class="container-fluid projects" id="projects">
<h1 class="text-center project-heading">Projects</h1>
<div class="white-wrap">
<div id="app">
<router-view></router-view>
</div>
</div>
<template id="post-list-template">
<div class="container">
<div class="post-list">
<article v-for="post in posts">
<div class="post-content">
<h2>{{ post.title.rendered }}</h2>
{{ post.id }}
</div>
</article>
</div>
</div>
</template>
</div>
This resolved my problem:
var postLists = Vue.component('post-list',{
template:'#post-list-template',
data: function () {
return {
posts:'',
}
},
mounted:function () {
this.$http.get('./wp-json/wp/v2/posts').then(response => {
// get body data
this.posts = response.body;
this.posts.forEach(function (){
} );
}, response => {
console.log('Not Found');
});
}
});
//router
var router = new VueRouter({
routes: [
{ path: '', component: postLists },
]
});
new Vue({
el: '#app',
router: router,
});

Resources