Reputation: 82182
Basically, I am using a custom component someone else wrote, and I want to set a default value for this v-text-field
and i have tried EVERYTHING to override the editedItem.color v-model.
Nothing I am capable of coming up with will work!
I am a laravel php dev, and I could really use some help from my stack friends here. I am at a new job, and i do not wish to fail.
<div v-if="formState === 'create'">
<v-text-field
v-model="editedItem.color"
:default="'#FF0000'"
:value="'#FF0000'"
:disabled="true"
label="Color*"
/>
</div>
As far as data, when i go the custom component, the data is as follows:
data: () => ({
formState: 'create',
loading: false,
items: [],
editedItem: {},
selectedItems: [],
}),
This seems like something that should be really easy. Just set a default value, and send that to the API. But with the v-model, it will not accept a v-bind:value or v-bind:default
This is a Vuetify component, and I am a newb Vue dev.
So in Summary, nothing will work without the v-model="editedItem.color", and yet, nothing will work if i do not set that default value.
The issue being that color picker returns an array, and we need it NOT to return an array.
So either I need to set the default value for 'create' mode to the #FF0000 hex value, or i need to parse out the returned value from the v-color-picker and JUST use the hex value and not return the array. So basically it all boils down to intercepting the editedItem.color for either solution.
This is my complete page/tags/index.vue page implementing the custom component.
Thanks SOF Fam!
<template>
<work-custom-table
v-model="headers"
:routes="routes"
:title="title"
settings-key="crud.table"
sort-by="name"
allow-merge
>
<template #item.preview="{ item }">
<v-chip :color="item.color">{{ item.name }}</v-chip>
</template>
<template #form="{editedItem, formState}">
<v-row>
<v-col>
<v-text-field
v-model="editedItem.name"
:disabled="formState === 'view'"
:rules="[$rules.required]"
label="Name*"
hint="*Required"
/>
</v-col>
</v-row>
<v-row>
<v-col>
<v-text-field
v-model="editedItem.description"
:disabled="formState === 'view'"
:rules="[$rules.required]"
label="Description"
/>
</v-col>
</v-row>
<v-row>
<v-col>
<div v-if="formState === 'create'">
<v-text-field
v-model="editedItem.color"
:disabled="true"
label="Color*"
/>
</div>
<div v-else>
<v-color-picker
id="tag-color"
v-model="editedItem.color"
:default="'#FF0000'"
:disabled="formState === 'view'"
class="elevation-0"
label="Color*"
hint="*Required"
mode="hexa"
hide-canvas
/>
</div>
</v-col>
</v-row>
</template>
</work-custom-table>
</template>
Any help would be great!
Upvotes: 1
Views: 12465
Reputation: 90188
<v-text-field>
is just a wrapper around an html <input>
.
And in Vue, on <input>
s, v-model
and value
are mutually exclusive. value
is only read when you don't have two-way data binding (using v-model
).
Which means all you need to do is provide the default value in the editedItem
itself, before passing it to the <v-text-input>
(and remove default
& value
). Example:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
formState: 'create',
editedItem: {
color: '#FF0000'
}
})
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>
<div id="app">
<div v-if="formState === 'create'">
<v-text-field v-model="editedItem.color" :disabled="true" label="Color*" />
</div>
</div>
Obviously, if editedItem
is coming from another component or from an external API, you'll have to intercept it and populate the default value of color
on it if color
does not have a truthy value. A generic example:
methods: {
getEditedItemFromApi() {
this.$http.get('some/api/url')
.then(r => this.editedItem = ({
...r.data,
// assumming the API returns the editingItem object
color: r.data.color || '#FF0000'
}));
}
}
(we're destructuring the response data and adding color
property to all its existing properties, with a value of its own color
property if it's anything truthy or the default value if it's falsey.
The gist of it is: you have to populate the default value on the actual property bound to v-model
, prior to passing it to the <input>
.
Here's the relevant part of Vue documentation on v-model
.
And, to cover all cases, here's how you'd use a computed
with set
and get
, allowing you map default values:
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: '#app',
data: () => ({
items: [
{ id: 'one', color: 'black' },
{ id: 'two' }
],
selectedItem: null
}),
computed: {
editingItem: {
get() {
return { ...this.selectedItem, color: this.selectedItem?.color || '#FF0000' };
},
set(item) {
this.selectedItem = item;
}
}
}
})
.flexer {
display: flex;
align-items: center;
}
.flexer span {
width: 1em;
height: 1em;
border: 3px solid;
border-radius: 50%;
margin-left: .5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<select v-model="selectedItem">
<option :value="null">Select item</option>
<option v-for="item in items" :value="item">{{item.id}}</option>
</select>
<div class="flexer" v-if="selectedItem">
<input v-model="editingItem.color" :disabled="true" />
<span :style="{ borderColor: editingItem.color }" />
</div>
<pre v-html="{ selectedItem, editingItem }" />
</div>
This would also cover the case when it's coming as prop
, from a parent.
Upvotes: 1
Reputation: 82182
My solution has little to do with VUE, but hopefully it can help someone, I hit that a personal state where you start looking for other solutions.
The problem is that on 'create' the color-picker was returning an array, where on edit, it was returning the hex value, so my (maybe a little hacky) solution was to set a default value for the color value initially, and then set color on edit.
But instead of manipulating vue vars with getters and setters,
I went into my Laravel API FormRequest instance, and you can prepare your data before validation using prepareForValidation()
method.
I did this:
protected function prepareForValidation(){
if(gettype($this->color) == 'array'){
$this->merge(['color' => $this->color['hex']]);
}
}
I was able to check for an array, and if array, parse out the value. Sadly, I was not able to get the get and set to work for me.
Thanks!
Upvotes: 0