I have a parent component called Stepper which contains this child component called ShortSummary. I am trying to pass a prop from Stepper to ShortSummary by clicking on a radiobutton. but it doesn't work! Here's what I have done. This is Stepper:
<v-radio-group row v-model="voltage" >
<v-radio
v-for="n in radioNames"
:key="n"
:label="n"
:value="n"></v-radio>
</v-radio-group>
<app-short-summary :voltage="voltage" ></app-short-summary>
<script>
import ShortSummary from "./ShortSummary";
data() {
return {
voltage:'',
radioNames:
['24V to 36V',
'48V to 72V',
'96V to 110V']
},
components:{
appShortSummary: ShortSummry
}
}
</script>
and this is ShortSummary:
<v-list-tile
:key="item.title"
avatar
ripple
#click="toggle(index)">
<v-list-tile-content>
{{item.action}}
</v-list-tile-content>
</v-list-tile>
<script>
export default {
props:['voltage']
data () {
return {
selected: [2],
items: [
{
action: `Voltage: ${this.voltage}`
},
{
action: 'Weight: POOF'
},
{
action: 'Size: BOOM'
},
{
action: '2oo2? Need the logic document'
},
{
action: 'Price: Very very expensive'
}
]
}
},
}
</script>
currently it shows voltage as blank. I want Voltage: ${this.voltage} to show the value of voltage selected from the radiobutton on Stepper
Component's data object is initialized before this is available, hence this.voltage is undefined.
Instead make your items as computed prop.
<script>
export default {
props:['voltage']
data () {
return {
selected: [2],
}
},
computed: {
items() {
return [
{
action: `Voltage: ${this.voltage}`
},
{
action: 'Weight: POOF'
},
{
action: 'Size: BOOM'
},
{
action: '2oo2? Need the logic document'
},
{
action: 'Price: Very very expensive'
}
]
}
}
</script>
Related
I have the following vue component
<template>
<div class="box"
:data-target="dropAreaClass"
:class="{ 'js-draggable': isDraggable }"
:id="id"
:draggable="isDraggable"
#dragstart="dragStart"
#dragend="dragEnd">
{{ id }}
</div>
</template>
<script>
export default {
name: 'ActionBox',
props: {
dropAreaClass: {
default: 'js-droppable--any',
type: String,
},
id: {
default: null,
type: String,
required: true,
},
isDraggable: {
default: true,
type: Boolean,
},
},
data: () => ({
dropAreas: null,
}),
mounted() {
this.dropAreas = document.querySelectorAll(`.${this.dropAreaClass}`);
},
methods: {
dragEnd(event) {
this.dropAreas.forEach(dropArea => {
dropArea.classList.remove('drop');
});
event.currentTarget.classList.remove('dragging');
},
dragStart(event) {
this.dropAreas.forEach(dropArea => {
dropArea.classList.add('drop');
});
event.currentTarget.classList.add('dragging');
event.dataTransfer.setData('text', event.currentTarget.id);
},
},
};
</script>
This is a simple div which I can drag a drop into multiple columns in the parent component - once it is dropped in one of the target columns, the following function is fired to move the component to the column it is dropped in:
drop(event) {
const droppedElement = document.getElementById(event.dataTransfer.getData('text'));
if (event.currentTarget.classList.contains(droppedElement.dataset.target)) {
event.currentTarget.prepend(droppedElement);
event.currentTarget.classList.remove('drop');
}
},
This all works fine, however, once it is dropped, I can no longer drag the component to another column as it seems to have lost all it's event bindings. Is there a way to keep the events after dropping?
I am trying to use the vue-select component for a dropdown list. So far I have written.
<template>
<div>
<v-select label="name" key="id" :v-model="selected" :reduce="data => data.id" :options="items" #input="update()" />
</div>
</template>
<script>
export default {
props: {
initial: {
type: [String, Number],
default: 0,
},
api_call: {
type: String,
required: true,
},
},
data(){
return {
value: this.initial,
items: [],
}
},
computed: {
selected: {
get() {
return this.value;
},
set(val) {
return this.value = val;
}
},
},
methods:{
update() {
console.log('selected', this.selected, this.value);
this.$emit('input', this.selected);
},
getData: function(){
axios.get('/api/' + this.api_call)
.then(function (response) {
this.items = response.data;
}.bind(this));
},
},
created(){
this.getData();
}
}
The dropdown list populates as intended and selecting an Item inserts it in the input filed. The two problems I have are
Neither the value nor the selected variables change when something is selected.
I am also passing in an initial value which I would like to be selected as the default in the list.
Remove the binding sign : from v-model directive
<v-select label="name" key="id" v-model="selected" :reduce="data => data.id" :options="items" #input="update()" />
and init your value like :
data(vm){//vm refers to this
return {
value: vm.initial,
items: [],
}
},
or :
data(){
return {
value: null,
items: [],
}
},
mounted(){
this.value=this.initial
}
With the following component, I am getting an Error: [vuex] do not mutate vuex store state outside mutation handlers. error:
<template>
<div>
<v-data-table
:headers="headers"
:items="items"
:search="search"
:key="tableKey"
:pagination.sync="pagination"
disable-initial-sort
rowKey
>
<template slot="items" slot-scope="props">
<tr #click="clicked(props.item)" :class="{'secondary': props.item[rowKey]===selectedCode}">
<td v-for="header in headers" :key="header.value">
<BaseTableColumn
:item="props.item"
:index="header.value"
:format="header.format"
/>
</td>
</tr>
</template>
</v-data-table>
</div>
</template>
<script>
export default {
name: 'BaseTable',
props: {
headers: Array,
items: Array,
search: String,
tableKey: String,
rowKey: String,
},
data: () => ({
pagination: {
rowsPerPage: 10,
totalItems: -1,
},
selectedCode: -1,
}),
components: {
BaseTableColumn: () => import('#/components/base/BaseTableColumn'),
},
methods: {
clicked(row) {
window.scrollTo(0, 0);
this.selectedCode = row[this.rowKey];
this.$set(row, 'selected', true);
this.$emit('rowClick', row);
},
highlightFirst(items) {
this.selectedCode = this.items[0][this.rowKey];
this.$set(this.items[0], 'selected', true);
},
},
updated() {
if (this.selectedCode === -1 && (typeof this.items === 'object') && this.items.length > 0) {
this.highlightFirst(this.items);
}
},
};
</script>
For reference, here is headers.js:
const headers = [
{
text: 'Tenant Code',
value: 'code',
},
{
text: 'Tenant ID',
value: 'name',
},
];
export default headers;
and BaseTableColumn.vue:
<script>
export default {
name: 'BaseTableColumn',
props: {
format: Function,
item: Object,
index: String,
},
methods: {
getText() {
return this.item[this.index];
},
},
render(createElement) {
if (this.$props.format) {
return this.$props.format(this.item, this.index, createElement);
}
return createElement('div', this.getText());
},
};
</script>
The issue happens here:
this.$set(this.items[0], 'selected', true);
However, if I follow the docs like so:
<template>
<div>
<v-data-table
:headers="headers"
:items="tableRows"
:search="search"
:key="tableKey"
:pagination.sync="pagination"
disable-initial-sort
rowKey
>
...
</template>
<script>
export default {
name: 'BaseTable',
props: {
headers: Array,
items: Array,
search: String,
tableKey: String,
rowKey: String,
},
...
computed: {
tableRows() {
const rows = [...this.items];
return rows;
},
},
...
methods: {
...
highlightFirst(items) {
this.selectedCode = this.items[0][this.rowKey];
this.$set(this.tableRows[0], 'selected', true);
},
},
updated() {
if (this.selectedCode === -1 && (typeof this.tableRows === 'object') && this.tableRows.length > 0) {
this.highlightFirst(this.tableRows);
}
},
};
</script>
I still get the errors, specifically in the updated() hook and the highlightFirst() method, even though I'm not referencing or mutating a prop. What else do I need to change to get rid of this error?
The way I eventually solved this problem was to emit an event and use the row value in the parent component:
clicked(row) {
window.scrollTo(0, 0);
this.selectedCode = row[this.rowKey];
this.$emit('rowClick', row);
},
However, to #Jesper's point above, since then, I have been using Object.assign() in cases like this where I need to break the link to Vuex.
I am stuck at this very point: exporting filter function and using it in vuex store. No problem'till here. Now am trying to put #click event on divs. And when I click, for example. Audi the filter needs to show just "audi" And if I click "audi" again then it needs remove it from the filter.
Here is the sandbox: https://codesandbox.io/s/filtering-bzphi
filter.js
export const carFilter = car => allcars => {
if (car.length > 0) {
if (allcars.name.includes(car)) {
return true;
} else {
return false;
}
} else {
return true;
}
};
Store
export const store = new Vuex.Store({
state: {
cars: [
{ name: "AUDI" },
{ name: "BMW" },
{ name: "MERCEDES" },
{ name: "HONDA" },
{ name: "TOYOTA" }
],
carBrand: []
},
mutations: {
updateCarsFilter(state, carBrand) {
state.carBrand = carBrand;
}
},
getters: {
filteredCars: state => {
return state.cars.filter(carFilter(state.carBrand));
}
}
});
and App.js
<template>
<div id="app">
<div class="boxes" :key="index" v-for="(item, index) in cars">{{item.name}}</div>
<List/>
</div>
</template>
<script>
import List from "./List.vue";
export default {
name: "App",
components: {
List
},
computed: {
selectBrand: {
set(val) {
this.$store.commit("updateCarsFilter", val);
},
get() {
return this.$store.state.carBrand;
}
},
cars() {
return this.$store.getters.filteredCars;
}
}
};
</script>
I also created a sandbox for this. You can check it for better understanding. https://codesandbox.io/s/filtering-bzphi
In the store.js
changed the carBrand default to ''
added Mutation clearFilter
added Getter isActiveFilter
update
remove carBrand from state
replaced by selectedCars that is an array
removed mutation about carBrand
added mutation addCarSelection removeCarSelection
filteredCars return selectedCars array if contains cars, otherwise cars state
added isSelectedCar to check if a car is in the selection
carFilter function from filter.js is no longer needed.
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
cars: [
{ name: "AUDI" },
{ name: "BMW" },
{ name: "MERCEDES" },
{ name: "HONDA" },
{ name: "TOYOTA" }
],
selectedCars: []
},
mutations: {
addCarSelection(state, car) {
state.selectedCars.push(car);
},
removeCarSelection(state, car) {
state.selectedCars = state.selectedCars.filter(r => r.name !== car.name);
}
},
getters: {
filteredCars: state => {
if (state.selectedCars.length !== 0) {
// There's selected cars, return filtered
return state.selectedCars;
} else {
return state.cars;
}
},
isSelectedCar: state => car => {
return state.selectedCars.some(r => r.name === car.name);
}
}
});
In the App.vue
added method filterCars (moved from computed property searchText)
added method clearFilter
update
removed filterCars and 'clearFilter' method and mapped new mutation and getters from store
methods: {
addCarSelection(car) {
this.$store.commit("addCarSelection", car);
},
removeCarSelection(car) {
this.$store.commit("removeCarSelection", car);
},
isSelectedCar(car) {
return this.$store.getters.isSelectedCar(car)
},
}
added isFilterActive() computed property
update
removed isFilterActive() and searchText from computed property
computed: {
cars() {
return this.$store.getters.filteredCars;
},
},
update
Changed the Template code to manage #click event to add car or remove car from selection
boxes always show cars available, if isSelectedCar toggle between add or remove function.
List show selected cars if presents otherwise the full car catalog.
<template>
<div id="app">
<div class="boxes" :key="index" v-for="(item, index) in cars">
<div
v-if="!isSelectedCar(item)"
style="cursor:pointer"
#click="addCarSelection(item)"
>{{item.name}}</div>
<div v-else style="cursor:pointer;" #click="removeCarSelection(item)">
{{item.name}}
<small>[x]</small>
</div>
</div>
<List/>
</div>
</template>
Updated version is available in this sandbox
https://codesandbox.io/s/filtering-3ej7d
I can't transfer the value from input to the store. When I click on the add item button, I need to create a block with its delete button and the text entered in the input. And then save it all in localstorage. But now I am creating only a new block without text. Please help me fix my code to make it work.
Here's how it should work
But how it works now
What I'm doing wrong? How do I transfer the value from Input to Vuex?
Here is my code
<template>
<f7-block-title>Some items</f7-block-title>
<f7-block v-for="(cat, n) in getCats" :key="n">
<span>{{ cat }}</span>
<f7-button fill color="red" #click="removeCat(n)">Delete Cat</f7-button>
</f7-block>
<f7-list form>
<f7-list-input :value="tempCat" type="text"></f7-list-input>
<f7-button fill color="blue" #click="addCat(tempCat)">Add some item</f7-button>
</f7-list>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
data () {
return {
tempCat: '',
};
},
computed:{
...mapGetters([
'getCats',
]),
},
methods: {
...mapActions([
'addCat',
'removeCat',
])
}
}
</script>
Code in VUEX
function loadLocalStorage() {
try {
return JSON.parse(localStorage.getItem('cats'));
} catch(e) {
localStorage.removeItem('cats');
return [];
}
}
export default new Vuex.Store({
state: {
cats: loadLocalStorage(),
},
getters:{
getCats: state => state.cats,
},
actions: {
addCat(context, data) {
context.commit('ADD_CAT', data);
context.commit('SAVE_CATS');
},
removeCat(context, data) {
context.commit('REMOVE_CAT', data);
context.commit('SAVE_CATS');
},
},
mutations: {
ADD_CAT(state, data) {
state.cats.push(data);
console.log(state.cats);
},
SAVE_CATS(state) {
localStorage.setItem('cats', JSON.stringify(state.cats));
console.log(state.cats);
},
REMOVE_CAT(state, index) {
state.cats.splice(index, 1);
},
},
});
GitHub link https://github.com/MrRJDio/ex1
First of all, your code doesn't respect the VueX state management standard. This article explains very well how to make proper use of VueX.
Some valid Vuex would like this:
Vue file:
<template>
<f7-block strong>
<f7-block-title>Some items</f7-block-title>
<f7-block v-for="(cat, n) in getCats" :key="n">
<span>{{ cat }}</span>
<f7-button fill color="red" #click="removeCat(n)">Delete Cat</f7-button>
</f7-block>
<f7-list form>
<f7-list-input :value="tempCat" type="text" placeholder="Заметка"></f7-list-input>
<f7-button fill color="blue" #click="addCat(tempCat)">Add some item</f7-button>
</f7-list>
</f7-block>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
data () {
return {
tempCat: '',
};
},
computed:{
...mapGetters([
'getCats',
]),
},
methods: {
...mapActions([
'addCat',
'removeCat',
])
}
}
</script>
Store:
function loadLocalStorage() {
try {
return JSON.parse(localStorage.getItem('cats'));
} catch(e) {
localStorage.removeItem('cats');
return [];
}
}
export default new Vuex.Store({
state: {
cats: loadLocalStorage(),
},
getters:{
getCats: state => state.cats,
},
actions: {
addCat(context, data) {
context.commit('ADD_CAT', data);
context.commit('SAVE_CATS');
},
removeCat(context, data) {
context.commit('REMOVE_CAT', data);
context.commit('SAVE_CATS');
},
},
mutations: {
ADD_CAT(state, data) {
state.cats.push(data);
},
SAVE_CATS(state) {
localStorage.setItem('cats', JSON.stringify(state.cats));
},
REMOVE_CAT(state, index) {
state.cats.splice(index, 1);
},
},
});