Update v-for When Data Is Added To Array - VueJS - vue.js

I'm kinda new to VueJS so I was hoping to get some help. I'm currently returning an array of json objects from a PHP file.
Example:
<?php
/*
Returns an array similar to this:
[
{name: 'foo'},
{name: 'bar'},
{name: 'banana'}
]
*/
echo json_encode(array_values($array));
?>
And I'm appending this array of objects to an already existing array of objects in Vue:
axios.post('http://localhost/get_array.php').then(response => {
// Append returned array to already existing array
for (var i = 0; i <= response.data.length - 1; i++) {
this.existingArray.push(response.data[i])
}
}).catch(e => {
console.log("Error")
})
Right now I'm appending the data with a for loop but I was wondering if VueJS has an in-built function that does this automatically without having to use the for loop?

You can use concat which returns a new concatenated array:
axios.post('http://localhost/get_array.php')
.then(response => {
this.existingArray = this.existingArray.concat(response.data)
})
.catch(e => {
console.log("Error")
})
Updating existingArray with the result of calling concat with the response data should trigger the update.

Related

How can I access to each element inside of a grid element with Cypress?

I have a Grid component which includes 24 divs and inside of each div I need to take the value.
This value actually arrives in <p>, so which is the best way to do this?
Below is the app image. I would appreciate an example.
You could probably do something like storing the data in an object or array outside of the Cypress chain. Without a code example, here's my best guess.
cy.get('grid').within(() => { // cy.within() searches only within yielded element
const data = {}; // create data object
cy.get('div').each(($div, index) => { // cy.each() allows us to iterate through yielded elements
data[index] = $div.text() // or possibly some other JQuery command to get the value
// additionally, could go without the index at all and make `data` an array.
}).then(() => {
// whatever needs to be done with `data`, wrapped in `then` to make sure data is populated correctly.
});
});
You can add use each for this to loop through the elements and then do further operations:
cy.get('.chakra-stack')
.find('p')
.each(($ele) => {
cy.log($ele.text().trim()) //Logs all the texts one by one
})
Just add the p selector to your cy.get() command
cy.get('div.chakra-stack p') // access <p> within <div>
.each($el => {
cy.wrap($el).invoke('text')
.then(text => {
...
})
})
To get the value before the text
cy.get('div.chakra-stack p') // access <p> within <div>
.each($el => {
cy.wrap($el)
.prev() // element with value
.invoke('text')
.then(value => {
...
})
})
Accessing values by text label like this
const values = {}
cy.get('div.chakra-stack p')
.each($el => {
const frase = $el.text()
cy.wrap($el).prev().invoke('text')
.then(value => values[frase] = +value)
})
.then(() => {
// values = {'shield': 1, 'session': 2, ...}
})

Vuex passing different arrays

Making a filter:
Mutations
export default {
state: {
filteredBrands: []
},
mutations: {
showFilteredList(state, payload) {
state.filteredBrands.push(payload);
}
}
};
Methods
loadProducts(item) {
axios.get('/api', {
params: {
per_page: 20,
filter_machinery_brands: [ item ]
}
})
.then((response) => {
this.$store.commit(
'showFilteredList',
response.data
);
});
},
item this is an input with a checkbox, when clicked, a request is made to the server for this category
For some reason, the push does not work, why?
And I would like there to be a check, if the array is the same, then delete, otherwise add. Is it possible?
If you can se an array comes in as payload. Then you are trying to push an array into an array. Which cant be done in either js or ts.
You can try set the value:
state.filteredBrands = payload;
otherwise you would have to do something like this:
state.filteredBrands.push(payload[0]);
If you wanna control for existing items in array, and assuming your are not always setting value, but pushing new values into your array. You can do something like this:
if (state.filteredBrands.indexOf(payload[0]) === -1) {
// Not in array
state.filteredBrands.push(payload[0])
} else {
// is allready in array
state.filteredBrands.forEach((item, index) => {
if (item === payload[0]) {
state.filteredBrands.splice(index, 1)
}
})
}
EDIT:
My assumption was right.
Your payload is an array
Your state is an array
-------> You are trying to push payload(array) into state(array) - which cant be done i js - This solution would after my suggestion be more clean:
payload.forEach((value, index) => { // Looping payload
if (state.filteredBrands.indexOf(value) === -1) {
state.filteredBrands.push(value) // push if value not allready in array
} else {
state.filteredBrands.splice(index, 1) // if value is in array -> remove
}
})
Yes, you can push an array into an array.
I guess the problem here is your vuex config.
Vuex state is a function, so it needs to be:
state () {
return {
filteredBrands: []
}
}
And if you are using Nuxt:
export const state = () => ({
filteredBrands: []
})

dynamically add new fields to b-table [ Vue.js ]

I am trying to create a table using bootstrap table with fields dynamically added. The fields that will be added will be taken from my api (see code below).
vue.js (jade) - The 2nd template will be the one to render the dynamically added fields but the problem is I can't access the row.item.members because I am not in the row scope. If there is a way to access the row data in the template tag it would be great but I already spent a day and found no luck
b-table(small v-bind:items="plans" v-bind:fields="fields" fixed responsive)
template(slot='bg_action', slot-scope='row')
nuxt-link(:to="'/supply_and_demand/master/'+selected+'/'+row.item.date")
b-button.mr-1(size='sm', variant="primary")
| {{ row.item.date }}
template(v-for="member_info in row.item.members" :slot="id_+ 'member_info.id'" )
| {{ member_info.name }}
my api call (which adds new fields to the table and get the data)
async fetchData(){
let params = {
"q[balancing_group_id_eq]": this.selected
}
this.$restApi.index('bg_members', {params})
.then( (result)=>{
this.fields = [
{ key: 'date', label: '' },
{ key: 'bg_action', label: 'BG' }
]
for(let i = 1; i <= result.length; i++){
this.fields.push({ key: 'id_' + result[i-1].company.id, label: result[i-1].company.name })
}
})
params = {
"q[balancing_group_id_eq]": this.selected,
"q[date_gteq]": this.from,
"q[date_lteq]": this.to
}
this.$axios.$get('/v1/occto/plans', { params })
.then( (result)=>{
console.log("plans")
console.log(this.plans)
this.plans = result
})
}
tldr:I want to access the row data inside the template tag so I can dynamically set the slot which will result to data being displayed properly.

How To Access All Indexes In Nested Array (Vue-chartjs)

so I am trying to display data on my doughnut chart and I am having issues accessing my data from a nested array. When I use the following it just gives me the selected index of the nested array.
So I am wondering is there something else I need to do the computed data or if there is something I am doing wrong.
here is the computed property
countEngagementsByStatus () {
const selectedWorkflow = this.allWorkflows.filter(workflow => workflow.id === this.workflowKey)
const res = selectedWorkflow.map(({statuses, id}) => ({
workflow_id: id,
statuses: statuses.reduce((acc, cur) => {
const count = this.allEngagements.filter(({workflow_id, status}) => workflow_id === id && status === cur.status).length;
acc.push(count);
return acc;
}, [])
}))
return res
},
And on my doughnut chart I am accessing the data. *note removed styling data to clean up the question
datasetsfull() {
return {
labels: this.mapStatuses[0].statuses,
datasets: [
{
label: 'Data One',
data: [
//this is the line I have issues with
this.countEngagementsByStatus[0].statuses[0]
]
}
]
}
},
here is an image of what I am getting
Now If I do this
data: [
this.countEngagementsByStatus[0]
]
I get this as a result however it cannot access the array of numbers shown
So my question is, am I doing something wrong with computed property or am I accessing the data incorrectly or both? Lol
Here is a Js Fiddle To give an idea
So my issue was I was wrapping the data in an array
data: [
this.countEngagementsByStatus[0].statuses
]
I changed it to this
data: this.countEngagementsByStatus[0].statuses

Iterating with v-for on dynamic item

I'm trying to iterate through a db object I fetch during created(), I get the values in a console.log but the v-for template part remains empty. My sub-question is : is this good practice ? I'm quite new to Vue and my searches on this issue make me think it's a lifecycle issue.
Thanks for the help.
TEMPLATE PART :
.content(v-for="(content, key, index) in contents")
h3 {{key}}
.line
| {{getValue(content)}} // this is blank
METHODS PART:
getValue(value) {
PagesService.fetchDataWrap({
id: value
}).then((response) => {
const test = response.data.values[0].value
console.log(test) //this is working and gives the right value
return test
})
},
getPage() {
PagesService.fetchPage({
id: this.$route.params.page
}).then((response) => {
this.name = response.data.result.name
this.langs = response.data.result.langs
this.project = response.data.result.parent
this.contents = response.data.result.values
})
this.getProject()
}
console.log(this.contents) result :
{__ob__: Observer}
footer: "5a29943b719236225dce6191"
header: "5a29a9f080568b2484b31ee1"
which is the values I want to send when v-for iterates on contents so the getValue can process it to fetch corresponding values
I wouldn't recommend attempting to output the value of an asynchronous method. It's highly unlikely that it will work correctly.
Instead, populate your contents array / object fully during the created hook. For example, this can replace the contents hash value with whatever comes back from fetchDataWrap...
getPage () {
PagesService.fetchPage({
id: this.$route.params.page
}).then(response => {
this.name = response.data.result.name
this.langs = response.data.result.langs
this.project = response.data.result.parent
let contents = response.data.result.values
Promise.all(Object.keys(contents).map(key => {
// map each key to a "fetchDataWrap" promise
return PageService.fetchDataWrap({
id: contents[key]
}).then(res => {
// replace the hash with the resolved value
contents[key] = res.data.values[0].value
})
}).then(() => {
// all done, assign the data property
this.contents = contents
})
})
}
Then you can trust that the content has been loaded for rendering
.content(v-for="(content, key, index) in contents")
h3 {{key}}
.line
| {{content}}