I have Related data between Province and District, Province hasMany District.
I have Object something like this.
{
"id": 1,
"name_eng": "Banteay Meanchey",
"name_kh": "បន្ទាយមានជ័យ",
"district": [
{
"id": 1,
"name_eng": "Mongkol Borei",
"name_kh": "មង្គលបុរី",
"province": 1
}
]
},
I have form like above image, All i want is when select Province the field District will Auto Filled to related relationship.
Between i use Vuetify v-autocomplete
<label
>Pls Select Province/District</label
>
<v-autocomplete
:items="provinces"
item-id="id"
item-text="name_kh"
label="Pls Select Province"
solo
v-model="form.province"
return-object
>
</v-autocomplete>
<v-autocomplete
:items="provinces"
item-id="id"
item-text="name_kh"
label="Pls Select District"
solo
v-model="form.province"
return-object
>
</v-autocomplete>
In script Tag
<script>
import axios from "axios";
export default {
data() {
return {
menu: false,
loading: false,
form: {},
provinces: [],
};
},
created() {
this.getProvince();
},
computed() {},
methods: {
getProvince() {
axios
.get(`api/v1/province/`)
.then((res) => {
console.log(res);
this.provinces = res.data;
})
.catch((err) => {
console.log(err.response);
});
},
},
};
</script>
I'll appreciate of all ur help :) Thanks...
On district dropdown, you can be looping by selected province like below
<v-autocomplete
:items="getDistrictsByProvince(form.province)"
item-id="id"
item-text="name_kh"
label="Pls Select District"
solo
v-model="form.province"
return-object
>
</v-autocomplete>
In script Tag under method:
getDistrictsByProvince(province) {
if(province){
return this.provinces.find(item => item.id === province.id).district
} else {
return []
}
}
Related
I'm learning to code and have a Vuetify datatable where I want to change boolean values in the table to icons. I want to make the table dynamic so I can reuse it as a component, passing props to it depending on page. I can get headers and other stuff to pass as props fine but passing props into the v-slot item in child table is problematic.
I am currently passing a 'booleans' prop from parent which has an array of objects including names of the columns that I want to change to icons and the true/false icons.
Here is the 'boolean' prop array from parent. I've stripped everything else out for readability.
booleans: [
{
name: "wo",
iconTrue: "mdi-account",
iconFalse: "mdi-office-building",
},
{
name: "ep",
iconTrue: "mdi-account",
iconFalse: "mdi-office-building",
}]
The child component is a vuetify datatable.
<template>
<div>
<v-data-table
:headers="headers"
:items="gotData"
:items-per-page="25"
:sort-by="sort"
dense
:search="search"
:loading="loading"
loading-text="Loading... Please wait"
#click:row="handleClick"
class="elevation-1"
>
<template v-for="(bool, i) in booleans" v-slot:[boolNames[i]]="{ item }">
<v-icon :key="i" class="mr-3">
{{ boolNames[i] ? bool.iconTrue : bool.iconFalse }}</v-icon>
</template>
</v-data-table>
</div>
</template>
Script
<script>
export default {
data: () => ({
search: "",
loading: "true",
dialog: false,
gotData: [],
}),
props: {
dataSource: {
type: String,
},
headers: {
type: Array,
},
tableTitle: {
type: String,
},
pageURL: {
type: String,
},
sort: {
type: String,
},
booleans: {
type: Array,
},
},
created() {
this.initialize();
},
computed: {
formTitle() {
return this.editedIndex === -1 ? "New Item" : "Edit Item";
},
boolNames: function () {
return this.booleans.map(function (bool) {
return "item." + bool.name;
});
},
},
methods: {
async initialize() {
const response = await this.$axios
.$get(this.dataSource)
.then((response) => {
this.gotData = response.data;
})
.catch(function (error) {
console.log(error);
});
this.loading = false;
},
async addItem(item) {
this.editedIndex = this.dataSource.indexOf(item);
this.editedItem = Object.assign({}, item);
this.dialog = true;
this.$axios({
method: "post",
url: this.dataSource,
data: this.item,
})
.then((response) => {
this.gotData = response.data;
})
.catch(function (error) {
console.log(error);
});
},
handleClick(item) {
this.$router.push(this.pageURL + item.id);
},
},
};
</script>
boolNames[i] returns item.wo and item.ep as I want it to but vuetify sees these as strings not props and so the ternary always reads true and all cells in table are the true icon.
If I hard code item.wo into the template it will work properly, e.g.
<template v-for="(bool, i) in booleans" v-slot:[boolNames[i]]="{ item }">
<v-icon :key="i" class="mr-3">
{{ item.wo ? bool.iconTrue : bool.iconFalse }}</v-icon>
</template>
I've tried all sorts of other ways to get this to work but can't figure out.
How do I get this to work?
Ok, figured it out. I got rid of the computed property and went back to how I started. Just had a syntax error. Here is code that works.
<template
v-for="(bool, i) in booleans"
v-slot:[`item.${bool.name}`]="{ item }"
>
<v-icon :key="i" class="mr-3">
{{ item[bool.name] ? bool.iconTrue : bool.iconFalse }}</v-icon
>
</template>
I am using buefy taginput in my form, everything works as expect filter using ontype event.
only problem here is that i can see data in taginput box on when i focus, its getting selected too, but when i type its not getting filtered. for 10-15 items its not a problem but when its 1000+ items, it will be difficult. i don't know whats the problem here.
here is code so far.
<template>
<b-field label="Popular Destinations">
<b-taginput
v-model="form.popularSubDests"
:data="allSubDests"
autocomplete
:allow-new="allowNew"
:open-on-focus="openOnFocus"
field="SubDestName"
icon="label"
placeholder="Add Cities"
#typing="getFilteredSubdest"
>
</b-taginput>
</b-field>
</template>
<script>
export default {
data() {
return {
openOnFocus: false,
isSelectOnly: false,
allowNew: false,
allSubDestinations: [],
form: {
popularSubDests: [
{
SubDestName: null,
SubDestId: null,
},
],
},
}
},
computed: {
allSubDests() {
return this.allSubDestinations.map((item) => ({
SubDestId: item.id,
SubDestName: item.subdestname,
}))
},
},
methods: {
getFilteredSubdest(text) {
this.allSubDests = this.allSubDests.filter((option) => {
return option.SubDestName.toString().toLowerCase().indexOf(text.toLowerCase()) >= 0
})
},
},
async asyncdata({ route }) {
let { data: allSubDest } = await axios.get(`process.env.FETCHSUBDEST`)
return {
allSubDestinations: allSubDest.results,
}
},
}
</script>
I want a selector in a Vue component to update when the stored value in Vuex is updated. Here is a simplified version of the vue component:
<template>
<v-autocomplete
outlined
dense
v-model="team"
label="Select Team"
:items="teams"
item-text="name"
item-value="_id"
return-object
class="mx-3 mt-3"
#change="selectTeam"
></v-autocomplete>
</template>
The JS:
<script>
export default {
name: 'NavDrawer',
data() {
return {
team: null,
teams: [],
};
},
async created() {
this.team = this.$store.getters['teams/allTeams'].find(
(t) => t.name === this.$route.params.team,
);
this.teams = this.$store.getters['teams/allTeams'];
},
methods: {
async selectTeam() {
if (this.team) {
await this.$store.dispatch('editTeam/selectTeam', this.team);
this.$router.push(`/team/${this.team.name}`);
} else {
this.$router.push('/');
}
},
},
};
</script>
And the Vuex store:
export default {
namespaced: true,
state: () => ({
editedTeam: {},
}),
mutations: {
selectTeam(state, team) {
state.editedTeam = team;
},
resetTeam(state) {
state.editedTeam = {};
},
},
actions: {
selectTeam({ commit }, team) {
commit('selectTeam', team);
},
resetTeam({ commit }) {
commit('resetTeam');
},
},
getters: {
getSelectedTeam: (state) => state.editedTeam,
},
};
I'm not sure if it matters, but this vuex store is passed into an index file to create the Vuex.Store -- this is working correctly and is not the issue.
I want the team stored in editedTeam to reactively update the team selected in the v-autocomplete component, when a new editedTeam is selected elsewhere in the application. I want the v-autocomplete selector to send a new team to editedTeam when it is selected. I think I should be using mapState for this and storing them as a computed value -- but nothing I've tried has worked. I find the vuex documentation to be lacking in good examples.
Thanks!
This question already has answers here:
Returning Promises from Vuex actions
(5 answers)
Closed 2 years ago.
I would like to populate my bootstrap-vue table with data from my database. I am using vuex to attempt to achieve this; however, the bootstrap-vue table isn't getting the data for some reason. I checked Vuex dev tools:
I added console.log('Getters: ' + this.$store.getters.allEmployees); to my component to see what that retrieves and it only outputs Getters: to the console.
To further troubleshoot this, I hardcoded: [{"id":1,"name":"Jane Smith","email":"jane#smith.com","job_title":"Lead"},{"id":2,"name":"John Smith","email":"john#smith.com","job_title":"Installer"}] into the employees state and now the data gets loaded into the table.
Vuex module employees.js
const state = {
employees: [],
employeesStatus: null,
};
const getters = {
allEmployees: state => {
return state.employees;
},
};
const actions = {
fetchAllEmployees({commit, state}) {
commit('SET_EMPLOYEES_STATUS', 'loading');
axios.get('/api/employees')
.then(res => {
commit('SET_EMPLOYEES', res.data);
//console.log(state.employees);
commit('SET_EMPLOYEES_STATUS', 'success');
})
.catch(error => {
commit('SET_EMPLOYEES_STATUS', 'error');
});
},
};
const mutations = {
SET_EMPLOYEES(state, employees) {
state.employees = employees;
},
SET_EMPLOYEES_STATUS(state, status) {
state.employeesStatus = status;
}
};
export default {
state, getters, actions, mutations,
};
VueJS component EmployeeDataTable.vue:
<template>
<div class="overflow-auto pb-3" style="background: white; ">
<b-card
header="Employees"
header-tag="header"
>
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
aria-controls="my-table"
></b-pagination>
<p class="mt-3">Current Page: {{ currentPage }}</p>
<b-table
id="employee-table"
ref="employee-table"
:items="items"
:per-page="perPage"
:current-page="currentPage"
small
></b-table>
</b-card>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: "EmployeeDataTable",
data() {
return {
perPage: 3,
currentPage: 1,
items: [],
}
},
computed: {
...mapGetters(['allEmployees']),
rows() {
return this.items.length
}
},
methods: {
getEmployees() {
this.$store.dispatch('fetchAllEmployees').then(() => {
this.items = this.$store.getters.allEmployees;
console.log('Getters: ' + this.$store.getters.allEmployees); //<-Returns Getters:
});
//this.items = this.$store.getters.allEmployees;
}
},
mounted() {
this.getEmployees();
}
}
</script>
Phil's explanation did the trick. The snippets I changed are:
const actions = {
fetchAllEmployees({commit, state}) {
commit('SET_EMPLOYEES_STATUS', 'loading');
return axios.get('/api/employees')
.then(res => {
commit('SET_EMPLOYEES', res.data);
//console.log(state.employees);
commit('SET_EMPLOYEES_STATUS', 'success');
})
.catch(error => {
commit('SET_EMPLOYEES_STATUS', 'error');
});
},
};
and
<b-table
id="employee-table"
ref="employee-table"
:items="allEmployees"
:per-page="perPage"
:current-page="currentPage"
small
></b-table>
I am trying to get the changed value of vuetify v-select by using $emit but it doesn't work.
I divided components by applying atomic design pattern (atoms(child component and not to connect with the store), organisms(parent component)) and vuex stores.
I think $emit data is OK but anything doesn't work after the process.
This is for a new application for management page with
using vue, vuex, vuetify, atomic design connecting to API server.
Components
child component - in atoms folder
<template>
<v-select
:items="list"
:label="label"
v-model="selected"
item-value="id"
item-text="name"
return-object
#change="changeSelected"
></v-select>
</template>
<script>
export default {
props: ["list", "label", "defaultSelected"],
data() {
return {
selected: this.defaultSelected
};
},
methods: {
changeSelected(newValue) {
console.log(newValue); // display changed new data
this.$emit("changeSelected", newValue);
}
}
};
</script>
parent component - in organisms folder
<template>
<v-select-child
:select-label="label"
:select-list="list"
:default-selected="selected"
#change-selected="changeSelected" // problem issue?
>
</v-select-child>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
...
},
computed: {
...mapState({
list: state => state.list
})
},
methods: {
changeSelected() {
console.log("changeSelected"); // doesn't work
this.$store.dispatch("setSelected", { payload: this.selected });
}
}
};
</script>
vuex stores
index.js
export default new Vuex.Store({
modules: {
xxx
},
state: {
list: [
{
name: "aaaaa",
id: "001"
},
{
name: "bbbbb",
id: "002"
}
]
},
getters: {},
mutations: {},
actions: {}
});
xxx.js
export default {
selected: { id: "001" }
},
getters: {
//
},
mutations: {
updateSelected(state, payload) {
console.log("payload"); // doesn't work
console.log(payload);
state.selected = payload;
console.log(state.selected);
}
},
actions: {
setSelected({ commit }, payload) {
console.log("Action"); // doesn't work
commit("updateSelected", payload);
}
}
};
It does not print any console log after changeSelected function.
In document
Unlike components and props, event names don’t provide any automatic
case transformation. Instead, the name of an emitted event must
exactly match the name used to listen to that event.
That means if you emit event like $emit('changeSelected'), then you need to use #changeSelected. #change-selected will not work.
<v-select-child
:select-label="label"
:select-list="list"
:default-selected="selected"
#changeSelected="changeSelected"
>
</v-select-child>
I found a solution below:
child component
<template>
<v-select
:label="label"
:items="list"
v-model="selected"
item-value="id"
item-text="name"
return-object
></v-select>
</template>
<script>
export default {
props: ["list", "label", "defaultSelected"],
computed: {
selected: {
get() {
return this.defaultSelected;
},
set(newVal) {
if (this.selected !== newVal) {
this.$emit("changeSelected", newVal);
}
}
}
}
};
</script>
parent component
<template>
<v-select-child
:label="label"
:list="list"
:defaultSelected="selected"
#changeSelected="changeSelected" // fix the property using camelCase
></v-select-child>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
...
},
computed: {
...mapState({
list: state => state.list
})
},
methods: {
changeSelected(val) { // val: changed object value
this.$store.dispatch("setSelected", { id:val.id });
}
}
};
</script>
You can also use watch;
<v-select
:label="label"
:items="list"
v-model="selected"
item-value="id"
item-text="name"
></v-select>
</template>
...
watch:{
selected(){
this.$emit('changeValue', this.selected.id');
}
}
...
and from parent;
<child #changeValue="id = $event" .. />