I tried to render a list of items by Vuejs, the code below is a simplified version of it. Basically, I need it to display data, the state and data appears in VueDevTool but not on the page.
<template>
<div>
<h1>{{this.sendersList.length}}</h1> <!-- 0 -->
<h1>{{senders.length}}</h1> <!-- 0 -->
</div>
</template>
<script>
export default{
data () {
return {
sendersList: []
}
},
created () {
this.$store.dispatch('getAllSenders', {
app_id: this.$route.params.chat_id
}).then(response => {
this.sendersList = response
})
},
computed: {
senders(){
return this.$store.getters.getAllSenders
}
}
}
</script>
Store code returns data as normal, VueDevtool can see it but I cant find away to render it on the front-end
getAllMessages(context, data){
return new Promise((resolve, reject) => {
axios.post('messages/getAllMessages', {
sender_id: data.sender_id
}).then(response => {
let payload = []
for (let index = 0; index < response.data.length; index++) {
payload.push({
message_id: response.data[index].message_id,
message_content: response.data[index].message_content,
message_type: response.data[index].message_type,
message_sentiment: response.data[index].message_sentiment,
sender_id: response.data[index].sender_id,
user_id: response.data[index].user_id,
from_sender: response.data[index].from_sender,
created_date: response.data[index].created_date,
})
}
context.commit('getAllMessages', payload)
resolve(payload)
}).catch(error => {
reject(error)
})
})
},
Try change this
<h1>{{this.sendersList.length}}</h1>
To this
<h1>{{sendersList.length}}</h1>
Related
<template>
<div class="hello">
<h1>Example 2</h1>
<input #click="send" type="button" value="Send" />
<div class="out" v-if="successIds.length">{{ successIds }}</div>
</div>
</template>
<script>
/*
#return
resolve: { id: 1, success: true }
or
reject: { success: false }
*/
const fakeApiRequest = (id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = id % 2;
success ? resolve({ id, success }) : reject({ success });
}, 2000);
});
};
export default {
data() {
return {
// Fetch ids
ids: [1, 2, 3, 4, 5, 6],
// Complete ids
successIds: [],
};
},
methods: {
// iterating through the ids array
newValues(id) {
this.ids.forEach((el) => el.this.fakeApiRequest(id));
},
// filling the successIds array
send(id) {
this.$set(this, "successIds", this.newValues(id));
},
},
};
</script>
How can I fill and display the successId array in the template with the iterated elements of the existing array using Promise function within a $set Vue method? I seem to fail trying to reach the fakeApiRequest in the newValues function.
I'm not sure why you think you need to use the $set method. There are clear documented uses for it, and setting/replacing an array is not one. Besides that though, to be frank, there are a lot of issues with your code, and it's not very clear what you're trying to do, but I did my best to correct all the issues and left comments describing my changes.
sandbox example
<template>
<div class="hello">
<h1>Example 2</h1>
<input type="button" value="Send" #click="send" />
<div v-if="successIds.length" class="out">{{ successIds }}</div>
</div>
</template>
<script>
export default {
data() {
return {
// Fetch ids
ids: [1, 2, 3, 4, 5, 6],
// Complete ids
successIds: []
};
},
methods: {
// note 1: method loops through all ids so not sure what the 'id' param is for
// note 2: calling other async methods requires we use 'async' and 'await' keywords
async newValues(id) {
// note 3: the code in this method before was non-sensical to me, e.g. "el.this.fakeApiRequest" isn't valid syntax
// and the forEach loop didn't do anything with the actual result returned by fakeApiRequest.
// note 4: forEach actually isn't designed for async code. Must use normal for loop
const results = [];
for (let i = 0; i < this.ids.length; i++) {
let res = null;
try {
res = await this.fakeApiRequest(this.ids[i]);
} catch (rejectVal) {
res = rejectVal;
}
console.log('res', res);
results.push(res);
}
return results;
},
// note 5: not sure why id is a param as this method isn't called with any specific id
async send(id) {
// note 6: the use of $set before was unnecessary
this.successIds = await this.newValues();
},
/*
#return
resolve: { id: 1, success: true }
or
reject: { success: false }
*/
// note 7: moved this here so it can be called by other methods. decreased timeout time for sanity's sake
fakeApiRequest(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = id % 2;
success ? resolve({ id, success }) : reject({ success });
}, 100);
});
}
}
};
</script>
I use Strapi V4. I have a link collection and I want to update likes.
How update the relation array ? When I put new data old value are replace by the new one.
Example :
likes : [1]
if I update another time
likes:[2].
BUT I want this likes : [1,2]
I try this but It d'oesn't work. Thans for your replay
'use strict';
/**
* link controller
*/
const { createCoreController } = require('#strapi/strapi').factories;
module.exports = createCoreController('api::link.link', ({ strapi }) => ({
// Method 2: Wrapping a core action (leaves core logic in place)
async find(ctx) {
const { data, meta } = await super.find(ctx);
const linkId = data.map((link) => link.id);
const allPosts = await strapi.entityService.findMany('api::link.link', {
fields: ["id"],
filters: { id: { $in: linkId } },
populate: {
likes: { count: true },
},
});
data.forEach(link => {
link.likes = allPosts.find(({ id }) => id === link.id)?.likes?.count || 0;
});
//update value with new array => need to be fix
await strapi.entityService.update("api::link.link", {
likes: [...allPosts.likes.map(({ id }) => id), ...likes],
});
return { data, meta };
},
}));
This part need to be fix. Can you help me ? Thanks
//update value with new array => need to be fix
await strapi.entityService.update("api::link.link", {
likes: [...allPosts.likes.map(({ id }) => id), ...likes],
});
As I am starting my experience with Firebase I am a little bit struggling with the pagination of posts on my blog website :(.
I think I kind of understood the docs from Google and I know how to move the pagination to the next page. However, I have absolutely no clue how to paginate back to the previous page.
Basically, I wanted to have a simple pagination component which will look something like that: < 1 2 3 [...] > (where you can paginate next and back using the arrows).
It is fine to paginate to the next page but, when it comes to paginating back I cannot find any proper tutorial to do it in pure React.
I have tried to use various methods from startAt, endAt, endBefore etc. But the result was or an error or it was moving me back to the first page (even when I was on the third or fourth)
I even tried to find the first object in an array and use it as endBefore but it resulted again in paginating back to the first page.
That's how my code looks right now (yes I know that pageNext() and pagePrev() are the same)
import React, { Component } from 'react'
import { withFirebase } from './Firebase'
import Post from './Post'
import '../scss/Post.scss'
class Posts extends Component {
constructor(props) {
super(props);
this.state = {
loading:false,
posts:[],
post_id:[],
lastVisible:null,
limit:2
}
this.handlePageNext = this.handlePageNext.bind(this);
}
componentDidMount() {
let newPosts=[];
let postsId=[];
this.setState({ loading: true });
this.props.firebase.posts()
.orderBy('date', 'desc')
.limit(2)
.get().then(querySnapshot => {
let lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];
this.setState({ lastVisible: lastVisible});
querySnapshot.forEach(doc => {
newPosts = newPosts.concat(doc.data());
postsId = postsId.concat(doc.id);
this.setState({
posts:newPosts,
post_id:postsId,
loading:false
});
})
})
}
handlePageNext() {
let newPosts=[];
let postsId=[];
this.setState({ loading: true });
this.props.firebase.posts()
.orderBy('date', 'desc')
.startAt(this.state.lastVisible)
.limit(this.state.limit)
.get().then(querySnapshot => {
let lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];
this.setState({ lastVisible:lastVisible });
querySnapshot.forEach(doc => {
newPosts = newPosts.concat(doc.data());
postsId = postsId.concat(doc.id);
this.setState({
posts:newPosts,
post_id:postsId,
loading:false
});
})
})
}
handlePagePrev() {
let newPosts=[];
let postsId=[];
this.setState({ loading: true });
this.props.firebase.posts()
.orderBy('date', 'desc')
.startAt(this.state.lastVisible)
.limit(this.state.limit)
.get().then(querySnapshot => {
let lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];
this.setState({ lastVisible:lastVisible});
querySnapshot.forEach(doc => {
newPosts = newPosts.concat(doc.data());
postsId = postsId.concat(doc.id);
this.setState({
posts:newPosts,
post_id:postsId,
loading:false
});
})
})
}
render() {
return (
<div className='posts'>
<div className='row'>
{this.state.posts.map((post, i) => (
<Post
key={i}
title={post.title}
author={post.author}
desc={post.desc}
text={post.text}
id={this.state.post_id[i]}
date={post.date}
imgURL={post.imgURL}/>
))}
{this.state.loading && <p>Loading...</p>}
<button className='btn' onClick={() => this.handlePagePrev()}>←</button>
<button className='btn' onClick={() => this.handlePageNext()}>></button>
</div>
</div>
)
}
}
export default withFirebase(Posts);
I wanted to have a simple pagination using buttons (left and right arrows) but I am struggling with it for already 3rd hour and cannot find the proper solution to this.
You have to keep the "lastVisible" and pass it to startAfter(). 2 functions I wrote below:
export const getMostRecentPostsFirstPage = (limit, specificUserId) => {
if (!Number.isInteger(limit) || limit < 1) {
throw new Error('limit must be a positive integer');
}
const collection = Firestore.collection('posts');
let query = null;
if (specificUserId) {
query = collection
.where('userId', '==', `${specificUserId}`)
.orderBy('postedTimestamp', 'desc')
.limit(limit);
} else {
query = collection.orderBy('postedTimestamp', 'desc').limit(limit);
}
return new Promise((resolve, reject) => {
const posts = [];
query
.get()
.then(snapshot => {
const lastVisible = snapshot.docs[snapshot.docs.length - 1];
snapshot.forEach(post => {
posts.push(post.data());
});
const hasMore = posts.length == limit;
resolve({ posts: posts, lastVisible: lastVisible, hasMore: hasMore });
})
.catch(error => reject(error));
});
};
export const getMostRecentPostsNextPage = (lastVisible, limit, specificUserId) => {
if (!lastVisible) {
throw new Error('Need to provide lastVisible argument');
}
if (!Number.isInteger(limit) || limit < 1) {
throw new Error('limit must be a positive integer');
}
const collection = Firestore.collection('posts');
let query = null;
if (specificUserId) {
query = collection
.where('userId', '==', `${specificUserId}`)
.orderBy('postedTimestamp', 'desc')
.startAfter(lastVisible)
.limit(limit);
} else {
query = collection
.orderBy('postedTimestamp', 'desc')
.startAfter(lastVisible)
.limit(limit);
}
return new Promise((resolve, reject) => {
const posts = [];
query
.get()
.then(snapshot => {
const lastVisible = snapshot.docs[snapshot.docs.length - 1];
snapshot.forEach(post => {
posts.push(post.data());
});
const hasMore = posts.length == limit;
resolve({ posts: posts, lastVisible: lastVisible, hasMore: hasMore });
})
.catch(error => reject(error));
});
};
It uses redux-saga, but you get the idea.
on first query, do not call "startAfter()", but do on the subsequent queries, and you must save "lastVisible" between each call.
Here is standard pagination by using Firebase in reactjs.
I'm actually working on a VueJs project where I meet some problems.
The 1st is that when I'm reloading page using parameters, I'm throwed back to the root page and I don"t understand why. I'm actually using the vue webpack template and lazy loading for my routes templates.
The 2nd problem is that I'm making a page of comments for my project who's are generated from a array of object. When the user has done posting his comment a new array is loaded from the database and put in the data of the parent as following :
parentComponent -> data -> array of objects -> each object = a component
So I used this.$set to put datas but it has not worked,I used a foreach loop and now I'm just replacing the array like this :
oldArray = new Array
But it doesn't work and my child components don't want to update even with forceUpdate().Maybe it's something very silly but I didn't found the answer.
If someone could have the answer that would be very nice to share it.
Here is my parent code:
<template>
<div class='comments'>
<div v-if="comments.length > 0" class="comments__block">
<comment-block v-for="comment in comments" :key="comment.Id" :comment.sync="comment" :updateHandler="loadComments"></comment-block>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'Comments',
data () {
return {
page: 1,
comments: [],
numberPages: 0,
resultEmpty: false
}
},
components: {
'comment-block': commBlock,
},
computed: {
methods: {
loadComments (nextPage = 1) {
if (isLogged) {
axios
.get(`API query if logged)
.then(response => {
if (Success) {
if (Comments) {
this.comments = Comments
this.resultEmpty = false
} else {
this.resultEmpty = true
}
}
})
.catch(e => {
console.log(e)
})
} else {
axios
.get(`url if not logged`)
.then(response => {
if (Success) {
if (Comments) {
this.comments = []
Comments.forEach(c => {
this.comments.push(c)
})
this.resultEmpty = false
} else {
this.resultEmpty = true
}
}
})
.catch(e => {
console.log(e)
})
}
}
},
mounted () {
this.loadComments()
},
watch: {
'$route' (to, from) {
this.loadComments()
}
},
}
</script>
And for the children
<template>
<div class='comment-block'>
<div class="comment-block__header">
<div class="comment-block__username">
{{userName}}
</div>
<div v-if="isLogged" class="comment-block__likes">
<input v-model="like" class="comment-block__radio" type="radio" name="likes" id="like" value="Y"/><label class="comment-block__radio-label comment-block__radio-label--like" for="like" v-bind:class="{'comment-block__radio-label--liked': like == 'Y'}" #click="toggle('Y')">{{nbLikes}}<v-icon large color="white">keyboard_arrow_up</v-icon></label>
<input v-model="like" class="comment-block__radio" type="radio" name="likes" id="dislike" value="N"/><label class="comment-block__radio-label comment-block__radio-label--dislike" for="dislike" v-bind:class="{'comment-block__radio-label--liked': like == 'N'}" #click="toggle('N')">{{nbDislikes}}<v-icon large color="white">keyboard_arrow_down</v-icon></label>
<input v-model="like" class="comment-block__radio" type="radio" name="likes" id="disapproved" value="D"/><label class="comment-block__radio-label comment-block__radio-label--disapproved" for="disapproved" v-bind:class="{'comment-block__radio-label--liked': like == 'D'}" #click="toggle('D')">{{nbDisapproved}}<v-icon large color="white">report</v-icon></label>
</div>
<div v-else class="comment-block__likes">
<button class="comment-block__button" #click="displayMessage = ! displayMessage" id="like"><p class="comment-block__radio-p comment-block__radio-p--like" for="like">{{comment.NbLikes}}<v-icon large color="white">keyboard_arrow_up</v-icon></p></button>
<button class="comment-block__button" #click="displayMessage = ! displayMessage" id="dislike"><p class="comment-block__radio-p comment-block__radio-p--dislike" for="dislike">{{comment.NbDislikes}}<v-icon large color="white">keyboard_arrow_down</v-icon></p></button>
<button class="comment-block__button" #click="displayMessage = ! displayMessage" id="disapproved"><p class="comment-block__radio-p comment-block__radio-p--disapproved" for="disapproved">{{comment.NbDisapproved}}<v-icon large color="white">report</v-icon></p></button>
</div>
</div>
<div class="comment-block__body">
<div cols="12">
<div class="comment-block__commentary">
{{commentary }}
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'Comments',
data () {
return {
id: this.comment.idComment,
userName: this.comment.UserName,
commentary: this.comment.Commentary,
nbLikes: this.comment.NbLikes,
nbDislikes: this.comment.NbDislikes,
nbDisapproved: this.comment.NbDisapproved,
displayedLikes: this.nbLikes,
displayedDislikes: this.nbDislikes,
displayedDisapproved: this.nbDisapproved,
lastLike: this.comment.LastLike,
like: this.comment.LastLike,
displayMessage: false
}
},
props: {
comment: {type: Object, required: true},
updateHandler: {type: Function, required: true}
},
computed: {
isLogged () {
if (this.$store.state.jwt.token) {
return true
}
return false
}
},
methods: {
submitLike () {
var payload = {
IdComment: this.id,
Like: this.like
}
var header = {
headers: {
Authorization: this.$store.state.jwt.token
}
}
axios
.post('someUrl', payload, header)
.then(resp => {
if (Success) {
this.updateHandler()
}
})
.catch(e => {
console.log(e)
})
},
toggle (value) {
if (value === this.like) {
this.like = ''
}
}
},
watch: {
like (newVal, oldVal) {
if (newVal !== oldVal) {
this.submitLike()
switch (oldVal) {
case 'Y' : this.nbLikes--
break
case 'N' : this.nbDislikes--
break
case 'D' : this.nbDisapproved--
break
}
switch (newVal) {
case 'Y' : this.nbLikes++
break
case 'N' : this.nbDislikes++
break
case 'D' : this.nbDisapproved++
break
}
}
if (oldVal === newVal) {
this.like = ''
}
},
comment (newVal) {
this.$forceUpdate()
}
}
}
</script>
PS: Sorry for my bad english if it is.
I would like to add an array into an array object. However, I am only able to add the array into a new object instead of the existing one. Is there any way where I can link the array to the existing object? Its much more easier for me too if I could add in the array based on which link it is from.
Here is my code:
this.af.database.list(`/users/${userid}/favourites`, {
query: { orderByChild: 'priority' },
preserveSnapshot: true
})
.subscribe(snapshots => {
snapshots.forEach(snapshot => {
this.category.push({
name: snapshot.val().name,
rss: snapshot.val().regions[0].rss
});
})
for (let i = 0; i < this.category.length; i++) {
this.http.get(this.category[i].rss)
.map(res => res.text())
.subscribe((data) => {
this.parseXML(data)
.then((data) => {
this.xmlItemsApac = data
this.category.push({
feeds: data
})
});
});
}
});
console.log(this.category)
parseXML(data) {
return new Promise(resolve => {
var k,
arr = [],
parser = new xml2js.Parser(
{
explicitArray: false
});
parser.parseString(data, function (err, result) {
var obj = result.rss.channel;
for (k in obj.item) {
var item = obj.item[k];
arr.push({
title: item.title,
link: item.link,
description: item.description,
pubDate: item.pubDate
});
}
resolve(arr);
});
});
}