vue3 composition API - watch - vuejs3

I am trying to get to grips with the composition API. Struggling with watch:
const totalValuation = ref(0);
const values = ref([1, 2, 3]);
totalValuation.value = watch(finalTasksFiltered.value, () => {
return values.value.reduce((prev, curr) => {
console.log(prev + curr);
return prev + curr;
}, 0);
});
return {
finalTasksFiltered,
totalValuation,
};
The console.log works exactly like it should (1,3,6) but I cannot seem to render it to the DOM.
When I check to console it is fine but in the DOM like so {{ totalValuation }} it returns:
() => { (0,_vue_reactivity__WEBPACK_IMPORTED_MODULE_0__.stop)(runner); if (instance) { (0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.remove)(instance.effects, runner); } }
Oh, I am using Quasar - not sure if that makes a difference.
I am sure its something small.
I have imported ref and watch from vue.
I have a computed function working fine too.

watch is meant to execute a function when some value changes. It is not meant to be assigned as a ref. What you're looking to do seems like a better fit for computed
watch: (no assignment)
watch(finalTasksFiltered.value, () => {
totalValuation.value = values.value.reduce((prev, curr) => {
console.log(prev + curr);
return prev + curr;
}, 0);
});
computed: (uses assignment)
const totalValuation = computed(() => {
return values.value.reduce((prev, curr) => {
console.log(prev + curr);
return prev + curr;
}, 0);
});

Related

How to do pagination based on the document position within a collection? (offset pagination)

I'm trying to do a pagination where the user can see each button's page number in the UI. I'm using Firestore and Buefy for this project.
My problem is that Firestore is returning wrong queries for this case. Sometimes (depending the page that the users clicks on) It works but sometimes don't (It returns the same data of the before page button).
It's really messy I don't understand what's going on. I'll show you the code:
Vue component: (pay attention on the onPageChange method)
<template>
<div>
<b-table
:data="displayData"
:columns="table.columns"
hoverable
scrollable
:loading="isLoading"
paginated
backend-pagination
:total="table.total"
:per-page="table.perPage"
#page-change="onPageChange">
</b-table>
</div>
</template>
<script>
import { fetchBarriosWithLimit, getTotalDocumentBarrios, nextBarrios } from '../../../../firebase/firestore/Barrios/index.js'
import moment from 'moment'
const BARRIOS_PER_PAGE = 5
export default {
data() {
return {
table: {
data: [],
columns: [
{
field: 'name',
label: 'Nombre'
},
{
field: 'dateAddedFormatted',
label: 'Fecha aƱadido'
},
{
field: 'totalStreets',
label: 'Total de calles'
}
],
perPage: BARRIOS_PER_PAGE,
total: 0
},
isLoading: false,
lastPageChange: 1
}
},
methods: {
onPageChange(pageNumber) {
// This is important. this method gets fired each time a user clicks a new page. I page number that the user clicks.
this.isLoading = true
if(pageNumber === 1) {
console.log('show first 5...')
return;
}
const totalPages = Math.ceil(this.table.total / this.table.perPage)
if(pageNumber === totalPages) {
console.log('show last 5...')
return;
}
/* Here a calculate the next starting point */
const startAfter = (pageNumber - 1) * this.table.perPage
nextBarrios(this.table.perPage, startAfter)
.then((querySnap) => {
this.table.data = []
this.buildBarrios(querySnap)
console.log('Start after: ', startAfter)
})
.catch((err) => {
console.err(err)
})
.finally(() => {
this.isLoading = false
})
},
buildBarrios(querySnap) {
querySnap.docs.forEach((docSnap) => {
this.table.data.push({
id: docSnap.id,
...docSnap.data(),
docSnapshot: docSnap
})
});
}
},
computed: {
displayData() {
let data = []
this.table.data.map((barrioBuieldedObj) => {
barrioBuieldedObj.dateAddedFormatted = moment(Number(barrioBuieldedObj.dateAdded)).format("DD/MM/YYYY")
barrioBuieldedObj.totalStreets ? true : barrioBuieldedObj.totalStreets = 0;
data.push(barrioBuieldedObj)
});
return data;
}
},
mounted() {
// obtener primer paginacion y total de documentos.
this.isLoading = true
getTotalDocumentBarrios()
.then((docSnap) => {
if(!docSnap.exists || !docSnap.data().totalBarrios) {
// mostrar mensaje que no hay barrios...
console.log('No hay barrios agregados...')
this.table.total = 0
return;
}
const totalBarrios = docSnap.data().totalBarrios
this.table.total = totalBarrios
if(totalBarrios <= BARRIOS_PER_PAGE) {
return fetchBarriosWithLimit(totalBarrios)
} else {
return fetchBarriosWithLimit(BARRIOS_PER_PAGE)
}
})
.then((querySnap) => {
if(querySnap.empty) {
// ningun doc. mostrar mensaje q no hay barrios agregados...
return;
}
this.buildBarrios(querySnap)
})
.catch((err) => {
console.error(err)
})
.finally(() => {
this.isLoading = false
})
}
}
</script>
<style lang="scss" scoped>
</style>
The nextBarrios function:
function nextBarrios(limitNum, startAtNum) {
const query = db.collection('Barrios')
.orderBy('dateAdded')
.startAfter(startAtNum)
.limit(limitNum)
return query.get()
}
db is the result object of calling firebase.firestore(). Can I tell a query to start at a certain number where number is the index position of the document within a collection? If not, How could I approach this problem?
Thank you!
Firestore doesn't support offset or index based pagination. It's also not possible to tell how many documents the entire query would return without actually reading them all. So, unfortunately, what you're trying to do isn't possible with Firestore.
It seems also that you're misunderstanding how the pagination APIs actually work. startAfter doesn't take an index - it takes either a DocumentSnapshot of the last document in the prior page, or a value of the ordered field that you used to sort the query, again, the last value you saw in the prior page. You are basically going to use the API to tell it where to start in the next page of results based on what you found in the last page. That's what the documentation means when it says you are working with a "query cursor".

props in functions not calling the function

I'm trying to fix a problem from the code and don't understand why is not working.
Function:
export const monthlyKpiActions_disp = (threeMonthsBefore, currentDate) => {
console.log('kpppppppppppppppi')
return monthlyKpiActions.fetch({
filter: {
objectId,
interval: threeMonthsBefore + '/' + currentDate,
names: [
'ecostats_fuelusagetotal',
'ecostats_fuelrefmileage',
'ecostats_co2emission',
'tripstats_mileage',
'tripstats_drivingtime',
'optidrive_indicator_8'
].join(',')
},
forceUpdate: true,
resetState: false
})
}
redux
function mapDispatchToProps(dispatch) {
return {
monthlyKpiActions_func: (threeMonthsBefore, currentDate) => dispatch(monthlyKpiActions_disp(threeMonthsBefore, currentDate)),
}
}
calling the function
const currentDate = moment.utc().add(1, 'months').format(dateFormat)
const threeMonthsBefore = moment.utc().subtract(3, 'months').format(dateFormat)
{ () => this.props.monthlyKpiActions_func(threeMonthsBefore, currentDate) }
The problem is that never enters the function, any suggestions?
That's because you never call the action, this line
{ () => this.props.monthlyKpiActions_func(threeMonthsBefore, currentDate) }
Creates a block scope with an anonymous function which internally calls your action, but its never invoked (nor makes any sense in this context).
Just call the action:
this.props.monthlyKpiActions_func(threeMonthsBefore, currentDate)

crawler with ramda.js (functional programming)

I'm trying to crawl movie data from TMDB website. I finished my code with pure javascript, but I want to change the code into functional programming style by using ramda.js.
I attached my code below. I want to get rid of for-loop (if it is possible) and use R.pipe function.
(async () => {
for (let i = 0; i < 1000; i++) {
(() => {
setTimeout(async () => {
let year = startYr + Math.floor(i / 5);
await request.get(path(year, i % 5 + 1), async (err, res, data) => {
const $ = cheerio.load(data);
let list = $('.results_poster_card .poster.card .info .flex a');
_.forEach(list, (element, index) => {
listJSON.push({
MovieID: $(element).attr('id').replace('movie_', ''),
Rank: (i % 5) * 20 + index + 1,
Year: year
});
});
if(i === 1000 - 1) {
await pWriteFile(`${outputPath}/movieList.json`, JSON.stringify(listJSON, null, 2));
}
});
}, 1000 * i);
})(i);
}
})().catch(error => console.log(error));
Steps:
1- Break your code in small functions
2- Stop using async await and use promise.then(otherFunction)
3- When using promise, you could create a sleep function like these: const sleep = (time) => new Promise(resolve => setTimeout(resolve, time));
Ex.:
const process = index => sleep(1000)
.then(() => makeRequest(index))
.then(processData);
R.range(0, 1000)
.reduce(
(prev, actual) => prev.then(() => process(actual),
Promise.resolve()
) // Sequential
.then(printResult);
R.range(0, 1000)
.map(process) // Parallel
.then(printResult);
You can use the Ramda range() function to replace your loop.
https://ramdajs.com/docs/#range
R.range(0, 1000);
That will provide you with a collection of integers (your i) that you can work with (map() or whatever you need).

Integrate the pull to refresh feature in Ionic 3 with Wordpress

I'm working on a Ionic3 app integrated with Wordpress using REST API v2 and I need to include the pull to refresh feature but I don't understand how to do it with my code.
This is my function that retrieves my post
getPostsWordpress(){
if(!(this.posts.length > 0)){
let loading = this.loadingCtrl.create();
loading.present();
this.wordpressService.getRecentPostsWithSort(this.categoryId,this.sort)
.subscribe(data => {
for(let post of data){
post.excerpt.rendered = post.excerpt.rendered.split('<a')[0] + "</p>";
this.posts.push(post);
}
loading.dismiss();
});
}
}
...
doInfinite(infiniteScroll) {
let page = (Math.ceil(this.posts.length/10)) + 1;
console.log("PAGE_"+page)
console.log("this.posts.length_"+this.posts.length)
let loading = true;
this.wordpressService.getRecentPostsWithSort(this.categoryId,this.sort, page)
.subscribe(data => {
for(let post of data){
if(!loading){
infiniteScroll.complete();
}
post.excerpt.rendered = post.excerpt.rendered.split('<a')[0] + "</p>";
this.posts.push(post);
loading = false;
}
}, err => {
this.morePagesAvailable = false;
})
}
doInfinite let me to implement infinite scroll, and all works well!
How is it possibile to integrate pull to refresh from the ionic documentation?
This is a sample from the doc and I don't understand how could I use it in my project.
doRefresh(refresher) {
console.log('Begin async operation', refresher);
setTimeout(() => {
console.log('Async operation has ended');
refresher.complete();
}, 2000);
}
Someone can help me?
Thank you in advance!
add this to ur html
<ion-refresher (ionRefresh)="doRefresh($event)">
<ion-refresher-content
pullingIcon="arrow-dropdown"
pullingText="Pull to refresh"
refreshingSpinner="circles"
refreshingText="Refreshing...">
</ion-refresher-content>
then in ur do refresh
doRefresh(refresher) {
console.log('Begin async operation', refresher);
//ur function e.g getPostWordPress()
setTimeout(() => {
console.log('Async operation has ended');
refresher.complete();
}, 2000);}

How to return to the function level?

I have a function loadMessages, I want it return an Observable.
loadMessages(chatId: string): Observable<Message[]> {
console.log('1');
this.autorun(() => {
const handle = this.subscribe('messages', chatId);
if (handle.ready()) {
console.log('2');
const messages = Messages.find().fetch();
return Observable.of(messages); // here return is not for this function, which is useless
}
});
console.log('3'); // I don't want this line run immediately
// I wish I can return here, but I cannot
}
How can I return to the function level?
Also, right now the order is 1 -> 3 -> 2. Is there any way to run 1 -> 2, and wait there until I get the data?
You can try something like this:
loadMessages(chatId: string): Observable<Message[]> {
console.log('1');
return Observable.create(observer => {
this.autorun(() => {
const handle = this.subscribe('messages', chatId);
if (handle.ready()) {
console.log('2');
const messages = Messages.find().fetch();
observer.next(messages)
}
});
});
}
Very simple example is here http://plnkr.co/edit/GADtB8QCTnNubtRu9SFv?p=preview

Resources