How to proccessing Vuex array in Vue.js - vue.js

I'm a new web developer. I need help getting all of the titles from all of the objects in an array. I get an array of products from an axios request. In the next step I need to process this array in a Vue component and record a single value to data. Next I need to display this data value in a multiselect's options.
Here is the axios code:
async getOrders(ctx, data)
{
return new Promise((resolve, reject) => {
axios({
url: '/orders',
data: data,
method: 'GET'
})
.then((resp) => {
ctx.commit('setOrders', resp.data.orders)
ctx.commit('setUsers', resp.data.users)
ctx.commit('setProducts', resp.data.products)
ctx.commit('updatePagination', resp.data.pagination)
resolve(resp)
})
.catch((error) => {
console.log(error)
reject(error)
})
})
},
This is my array of products recorded in Vuex store
0: {id: 6, category_id: 2, title: "Test", brand: "Тест", serial_number: "2165412315864",…}
1: {id: 7, category_id: 3, title: "Климат", brand: "Климат", serial_number: "2165412315864",…}
2: {id: 8, category_id: 5, title: "New", brand: "New", serial_number: "2165412315864",…}
This is my code to proccessing this array
computed:{
...mapGetters('order', ['users', 'products', 'orders']),
},
methods:{
getProducts(products)
{
const arr = products.map(c => c.title)
console.log('titles: ', arr); //Debug
this.options = arr
}
},
And here is the code for the multiselect
<multiselect v-model="formData.product" :options="options" :value="values" :multiple="true" :close-on-select="false" :clear-on-select="false" :preserve-search="true" placeholder="Pick some" label="name" track-by="name" :preselect-first="true">
<template slot="selection" slot-scope="{ values, search, isOpen }"><span class="multiselect__single" v-if="values.length && !isOpen">{{ values.length }} options selected</span></template>
</multiselect>
mounted() {
this.getProducts();
},

It looks like you're not sending your args by calling just this.getProducts(). You don't need to, just write this. in front of the computed value inside the method.
methods: {
getProducts () {
const arr = this.products.map(c => c.title)
this.options = arr
}
}

Related

Using a method as data inside the app parent

So I'm still learning Vue.js and I got my list working well and I have one question. I will explain what I'm trying to do below as best as possible and I wanted to see if someone could help me with my issue.
So here is the component that I have on the HTML side:
<favorites-edit-component
v-for="(favorite, index) in favorites"
v-bind:index="index"
v-bind:name="favorite.name"
v-bind:key="favorite.id"
v-on:remove="favorites.splice(index, 1)"
></favorites-edit-component>
Here is the vue.js portion that I have:
Vue.component('favorites-edit-component', {
template: `
<div class="column is-half">
<button class="button is-fullwidth is-danger is-outlined mb-0">
<span>{{ name }}</span>
<span class="icon is-small favorite-delete" v-on:click="$emit('remove')">
<i class="fas fa-times"></i>
</span>
</button>
</div>
`,
props: ['name'],
});
new Vue({
el: '#favorites-modal-edit',
data: {
new_favorite_input: '',
favorites: [
{
id: 1,
name: 'Horse',
url: 'www.example.com',
},
{
id: 2,
name: 'Sheep',
url: 'www.example2.com',
},
{
id: 3,
name: 'Octopus',
url: 'www.example2.com',
},
{
id: 4,
name: 'Deer',
url: 'www.example2.com',
},
{
id: 5,
name: 'Hamster',
url: 'www.example2.com',
},
],
next_favorite_id: 6,
},
methods: {
add_new_favorite: function() {
this.favorites.push({
id: this.next_favorite_id++,
name: this.new_favorite_input
})
this.new_favorite_input = ''
},
get_favorite_menu_items: function() {
wp.api.loadPromise.done(function () {
const menus = wp.api.collections.Posts.extend({
url: wpApiSettings.root + 'menus/v1/locations/favorites_launcher',
})
const Menus = new menus();
Menus.fetch().then(posts => {
console.log(posts.items);
return posts.items;
});
})
}
}
});
So as you can see, I have the data: { favorites: [{}] } called inside the vue app and I get this console.log:
Now I built a method called get_favorite_menu_item and this is the return posts.items output inside console.log:
Problem: I don't want to have a manual array of items, I want to be able to pull in the method output and structure that - How would I take a approach on pulling the items?
Could I call something like this:
favorites: this.get_favorite_menu_items?
Here is a JFiddle with all the items: https://jsfiddle.net/5opygkxw/
All help will be appreciated on how to pull in the data.
First I will init favorites to empty array.
then on get_favorite_menu_items() after I will init data from post.item to favorites.
on created() hooks i will call get_favorite_menu_items() to fetch the data when the view is created.
new Vue({
el: '#favorites-modal-edit',
data: {
new_favorite_input: '',
favorites: [],
next_favorite_id: 6,
},
methods: {
add_new_favorite: function() {
this.favorites.push({
id: this.next_favorite_id++,
name: this.new_favorite_input
})
this.new_favorite_input = ''
},
get_favorite_menu_items: function() {
wp.api.loadPromise.done(function () {
const menus = wp.api.collections.Posts.extend({
url: wpApiSettings.root + 'menus/v1/locations/favorites_launcher',
})
const Menus = new menus();
Menus.fetch().then(posts => {
console.log(posts.items);
// need map key also
this.favorites = posts.items;
});
})
}
},
created () {
// fetch the data when the view is created
this.get_favorite_menu_items();
},
});

Change radio button value to 'checked' (Vue.js, Vuetify)

I'm a little new in Vue.js and currently I am having a problem with radios.
I have a form with different inputs. When I'm submiting the form I create a JSON file with all the form answers:
Instead of this output I want the value of the selected radio to be 'Checked'.
{
"pos_r_1":"Radio 1"
"pos_r_2":"",
"pos_r_3":"",
"pos_r_4":"",
"pos_t_5":"this a test",
}
LIKE THAT:
{
"pos_r_1":"Checked"
"pos_r_2":"",
"pos_r_3":"",
"pos_r_4":"",
"pos_t_5":"this a test",
}
How can I change the value of the radio to 'checked'?
HTML
<v-form class="text-left" name="form" id="form">
<v-radio-group
v-model="checked"
hide-details="auto"
row
>
<v-radio
v-for="radio in group"
:key="radio.id"
:id="radio.id"
:name="radio.id"
:label="radio.text"
:value="radio.text"
/>
</v-radio-group>
<v-text-field
id="pos_t_5"
name="pos_t_5"
label="Text"
v-model="textfield"
/>
<v-btn
class="p-2"
color="primary"
elevation="11"
#click="onSubmit"
>click me</v-btn>
</v-form>
Script
export default Vue.extend({
name: 'Test',
data: function () {
return {
checked: '',
textfield: '',
group: [
{id: 'pos_r_1', text: 'Radio 1'},
{id: 'pos_r_2', text: 'Radio 2'},
{id: 'pos_r_3', text: 'Radio 3'},
{id: 'pos_r_4', text: 'Radio 4'},
],
}
},
onSubmit() {
this.loading = true
const form = document.querySelector('form');
const data = new FormData(form);
let currentObj = this;
let url = '/report/form/store';
axios({
url,
method: 'post',
data,
}) .then(function (response) {
currentObj.output = response.data;
}) .catch( (error) => {
if (error.response && error.response.status === 422){
this.errors = error.response.data.errors;
}
});
}
}
})
I've tried to change the value of the Radios to 'checked' but that doesn't work because then when I click one radio all getting checked.
This is only an example of the form. The form will be big with more that 20 different questions.
Update
This is not the way to do it. I have to manipulate the value of the radios buttons inside a Form Model, where I will save all the form answers. Then I can change the value of the radio to 'checked' easier.
So, radio buttons works as it should to https://developer.mozilla.org/ru/docs/Web/HTML/Element/Input/radio.
If you need to send a request like pos_r_3: Radio 3, you have to do some transformation on it. I'd suggest the code like:
export default Vue.extend({
name: 'Test',
data: function () {
return {
checked: '',
group: [
{id: 'pos_r_1', text: 'Radio 1'},
{id: 'pos_r_2', text: 'Radio 2'},
{id: 'pos_r_3', text: 'Radio 3'},
{id: 'pos_r_4', text: 'Radio 4'},
],
}
},
onSubmit() {
this.loading = true
const form = document.querySelector('form');
const data = new FormData(form);
for (let i = 0; i < this.group.length; i++){
const currentGroup = this.group[i];
data.set(currentGroup.id, currentGroup.text === this.checked ? 'Checked' : '');
}
let currentObj = this;
let url = '/report/form/store';
axios({
url,
method: 'post',
data,
}) .then(function (response) {
currentObj.output = response.data;
}) .catch( (error) => {
if (error.response && error.response.status === 422){
this.errors = error.response.data.errors;
}
});
}
}

How to put array in multiple select in Vue.JS

Just few hours im tryin to put array of object in multiple select
I got this array from axios request and next im need display whole array with all title objects in this array
If someone have info how to solv this probled it will be nice and im gratefull
this is my array
products: [{id: 6, category_id: 2, title: "Тест", brand: "Тест", serial_number: "2165412315864",…},…]
0: {id: 6, category_id: 2, title: "Test", brand: "Test", serial_number: "2165412315864",…}
1: {id: 7, category_id: 3, title: "Test2", brand: "Test2", serial_number: "2165412315864",…}
2: {id: 8, category_id: 5, title: "New", brand: "New", serial_number: "2165412315864",…}
this is my code from Vuex Store
async getOrders(ctx, data)
{
return new Promise((resolve, reject) => {
axios({
url: '/orders',
data: data,
method: 'GET'
})
.then((resp) => {
ctx.commit('setOrders', resp.data.orders)
ctx.commit('setUsers', resp.data.users)
ctx.commit('setProducts', resp.data.products)
ctx.commit('updatePagination', resp.data.pagination)
resolve(resp)
})
.catch((error) => {
console.log(error)
reject(error)
})
})
},
ASYNC/AWAIT FIX:
async getOrders(ctx, data) {
try {
const { data } = await axios({
url: '/orders',
data: data,
method: 'GET'
})
ctx.commit('setOrders', data.orders)
ctx.commit('setUsers', data.users)
ctx.commit('setProducts', data.products)
ctx.commit('updatePagination', data.pagination)
} catch (e) {
console.error(e)
}
}
IN COMPONENT:
<select v-model="product">
<option v-for="product in products" :key="product.code" :value="product">
{{ product.title }}
</option>
</select>
When you do this way, the whole selected product would be saved in the product data property.

Vue - Pass params from select inside an array.push

When passing params from a select, the usual syntax would be something like this.
<v-select
v-model="item_id"
items="items"
item-text="item_name"
item-value="id"
#change='itemDescription()'
/>
export default {
data: ()=> ({
item_id: '',
items: [],
itemDescription '',
}),
method: {
itemDescription() {
axios.get('/api/item', {
params: { id: this.item_id }
})
.then(response => this.itemDescription = response.data )
}
}
}
Now the problem comes when the select is inside an array.push. I can't simply pass the value to this.item_id since the structure would be object[0][1]. Here is an example syntax below.
<v-btn #click="addItem()">Add</v-btn>
<template v-for="item in items" :key="item.id>
<v-select
v-model="item.item_id"
items="item_all"
item-text="item_name"
item-value="id"
#change='itemDescription()'
/>
</template>
export default {
data: ()=> ({
items: [],
item_all: '',
}),
method: {
addItem() {
this.items.push({
item_id: '',
description: '',
}),
itemDescription() {
axios.get('/api/item', {
params: { id: this.items.item_id } // <-- this doesn't work
})
.then(response => this.items.description = response.data )
}
}
}
How do I pass id of each row every time I select each one of them?
I made it work now. I just used index, this was my savior.
Please see code below for those interested
<v-btn #click="addItem()">Add</v-btn>
<template v-for="(item, index) in items" :key="item.id>
<v-select
v-model="item.item_id"
items="item_all"
item-text="item_name"
item-value="id"
#change='itemDescription(index)'
/>
</template>
export default {
data: ()=> ({
items: [],
item_all: '',
itemDescription '',
}),
method: {
addItem() {
this.items.push({
item_id: '',
description: '',
}),
itemDescription(index) {
axios.get('/api/item', {
params: { id: this.items[index].item_id } // <-- this doesn't work
})
.then(response => this.items[index].description = response.data )
}
}
}
The 'this' in itemDescription method isn't same as 'this' in 'method:'.
so it will not work.
use another variable to keep this, and use it in itemDescription.
method: {
var that = this;
addItem() {
this.items.push({
item_id: '',
description: '',
}),
itemDescription() {
axios.get('/api/item', {
params: { id: that.items.item_id } // 'this' ain't work
})
.then(response => this.items.description = response.data )
}

VueJs: Form handling with Vuex and inputs generated with an API

Here's an example of a component:
<script>
export default {
name: 'my-form',
computed: {
myModules() {
return this.$store.state.myModules;
}
}
</script>
<template>
<form>
<p v-for="module in myModules">
<input type="checkbox" :value="module.id" />
<label>module.name</label>
</p>
<button type="submit">Submit</button>
</form>
</template>
The associated store:
state: {
myModules: []
},
mutations: {
setModules(state, modules) {
state.myModules = modules;
}
},
actions: {
getModules({commit}) {
return axios.get('modules')
.then((response) => {
commit('setModules', response.data.modules);
});
}
}
And finally, an example of return of the API "getModules":
modules : [
{
id: 1,
name: 'Module 1',
isActive: false
},
{
id: 2,
name: 'Module 2',
isActive: false
},
{
id: 3,
name: 'Module 3',
isActive: false
}
]
My question: what's the best way to change the "isActive" property of each module to "true" when I check the checkbox corresponding to the associated module, directly in the store?
I know that Vuex's documentation recommends to use "Two-way Computed Property" to manage the forms, but here I don't know the number of modules that the API can potentially return, and I don't know their name.
Thank you in advance!
This is a little bit wicked approach, but it works. You can create an accessor object for every item you access in a loop:
const store = new Vuex.Store({
mutations: {
setActive (state, {index, value}) {
state.modules[index].isActive = value
}
},
state: {
modules : [
{
id: 1,
name: 'Module 1',
isActive: false
},
{
id: 2,
name: 'Module 2',
isActive: false
},
{
id: 3,
name: 'Module 3',
isActive: false
}
]
}
});
const app = new Vue({
el: '#target',
store,
methods: {
model (id) {
const store = this.$store;
// here i return an object with value property that is bound to
// specific module and - thanks to Vue - retains reactivity
return Object.defineProperty({}, 'value', {
get () {
return store.state.modules[id].isActive
},
set (value) {
store.commit('setActive', {index: id, value});
}
});
}
}
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.min.js"></script>
<div id="target">
<div v-for="(item, id) in $store.state.modules">
Module #{{ item.id }} state: {{ item.isActive }}
</div>
<div v-for="(item, id) in $store.state.modules">
<label>
Module #{{ item.id }}
<input type="checkbox" v-model="model(id).value"/>
</label>
</div>
</div>
This is still quite a messy approach, but at least you don't have to commit mutations directly in template. With a little help of Vue.set() you can use this approach even to overcome standard reactivity caveats.
I have an alternative solution for you. You could make a child component for the checkboxes to clean up the code a bit.
UPD: I just realised that everything that I and #etki proposed is an overkill. I left the old version of my code below in case you still want to take a look. Here is a new one:
const modules = [{
id: 1,
name: 'Module 1',
isActive: true,
},
{
id: 2,
name: 'Module 2',
isActive: false,
},
{
id: 3,
name: 'Module 3',
isActive: false,
},
];
const store = new Vuex.Store({
state: {
myModules: [],
},
mutations: {
SET_MODULES(state, modules) {
state.myModules = modules;
},
TOGGLE_MODULE(state, id) {
state.myModules.some((el) => {
if (el.id === id) {
el.isActive = !el.isActive;
return true;
}
})
}
},
actions: {
getModules({
commit
}) {
return new Promise((fulfill) => {
setTimeout(() => {
commit('SET_MODULES', modules);
fulfill(modules);
}, 500)
});
}
}
});
const app = new Vue({
el: "#app",
store,
data: {},
methods: {
toggle(id) {
console.log(id);
this.$store.commit('TOGGLE_MODULE', id);
}
},
computed: {
myModules() {
return this.$store.state.myModules;
},
output() {
return JSON.stringify(this.myModules, null, 2);
},
},
mounted() {
this.$store.dispatch('getModules').then(() => console.log(this.myModules));
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<script src="https://unpkg.com/vue"></script>
<div id="app">
<form>
<div v-for="data in myModules">
<label :for="data.id">{{ data.name }}: {{data.isActive}}</label>
<input type="checkbox" :id="data.id" :name="'checkbox-' + data.id" :checked="data.isActive" #change="toggle(data.id)">
</div>
</form>
<h3>Vuex state:</h3>
<pre v-text="output"></pre>
</div>
As you can see above you could just call a function on input change and pass an id as a parameter to a method that fires vuex action.
The old version of my code.
A new one on jsfiddle