I Can't GroupBy arrays using computed in Vue.js - vue.js

i want help on this. Thank you.
I have an object :
Funding : [
{person_id:'1';
Amount : '100'},
{person_id:'1';
Amount : '200'},
{person_id:'2';
Amount : '150'},
I would like to groupBy Funding by person_id and get the sum of Amount in each group.
I use this code but nt working ..
Groupe(array,key) {
const result = {}
array.forEach(funding => {
if (!result[funding[person_id]]){
result[funding[person_id]] = []
}
result[funding[person_id]].push(item)
})
return result
}

I created two different examples, one a function will return the summed amount of just one of the keys. In the second, it will return the summed amount of all the keys.
Here is a codepen for that https://codepen.io/aquilesb/pen/BvbqMd
const data = [
{
person_id:'1',
amount : '100'},
{
person_id:'2',
amount : '150'
},
{
person_id:'1',
amount : '150'
},
{
person_id:'2',
amount : '70'
}
];
const personID = '1';
// return by a key
const groupByKey = (list, key) => list.reduce((acc, item) => {
if (item.person_id === key) {
return parseInt(item.amount, 10) + acc;
}
return acc;
}, 0);
//return the sum of all keys
const groupAll = list => list.reduce((acc, item) => {
const accAmout = acc[item.person_id] || 0;
return Object.assign({}, acc, {[item.person_id]: accAmout + parseInt(item.amount, 10)});
}, {});
console.log("groupByKey", groupByKey(data, personID));
console.log("groupAll", groupAll(data));

You can use lodash's .groupBy function and .reduce functions to group by Person ID first, and then add the amounts together. Using a computed property in Vue makes this very easy, and you can access the object in your template like its a regular property.
Vue/HTML Template
<div id="app">
<ul v-for="(total,personId) in fundingByPerson">
<li>Persond ID: {{personId}}, Amount : ${{total.toFixed(2)}}</li>
</ul>
</div>
Javascript
// Include lodash via `npm install lodash`
import _ from 'lodash';
new Vue({
el: "#app",
data() {
return {
Funding: [
{person_id:'1', Amount : '130'},
{person_id:'1', Amount : '200'},
{person_id:'2', Amount : '350'},
{person_id:'45', Amount : '150'}
]
}
},
computed: {
// Group by Person, then add amounts together
fundingByPerson: function(){
let byPerson = _.groupBy(this.Funding, 'person_id');
let totals = {};
// Loop over each Group of Amounts, indexed by personId
_.forEach(byPerson, function(amounts, personId){
totals[personId] = _.reduce( byPerson[personId], function(sum, entry){
return sum + parseFloat( entry.Amount );
}, 0);
})
return totals;
} // fundingByPerson
})
Here's a working fiddle: http://jsfiddle.net/mdy59c7e/6/

Related

How to refresh view when vuex store changes?

I get the data from the store like so
computed: {
notes() {
var data = this.$store.getters.getNotes;
var key = this.$store.getters.getTitleFilter;
if (key === "all") return data;
return data.filter((note) => {
var filteredNote = note.category.some(({ name }) => name === key);
if (filteredNote) return filteredNote;
});
},
},
When the note array changes (an item is removed, getNotes should reflect that. In other instances (where the data is returned without filtering) this used to do the trick:
watch: {
notes(newval) {
return newval;
},
},
I there a way to get the filtered array to update?

Duplicate items in list after an API update

I'm learning vuejs and I'm doing a weather app, the goal is to rank cities with an index (humidex). I fetch weather information by API (axios) in order to collect data from several cities. I want to auto update data every x minutes, problem : some of my results are duplicated (the new data don't replace the old one).
I tried to set an unique key (based on latitude and longitude) for each item, it works for several results but not for all.
data () {
return {
items:[],
show: false,
cities: cities,
newCity:''
}
},
components: {
Item
},
computed: {
sortHumidex() {
return this.items.slice().sort((a,b) => {
return this.getHumidex(b) - this.getHumidex(a) || b.current.temp_c - a.current.temp_c
})
}
},
methods: {
addCity() {
if (this.newCity.trim().length == 0) {
return
}
this.cities.push(this.newCity)
this.newCity = ''
},
getHumidex: (el) => {
const e = 6.112 * Math.pow(10,(7.5*el.current.temp_c/(237.7+el.current.temp_c)))
*(el.current.humidity/100)
return Math.round(el.current.temp_c + 5/9 * (e-10))
},
indexGeo: (e) => {
const lat = Math.round(Math.abs(e.location.lat))
const lon = Math.round(Math.abs(e.location.lon))
return lat.toString() + lon.toString()
},
getApi: function () {
const promises = [];
this.cities.forEach(function(element){
const myUrl = apiUrl+element;
promises.push(axios.get(myUrl))
});
let self = this;
axios
.all(promises)
.then(axios.spread((...responses) => {
responses.forEach(res => self.items.push(res.data))
}))
.catch(error => console.log(error));
}
},
created() {
this.getApi()
this.show = true
}
}
The render when I update API :
By pushing to the existing array of items, you have to deal with the possibility of duplicates. This can be eliminated simply by replacing items every time the API call is made.
Replace:
responses.forEach(res => self.items.push(res.data))
with:
self.items = responses.map(res => res.data)

how to add a condition like a greater than equal to in filter search in vue js

Hi every one i am going to build a real-estate application
i want to add a condition in Bedrooms filter function like a "greater than equal "
Eg:- if i select 2 on Bedroom list i want to filter greater than equal 2 Bedrooms properties
How can i do this
export default {
data() {
return {
blogs: [],
minbed: this.$route.params.bed,
}
},
created() {
this.$http.get("https://test.json").then(function(data) {
console.log(data);
this.blogs = data.body;
});
},
computed: {
filteredList() {
const { blogs, search, UnitType } = this;
return this.blogs
.filter(blog => blog.Bedrooms.includes(this.minbed))
}
}
<select
v-model="minbed"
id="formInput202"
class="form-control"
value="MaxBedrooms"
>
<option>Max.Bedrooms</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>ST</option>
</select>
includes method is not working in this case. Only accepts string as the param (Ref-Link1).
The inline callback function will sort out this case,
Check the below code.
filteredList() {
const { blogs, search, UnitType } = this;
var MaxBedroomsVal = this.minbed;
return this.blogs.filter( function (blog) {
return blog.Bedrooms >= MaxBedroomsVal;
})
}
Ref: Link2

Vue.js | Filters is not return

I have a problem.
I am posting a category id with http post. status is returning a data that is true. I want to return with the value count variable from the back. But count does not go back. Return in function does not work. the value in the function does not return from the outside.
category-index -> View
<td>{{category.id | count}}</td>
Controller File
/**
* #Access(admin=true)
* #Route(methods="POST")
* #Request({"id": "integer"}, csrf=true)
*/
public function countAction($id){
return ['status' => 'yes'];
}
Vue File
filters: {
count: function(data){
var count = '';
this.$http.post('/admin/api/dpnblog/category/count' , {id:data} , function(success){
count = success.status;
}).catch(function(error){
console.log('error')
})
return count;
}
}
But not working :(
Thank you guys.
Note: Since you're using <td> it implies that you have a whole table of these; you might want to consider getting them all at once to reduce the amount of back-end calls.
Filters are meant for simple in-place string modifications like formatting etc.
Consider using a method to fetch this instead.
template
<td>{{ categoryCount }}</td>
script
data() {
return {
categoryCount: ''
}
},
created() {
this.categoryCount = this.fetchCategoryCount()
},
methods: {
async fetchCategoryCount() {
try {
const response = await this.$http.post('/admin/api/dpnblog/category/count', {id: this.category.id})
return response.status;
} catch(error) {
console.error('error')
}
}
}
view
<td>{{count}}</td>
vue
data() {
return {
count: '',
}
},
mounted() {
// or in any other Controller, and set your id this function
this.countFunc()
},
methods: {
countFunc: function(data) {
this.$http
.post('/admin/api/dpnblog/category/count', { id: data }, function(
success,
) {
// update view
this.count = success.status
})
.catch(function(error) {
console.log('error')
})
},
},

Vuejs2 component not updating as parent data changes

I am trying to make a simple product catalogue using vuejs2.
All my data is stored in an object array, I then have a subset of this data which is what the product catalogue uses to display each product.The subset is used for pagination.
When a user switches pages it clears and pushes the next set of data into the array.
This automatically makes the product component display the new data.
I have issues with the following, each product has multiple colours which are stored as a comma delimited string eg (white, blue, red)
I am trying to make that information appear as a drop down list of options beside each product.
This works until I switch to the next page of data, all other details update except the colour drop downs, which only reflect the previous set of data.
My product list is stored in an object array like:
var obj = {
productID: productID,
product: title,
gender: gender,
colour: colour,
cost: cost,
size: size,
description: description
}
productArray.push(obj);
I then have several components that display this array of data:
Vue.component('product-list', {
template: '<ul id="productList">'+
'<product :productID="product.productID" v-for="product in products">'+
'<h4>Colour</h4><colourSelect :colours="product.colour" :productID="product.productID"></colourSelect>' +
'<h4>Gender</h4><span class="genderSpan"><p v-bind:id="getID(product.productID)">{{product.gender}}</p></span>' +
'</product></ul>',
data: function() {
return {
products:
paginatedArray
};
},
Vue.component('colourSelect', {
props: ['productID', 'colours'],
template: '<select v-bind:id="getID()" class="form-control input-xs"><colourOption v-for="colourItem in colourArray"></colourOption></select>',
data: function () { //split string based into array
var newArray = [];
var optionsArray = this.colours.split(',');
for (i = 0; i < optionsArray.length; i++) {
var obj = {
colour: optionsArray[i]
}
newArray.push(obj)
}
return {
colourArray: newArray
};
},
methods: {
getID: function (test) {
return 'colourSelect' + this.productID;
}
}
});
Vue.component('colourOption', {
props:['options'],
template: '<option><slot></slot></option>'
});
Within the app section of vuejs I have the following methods that do the pagination:
buildPages: function () {
for (i = 1; i < this.listLength() /this.totalPage ; i++) {
this.pages.push(i);
}
var page = this.currentPage * this.totalPage;
for (i = page; i < page + this.totalPage ; i++) {
paginatedArray.push(productArray[i]);
}
},
listLength: function () {
var listTotal = productArray.length;
return listTotal
},
changePage: function (number) {
this.currentPage = number
var page = this.currentPage * this.totalPage;
//paginatedArray = [];
var count = 0;
for (i = page; i < page + this.totalPage ; i++) {
if (typeof productArray[i] !== 'undefined') {
paginatedArray.splice(count, 1, productArray[i])
}
count++
}
},
productArray is the main array storing data, paginatedArray is the subset of data that the product component works off.
The issue appears to be within the colourSelect component, within its "data" section it splits the colour data and returns it as an colourOption component into the select, but won't update when the paginatedArray changes.
The colourSelect component does however appear to actually get passed the correct data, as getID method updates correctly. Its just the data section which is not being re-rerun.
This is my first vuejs site, anyone have any ideas around this?
Thanks
You should make the colourArray as a computed property, as the data block of component gets executed only once and later change of props will not update colourArray .
Vue.component('colourSelect', {
props: ['productID', 'colours'],
template: '<select v-bind:id="getID()" class="form-control input-xs"><colourOption v-for="colourItem in colourArray"></colourOption></select>',
computed:{
colourArray: function () { //split string based into array
var newArray = [];
var optionsArray = this.colours.split(',');
for (i = 0; i < optionsArray.length; i++) {
var obj = {
colour: optionsArray[i]
}
newArray.push(obj)
}
return newArray
}
},
methods: {
getID: function (test) {
return 'colourSelect' + this.productID;
}
}
});