How can I load reactive data to multiselect component? - vue.js

I am trying to use this library https://github.com/vueform/multiselect, but whenever I try to load fetched data, nothing shows up in there, but for e.g when I do {{ testData }} I see the value in html. Can anyone advice me how can I fix this?
Works:
<Multiselect :options="['test']" />
Doesn't work:
<Multiselect :options="testData" />
in my setup()
const testData = computed(() => {
return [
{
name: "Test"
}
]
})
return { testData }

From the above I assume it should be an array, so try this
const testData = computed(() => {
return [{ name: "Test"}]
})
return { testData }
and add the below change in template
<Multiselect :options="testData" track-by="name" label="name"/>
Modified on request:
If you wanna show the entire object then you can follow the below example
const testData = computed(() => {
return [
{ name: 'Vue.js', id: 'vue' },
{ name: 'Angular', id: 'angular' }
]
})
return { testData }
and add a method called nameWithId with the below content.
Note: I have given it based on Vue2 syntax, pls change the syntax that matches to Vue3
nameWithId({ name, id }) {
return `${name} — [${id}]`
}
then with the below changes in your template
<Multiselect v-model="selectedValue" :options="testData" :custom-label="nameWithId" placeholder="Select one" label="name" track-by="name"/>
Reference doc: https://vue-multiselect.js.org/#sub-getting-started

Related

Save multiple fields from record in different collection in react-admin Form

I'm using react-admin to manage a MongoDB database. A simplified example of the collections in the database:
contacts = [
{ id: 8, name: "Joe", country: "UK" },
]
tasks = [
{ id: 0, description: "", dev: { contact_id: 8, name: "Joe" } },
]
The documents in tasks have to store both contact_id (contact doc reference) and name (shown in many different views, so the number of API calls can be reduced). In this case, I'd use an AutocompleteInput within a ReferenceInput to save contact_id.
<ReferenceInput source="dev.contact_id" reference="contacts">
<AutocompleteInput
source="dev.contact_id"
optionText="name"
optionValue="id"
/>
</ReferenceInput>
However, once the contact is selected in the Autocomplete, I can't find a way to save the field name, so the task document looks like in the example. So far I've tried getting the contact record and adding the name field before submitting the form, but it's not working (hooks can only be called inside the body of a function component):
export const TaskForm = ({ children }) => {
const { handleSubmit } = useForm()
const onSubmit = async (data) => {
const contact = await useGetOne('contacts', { id: data?.dev?.contact_id })
console.log(contact)
}
return (
<Form onSubmit={handleSubmit(onSubmit)}>
{children}
</Form>
)
}
Any suggestions?
Perhaps you can use the dataProvider-hook instead of the useGetOne:
export const TaskForm = ({ children }) => {
const { handleSubmit } = useForm()
const dataProvider = useDataProvider();
const onSubmit = async (data) => {
const contact = await dataProvider.getOne('contacts', { id: data?.dev?.contact_id });
console.log(contact)
}
return (
<Form onSubmit={handleSubmit(onSubmit)}>
{children}
</Form>
)
}

How make json data available for my Vue dynamic routes

I have a List component where I fetch my date from db/blogs.json:
created() {
fetch('http://localhost:3000/blogs')
.then(response => {
return response.json();
})
.then(data => {
this.blogs = data;
})
},
In my BlogDetail.vue I have:
<script>
export default {
data: () => {
return {
blogId:this.$route.params.id
}
},
computed: {
blog() {
return this.blogs.find(
blog => blog.id === this.blogId
)
}
}
}
</script>
But how do I get the blogs data in this component, which I fetched in the List component?
Because now in the <template> section of my BlogDetail.vue I cannot access e.g. {{ blog.name }}
Update:
I try passing blogs with props:
Now I am accepting a prop in BlogDetails.vue:
props: {
blogs: {
type: Array
}
},
But from where (which component), I have to registering the prop like :blogs="blogs"?
Update 2:
This is what I have so far, link to the sandbox
Here is the working sandbox.
Firstly you need to import JSON data from your JSON file correctly. As:
<script>
import ListItem from "./ListItem";
import Blogs from "../../public/db/blogs.json";
export default {
name: "List",
components: {
ListItem
},
data() {
return {
blogs: Blogs.experiences
};
},
created() {}
};
</script>
Have to send props in the router-link as :
<router-link
:to="{ name: 'BlogDetails', params: { id: blog.id,blog:blog }}">More information
</router-link>
You can send props to the child component in the tag name, in your case:
//LIST component(PARENT)
<tamplate>
<BlogDetail :blogs="blogs"></BlogDetail> //CHILD component
</template>

When removing images the last image removed stays (no re-render)

I have an array of objects, each has a URL that is being loaded in this file:
<template>
<div>
<img :key="id" :src="img" alt="" class="image box" #click="cardClicked" />
</div>
</template>
<script lang="ts">
export default {
props: ["id", "value", "type", "owner", "imgURL"],
data() {
return {
img: require(`./../assets/${this.imgURL}.png`)
};
},
methods: {
cardClicked() {
this.$store.commit("addCardToPlayer", {
id: this.id,
type: this.type,
value: this.value,
owner: this.owner
});
}
}
};
</script>
In the Store mutation I preform filtering and while filtering I add the card to a another player, like so:
addCardToPlayer(state, clickedCard) {
const owner = clickedCard.owner;
const type = clickedCard.type;
const currPlayer = state.currentPlayerName;
if (clickedCard.owner === "deck") {
state.cardOwners[owner].cards[type] = state.cardOwners[owner].cards[
type
].filter(card => {
if (card.id === clickedCard.id) {
state.cardOwners[currPlayer].cards[type].push(card);
return false;
} else return true;
});
}
},
When clicking a card to remove, I see the card being added to the player and displayed correctly, and the number of cards displayed after removal is correct.
But
The card that was removed still shows.
What have I tried:
Forcing to re-render using:
cardClicked() {
this.$store.commit("addCardToPlayer", {
id: this.id,
type: this.type,
value: this.value,
owner: this.owner
});
this.$forceUpdate();
}
Making different components have key, and trying to change the key to cause a re-render:
data() {
return {
componentKey: 0,
};
},
methods: {
forceRerender() {
this.componentKey += 1;
}
}
Tried changing how I change the array by creating a new state.
EDIT: Tried using computed. i get an error:
TypeError: Cannot read property 'imgURL' of undefined
computed: {
getImg: () => {
return require(`./../assets/${this.imgURL}.png`);
}}
EDIT: I wrote the computed function as arrow function, which doesn't preserve context.
SOLVED, by using
computed: {
getImg() {
return require(`./../assets/${this.imgURL}.png`);
}}
How can I make the images update after click (remove).
Thanks.
SOLVED, by using
computed: {
getImg() {
return require(`./../assets/${this.imgURL}.png`);
}}

Displaying data from Vuex store in component based on route

I have the following data in Vuex store:
state: {
news: [
{ id: 1, title: "placeholder", text: "Lorem ipsum doloret imes", date: "20-01-2020", type: "management" },
{ id: 2, title: "Revenue", text: "Lorem ipsum doloret imes", date: "20-01-2020", type: "management" }]
}
I want to display this data in the component based on the id used in route:
{path: '/news/:id',
component: () => import('../views/NewsDetail.vue'),
props: true
}
In my NewsDetail.vue component I try to retrieve the data like this:
<template>
<p class="display-1 text--primary">{{display.type}}</p>
</template>
<script>
data () {
return {
display: newsId
}
},
created () {
const newsId = this.$store.state.news.find((newsId) => { return newsId.id == this.$route.params.id})
}
</script>
But I get error that newsId is not defined and that it is defined but never used...
How can I display the data from the vuex store based on route id (that should be matching the id of the entry in store)?
'error that newsId is not defined'
so what you want is vuex getters
<script>
import { mapGetters } from 'vuex'
computed: {
...mapGetters([
news
]),
newsId() {
return this.news.find((newsId) => { return newsId.id == this.$route.params.id})
}
}
it's either that or adding newsId to the data object
<script>
data () {
return {
newsId: '',
display: newsId
}
},
created () {
this.newsId = this.$store.state.news.find((newsId) => { return newsId.id ==
this.$route.params.id})
}
</script>
Your newsId constant is defined in the created() method and only exists within that scope. It is deleted as soon as the function returns. That's why you're getting the error message--because the const isn't used inside the function, and it's not available to be used anywhere else.
I suggest you create an id prop in your NewsDetail component, which will automatically be populated with the ID param. Then use a computed property to fetch the appropriate data from the store.

How load data after all computed data from vuex store was loaded?

Working with Laravel 5.7 / Vuejs 2.6 / Vuex 3.1 app I use "vue-select": "^2.6.4" and when I open form with existing data I need
to fill my select component with variable
selection_status = {key: ‘key’, label: ‘label’}
<v-select
v-model="selection_status"
data-vv-name="userRow.status"
:options="customerStatusValueArray"
v-validate="'required'"
id="status"
name="status"
class="form-control editable_field"
placeholder="Select option"
></v-select>
data() {
return {
...
selection_status: null,
mounted() {
this.loadCustomer();
}, // mounted() {
loadCustomer() {
axios.get(window.API_VERSION_LINK + 'personal/customers/' + this.user_id).then((response) => {
this.userRow = response.data.user;
this.customerStatusValueArray.map((nextCustomerStatusValue, index) => {
if (nextCustomerStatusValue.key == this.userRow.status) {
this.selection_status = {key: this.userRow.status, label: nextCustomerStatusValue.label};
}
});
...
computed: {
customerStatusValueArray() {
return this.$store.getters.customerStatusValueArray;
},
I get customerStatusValueArray array from vuex store and I found that it is filled AFTER method loadCustomer from mounted is loaded,
so this.selection_status is null.
Is there is a way to run
this.loadCustomer();
after all computed data from vuex store is loaded?
Thanks!
You probably should use a loading state,
also consider using created() to call this.loadCustomer()
because mounted() its called after the component has been rendered.
<v-select v-if="loaded' />
<my-loader v-else/>
data() {
loaded: false,
}
loadCustomer() {
axios.get('url').then((response) => {
this.loaded = true;
});
}
update:
You can observe when your computed changes,
once customerStatusValueArray isn't empty you can call this.loadCustomer()
export default {
watch: {
customerStatusValueArray: (newVal, oldVal) {
if (newVal.length > 0)
this.loadCustomer()
}
}
computed: {
customerStatusValueArray() {
return this.$store.getters.customerStatusValueArray;
},
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>