My card does not get the latest data from firestore even with pull refresh implemented in quasar
<q-pull-to-refresh #refresh="refresh">
<q-card
class="q-ma-md"
bordered
v-for="announcement in announcements"
:key="announcement.key"
>
<q-card-section>
<div class="text-h6">{{announcement.TITLE}}</div>
<div class="text-subtitle2">{{announcement.CONTENT}}</div>
</q-card-section>
</q-card>
</q-pull-to-refresh>
here is my script and methods
data() {
return {
announcements: [],
};
},
//methods
retrieveAnnouncements() {
firebase
.firestore()
.collection("announcement")
.get()
.then(snapShot => {
snapShot.forEach(element => {
const { TITLE, CONTENT, AUTHOR } = element.data();
//add retrieved data in announcement
this.announcements.push({
key: element.id,
TITLE,
CONTENT,
AUTHOR
});
});
});
},
here is my refresh method that tries to update the card of the current page
refresh(done) {
setTimeout(() => {
(this.announcements = null), done();
}, 1000);
},
created() {
this.retrieveAnnouncements();
}
Does your refresh function call retrieveAnnouncements?
It looks like it's only called on created
Related
My goal is to store a specific data in the localStorage when I click on a link
but log i get is either undefined or absolutely nothing.
<li v-for="(categorie, index) in categories" :key="index">
<a href="./currentCategory" #click.prevent="getCategory()">
<img class="categorie-img" :src="categorie.strCategoryThumb" >
<p>{{ categorie.strCategory }}</p>
</a>
</li>
data() {
return {
categories: []
}
},
methods: {
getAllCategories() {
axios
.get('https://www.themealdb.com/api/json/v1/1/categories.php')
.then((response) => {
console.log( response.data);
this.categories = response.data.categories;
}).catch(error => {
console.log(error);
alert("api can't be reached");
})
},
getCategory() {
localStorage.setItem('currentCategory', this.categorie.strCategory );
}
},
I am using this API https://www.themealdb.com/api/json/v1/1/categories.php
I guess this.categorie.strCategory is incorrect but i really cant figure it out
I also tried this.categories.strCategory
Try to pass category
#click.prevent="getCategory(categorie)
then save it
getCategory(cat) {
localStorage.setItem('currentCategory', cat );
}
Found the answer thanks to #Nikola Pavicevic
had to pass a category to the click event
#click.prevent="getCategory(categorie.strCategory)
and pass it to the function
getCategory(cat) {
localStorage.setItem('currentCategory', cat);
}
I know this has a simple answer but I appear to be stuck. I have an upload image input in a form. Following several tutorials, I have successfully created the upload method. My issue is once the image is uploaded to Firestore storage I use this.$emit('imgurl', downloadURL)
My problem is I do not know how to get that value so when the user submits the form the url gets added to the database.
Parts of the code:
HTML:
<div class="field avatar">
<label for="avatar">Avatar</label>
<input type="file" name="imgurl" accept="image/*" #change="detectFiles($event.target.files)">
<div class="progress-bar green" :style="{ width: progressUpload + '%'}">{{ progressUpload }}%</div>
<img class="avatar" v-bind:src="this.downloadURL">
</div>
Methods:
detectFiles (fileList) {
Array.from(Array(fileList.length).keys()).map( x => {
this.upload(fileList[x])
})
},
upload (file) {
var storage = firebase.storage();
this.uploadTask = storage.ref('avatars/'+file.name).put(file);
}
Watch:
watch: {
uploadTask: function() {
this.uploadTask.on('state_changed', sp => {
this.progressUpload = Math.floor(sp.bytesTransferred / sp.totalBytes * 100)
},
null,
() => {
this.uploadTask.snapshot.ref.getDownloadURL().then(downloadURL => {
this.downloadURL = downloadURL
this.$emit('imgurl', downloadURL)
})
})
}
}
Add to the database:
db.collection('teams').add({
team_name: this.team_name,
team_id: this.team_id,
bio: this.bio,
url: this.imgurl,
}).then(() => {
this.$router.push({ name: 'Admin' })
}).catch(err => {
console.log(err)
})
You can pass a function as a prop to a child component, then call this function passing your downloadURL as argument.
Parent Component
HTML
<child passURL="getDownloadURL">
JS
data: {
return {
downloadURL: null
}
},
methods: {
getDownloadURL: function(url) {
this.downloadURL = url
}
}
Child Component
JS
props: ['passURL'],
Inside your watcher, you can call
this.passURL(downloadURL)
Instead of $emit.
I found the answer. I added a hidden input field
<input type="hidden" name="imgurl" v-model="imgurl">
and replaced the emit with this.imgurl = downloadURL
I am learning Vuejs and I am stuck. Why can I see the messages get added to the object (in Chrome Vue debugger) yet it is not added to the div that contains the list?
My Vue Component:
<template>
<div id="round-status-message" class="round-status-message">
<div class="row">
<div class="col-xs-12" v-for="sysmessage in sysmessages" v-html="sysmessage.message"></div>
</div>
</div>
</template>
<script>
export default {
props: ['sysmessages'],
methods: {
scrollToTop () {
this.$el.scrollTop = 0
}
}
};
</script>
My Vue instance:
$(document).ready(function()
{
Vue.component('chat-system', require('../components/chat-system.vue'));
var chatSystem = new Vue({
el: '#system-chat',
data: function () {
return {
sysmessages: []
};
},
created() {
this.fetchMessages();
Echo.private(sys_channel)
.listen('SystemMessageSent', (e) => {
this.sysmessages.unshift({
sysmessage: e.message.message,
});
this.processMessage(e);
});
},
methods: {
fetchMessages() {
axios.get(sys_get_route)
.then(response => {
this.sysmessages = response.data;
});
},
processMessage(message) {
this.$nextTick(() => {
this.$refs.sysmessages.scrollToTop();
});
// updateGame();
}
}
});
});
My template call in HTML:
<div id="system-chat">
<chat-system ref="sysmessages" v-on:systemmessagesent="processMessage" :sysmessages="sysmessages" :player="{{ Auth::user() }}"></chat-system>
</div>
There are no compile or run time errors and I can see records added to the props in the vue chrome tool. I can also see empty HTML elements added to the div.
What have I missed?
UPDATE: My record structures:
response.data is an array of objects, each like this:
{"data":[
{"id":100,
"progress_id":5,
"message":"start message",
"action":"welcome"
},
{"id"....
e.message.message contains the text message entry, so just a string.
I am trying to access the message variable in each object during the fetchMessages method.
You're adding objects with sysmessage as the property.
this.sysmessages.unshift({
sysmessage: e.message.message,
});
But you are trying to view
v-for="sysmessage in sysmessages" v-html="sysmessage.message"
Based on your update, the code should be:
this.sysmessages.unshift({
message: e.message.message,
});
And you can leave the template as
v-html="sysmessage.message"
i have problem. When I click the button, it receives an entire database, but I want laod part database. How can I do this?
For example: After every click I would like to read 10 posts.
Thx for help.
Messages.vue:
<div class="chat__messages" ref="messages">
<chat-message v-for="message in messages" :key="message.id" :message="message"></chat-message>
<button class="btn btn-primary form-control loadmorebutton" #click="handleButton">Load more</button>
</div>
export default{
data(){
return {
messages: []
}
},
methods: {
removeMessage(id){...},
handleButton: function () {
axios.get('chat/messagesmore').then((response) => {
this.messages = response.data;
});
}
},
mounted(){
axios.get('chat/messages').then((response) => {
this.messages = response.data
});
Bus.$on('messages.added', (message) => {
this.messages.unshift(message);
//more code
}).$on('messages.removed', (message) => {
this.removeMessage(message.id);
});
}
}
Controller:
public function index()
{
$messages = Message::with('user')->latest()->limit(20)->get();
return response()->json($messages, 200);
}
public function loadmore()
{
$messages = Message::with('user')->latest()->get();
// $messages = Message::with('user')->latest()->paginate(10)->getCollection();
return response()->json($messages, 200);
}
paginate(10) Loads only 10 posts
You can do it like this:
<div class="chat__messages" ref="messages">
<chat-message v-for="message in messages" :key="message.id" :message="message"></chat-message>
<button class="btn btn-primary form-control loadmorebutton" #click="handleButton">Load more</button>
</div>
export default{
data(){
return {
messages: [],
moreMessages: [],
moreMsgFetched: false
}
},
methods: {
removeMessage(id){...},
handleButton: function () {
if(!this.moreMsgFetched){
axios.get('chat/messagesmore').then((response) => {
this.moreMessages = response.data;
this.messages = this.moreMessages.splice(0, 10);
this.moreMsgFetched = true;
});
}
var nextMsgs = this.moreMessages.splice(0, 10);
//if you want to replace the messages array every time with 10 more messages
this.messages = nextMsgs
//if you wnt to add 10 more messages to messages array
this.messages.push(nextMsgs);
}
},
mounted(){
axios.get('chat/messages').then((response) => {
this.messages = response.data
});
Bus.$on('messages.added', (message) => {
this.messages.unshift(message);
//more code
}).$on('messages.removed', (message) => {
this.removeMessage(message.id);
});
}
}
-initialize a data property morMsgFetched set to false to indicate if more messages are fetched or not
if morMsgFetched is false make the axios request and st the response to moreMessages, then remove 10 from moreMessages and set it to messages[]..
After that set morMsgFetched to true
on subsequest click remove 10 from moreMessages and push it to 'messages[]`
Use Laravels built in pagination.
public function index()
{
return Message::with('user')->latest()->paginate(20);
}
It returns you next_page url which you can use to get more results calculated automatically
This might be too late but i believe the best way to do it is using pagination, Initially onMounted you'll send a request to let's say /posts?page=1, the one is a variable let's say named 'pageNumber', each time the user clicks on the "Load More" button, you'll increment the pageNumber and resent the request, the link will page /posts?page=2 this time, at this point you can append the results you've got to the already existing one and decide if the Load More button should be shown based on the last_page attribute returned by laravel paginator...
I'm sure you already solved your problem or found another alternative, this might be usefull for future developers.
I am using vue.js 2 with webpack template. i am new to vue.js.
i want to bind DOM after data is received in ajax call.
here in my code contains v-for in which the response html is need to bind with v-html="tHtml[index]" every time after data is received from api call.
What can be used to re-bind or refresh view/DOM as we use $scope.$apply() in angularjs.
home.vue
<template>
<div class="row" id="home">
<h3 v-if="msg"><span class="label label-warning">{{msg}}</span></h3>
</div>
<div v-for="obj in tdata">
<div v-html="tHtml[$index]"></div>
</div>
</div>
</template>
<script>
import appService from '../service'
import bus from '../service/bus'
export default {
created() {
appService.checkAuth();
console.log("service appService val: "+appService.user.authenticated);
//called after vue has been created
bus.$on('eventBusWithTopic', (data) => { //fetch event bus on ready to get data
//alert("event fetched! "+data.user_id);
console.log("event fetched! "+data.user_id);
this.searchedTopic = data.topic;
this.user_id = data.user_id;
bus.$off('eventBusWithTopic'); //un-bind event after use
//check details
})
},
data() {
return {
searchedTopic: '',
user_id: '',
tdata: {},
tHtml: []
}
},
methods: {
getdata(){
console.log("dfd "+this.user_id);
appService.getdata(this, this.user_id, this.searchedTopic).success((res) => {
//console.log(" res: "+JSON.stringify(res));
this.tdata = res.data;
if(this.tdata.length > 0){
//**GET HTML** // <<--==--==--==
for(var i=0;i<this.tdata.length;i++){
this.getTemplate(this.tdata[i].id_str);
}
}
if(res.success == 0)
this.msg = res.message;
}).error((e) => console.log("error while getting data: "+JSON.stringify(e)))
},
getTemplate(id){
this.$http.get("https://uqkcgyy8wb.execute-api..*****../user/"+id+"/getHtml", (resp) => {
//return resp.data.html;
this.tHtml[this.tHtml.length] = resp.data.html;
console.log(this.tHtml);
}).error((e) => console.log("error while getting html: "+JSON.stringify(e)))
}
}
}
</script>