I'm having a form in vue js with select drop downs, I'm trying to use https://sagalbot.github.io/vue-select/ this library to execute this, according to the documentation I've to pass an array into this and I'm calling a axios method to get the options of the drop downs. I'm getting the data in following format:
And with following description:
I want to only show the names in the option and get values as ID of that particular row, how can I achieve this.
My code look something like this: https://jsfiddle.net/eemdjLex/1/
<div id="app">
<v-select multiple :options="model.data"></v-select>
</div>
import vSelect from 'vue-select';
Vue.component('v-select', vSelect)
const app = new Vue({
el: '#app'
router: router,
data () {
return {
model: {},
columns: {},
}
}
methods: {
fetchIndexData() {
var vm = this;
axios.get('/companies').then(response => {
Vue.set(vm.$data, 'model', response.data.model)
Vue.set(vm.$data, 'columns', response.data.columns)
}
}
});
It is not working proper but you get the idea what I'm trying to do.
v-select appears to return the entire option as the value when using v-model so I might use a pair of computed values here.
new Vue({
el:"#app",
data:{
serverData,
selected: null
},
computed:{
// serverData is a stand in for your model.data.
// map over that to build your options
selectOptions(){
return this.serverData.map(d => ({label: d.name, value: d.id}))
},
// selectedOption is just a short computed to get the id value
// from whatever option was selected. You could also just use
// "selected.id" in whatever needs the id instead if needed.
selectedOption(){
if (this.selected)
return this.selected.value
else
return null
}
}
})
Example.
Looking at the README on the GitHub page for vue-select, I'm seeing that you can pass the <v-select> component an options property as an array of objects with label and value keys.
I would make a computed property to take your model.data and format it this way:
computed: {
options() {
let data = this.model.data;
let options = [];
// do whatever you need to do to format the data to look like this object:
// options = [{ label: 'foo', value: 1 }, { label: 'bar', value: 2 }]
return options;
}
}
Then pass this computed property to the <v-select> instead:
<v-select multiple :options="options"></v-select>
The official select docs may help you
your v-select component should look like
new Vue({
template: `
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>`,
el: 'v-select',
props: [ 'options' ]
data: {
selected: ''
}
})
Related
I've using this code over and over again. Wonder if there's a better way to make this shortcut
Here's the example
// items.js
export default [
{ title: 'ABC', href: 'javascript:void(0)' },
{ title: 'DEF', href: 'javascript:void(0)' }
]
// index.vue
<script>
import items from './items.js'
export default: {
computed: {
links() {
let results = []
items.forEach((item,index) => {
item.id = index
results.push(item)
})
return results
}
}
}
</script>
//returned result = { title: 'ABC', href: 'javascript:void(0)', id: 0 }
I just want to add id to each of the object in the computed property, so that I not worry about using v-for="(item, index) in items" :key="index". instead just using v-for="item in links" :key="item.id" in the template
The question:
From the code, you see I declare empty array of results let results = [] then I populate the result from forEach data before I return the result. Is that any better way to do to return each of the loop data without declare empty array and populate it before return the array of that generated data?
Sometimes, I not just add id, maybe add another like item.internal = true. Or level if it's multilevel.
You could use map method and spread operator to add id to the item :
computed: {
links() {
return items.map((item,index)=>({id:index,...item}))
}
}
I have no idea if what I'm doing is correct or not, but here's a simplified version of what I'm trying to do:
I want to have 3 file inputs, with the 2nd and 3rd disabled until the 1st one has had a file selected.
I've tried to do is set the Vuex state variable to whatever the first file input is has selected, but upon doing that the other 2 inputs don't update their disabled state.
I have some file inputs that are created dynamically, like so:
Vue.component('file-input', {
props: ['items'],
template: `<div><input type="file" v-on:change="fileSelect(item)" v-bind:id="item.id" v-bind:disabled="disabledState"></div>`,
methods: {
fileSelect: function(item) {
store.commit('fileSelect', file);
}
},
computed: {
disabledState: function (item) {
return {
disabled: item.dependsOn && store.getters.getStateValue(item.dependsOn)
}
}
}
}
The data for the component is from the instance:
var vm = new Vue({
data: {
items: [
{ text: "One", id: "selectOne" },
{ text: "Two", id: "selectTwo", dependsOn: "fileOne" },
{ text: "Three", id: "selectThree", dependsOn: "fileOne" }
}
});
Now, notice the "dependsOn". In the Vuex store, I have a corresponding state item:
const store = new Vuex.Store({
state: {
files: [
{
fileOne: null
}
]
},
mutations: {
fileSelect(state, file) {
state.files.fileOne = file;
}
},
getters: {
getStateValue: (state) => (stateObject) => {
return state.files.findIndex(x => x[stateObject] === null) === 0 ? true : false;
}
}
});
Now, the above works when everything is first initialized. But once the first input has something selected, the other two inputs don't change.
I'm not sure how to update the bindings once a mutation of the state occurs.
I think you need to refactor your mutation to make the state property mutable, like this:
fileSelect(state, file) {
Vue.set(state.files[0].fileOne, file);
}
Well, I figured it out...
Because my state object is an array of objects, I can't just change one of the property's values with state.files.fileOne. I needed to do state.files[0].fileOne.
I have some questions about using v-model with "complex" object. Here's my code:
<v-list v-for="(facet, facetName) in getFacets" :key="facetName">
<v-list-tile-content v-for='valueFacet in facet" :key="valueFacet.key">
<v-checkbox v-model="selectedFacets[facetName]" :value="valueFacet.key"></v-checkbox>
</v-list-tile-content>
</v-list>
And here's my data / init:
data() {
return {
selectedFacets: {}
}
},
created: function() {
// I initialize my object with all my facets here
config.facets.forEarch(facet => {
this.selectedFacets[facet] = [];
});
}
Some explanation: each facet has multiple checkbox representing values. We can select multiple values. My object has to be like this :
selectedFacets: { facet1 : [value1, value2], facet2: [value12, value 13]
With this code, each time I select one value, it will remove the previous one.
I tried to initalize my object in my data like this without using created function:
data() {
return {
selectedFacets: { "facetName" : [], "facetName2" : []}
}
}
and it works fine. All my values for each facet are added in the right array. But I need to initialize my object and facet names with my conf and if I don't initialize my object in my data, it does not work. I tried with computed / created, by getting my object from my store, but it keeps adding value by removing the previous one.
Any idea about what I do wrong ? Thanks.
Just initialize your object with Vue.set:
created: function() {
config.facets.forEach(facet => {
Vue.set(this.selectedFacets, facet, []);
});
}
When component initializes template it doesn't know about selectedFacets[facetName] so to make it reactive and correct working with v-model you should use Vue.set mutator.
I can't find how to create a variable from another variable value.
I get this variable from AJAX call (using vue-resources):
langs: {1:'fr', 2:'en', 3:'ar'},
But, I don't know how many properties langs will have.
How can I get this variable dynamically:
newVar: {
has_lang: '1',
values: [{ is: 'fr', val:''}, { is: 'en', val:''}, { is: 'ar', val:''}]
},
So in newVar, the fr, en, and ar properties have been generated automatically using the values in langs.
I am planning to use the values array to bind to the values of my md-input inputs using v-model:
<md-input-container v-for="value in newVar.values">
<label>#{{ attribute.attribute }} #{{ value.is }}</label>
<md-input v-model="value.val"></md-input>
</md-input-container>
Is doing this manipulation the best practice? Because I can't find a solution which uses v-model for inputs that are generated from a v-for loop.
Use a watcher to set the newVar property whenever the langs property changes. You'll need to also do this during the mounted lifecycle event if you are passing in the langs variable as a prop or defining it within data().
In your case, I'd add a method to call at both points:
data() {
return {
langs: {1:'fr', 2:'en', 3:'ar'},
newVar: {},
};
},
methods: {
updateValues() {
let newVar = {
has_lang: (this.langs !== {}) ? '1' : '0',
values: [],
};
for (let lang in this.langs) {
newVar.values.push({ is: this.langs[lang], val: '' });
}
this.newVar = newVar;
}
},
watch: {
langs() {
this.updateValues();
}
},
mounted() {
this.updateValues();
}
Here's a CodePen.
I use Vuex with my Vue components. When my components have static fields that are editedtable, they are easily handled with computed properties:
computed: {
text: {
get() {
return ...
},
set(value) {
this.$store.commit...
},
},
},
<input type="text" v-model="text">
However, how should this be done when I render a list of options that need to be bound?
options = [
{
value: ...,
text: ...,
},
{
value: ...,
text: ...,
},
...
];
<input type="text" v-model="option.text" v-for="option in options">
You have to define mutations for the options, like "addOption", "editOption", etc...
Than optionally ( but recommended ) define an options component. Bind events to call the mutations.
A good simple example provided by vuex is available here:
https://github.com/vuejs/vuex/tree/dev/examples/todomvc
Particularly look at the todo component. It is in charge of a single item from the todo list.
https://github.com/vuejs/vuex/blob/dev/examples/todomvc/components/Todo.vue
and how they work with the list in the app component.
https://github.com/vuejs/vuex/blob/dev/examples/todomvc/components/App.vue
And these are their mutations. See how they edit and add and delete list items.
https://github.com/vuejs/vuex/blob/dev/examples/todomvc/store/mutations.js
I can't have a shorter answer, moving to vuex ( vue + redux methodology ) requires a shift in thinking and architecture.
You can model these options as data in your vue instance and use them in HTML as you have mentioned.
var vm = new Vue({
data: {
options: [
{
value: ...,
text: ...,
},
{
value: ...,
text: ...,
},
...
]
}
})
And in HTML:
<input type="text" v-model="option.text" key="option.value" v-for="option in options">
I have added a key attribute as well along with v-for so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key attribute for each item. An ideal value for key would be the unique id of each item.