v-select : cant show the seleted element - vue.js

Im using Vuetify in my project. When I insert some data by v-select its working fine. Also when Im edit that data that also works. The only problem is I cant see the selected element when Im click on Edit.
Here is my code
<v-select
prepend-icon="star_rate"
:items="ratings"
v-model="customer.rating"
label="Rating"
item-text="text"
item-value="customer.rating"
single-line
></v-select>
Note: If I use {{customer.rating}} it gives an output like this
{ "id": 1, "text": "Bad" }
and If I select a different element its perfectly change on database. So everything is fine. The only requirement is I want show this value Bad as a selected element when I click on Edit.
Here is the complete code of my project file https://github.com/Shakilzaman87/pukucrm/blob/master/src/components/customers/EditCustomer.vue
Thanks in advance

It's and old question but Let me post my answer to help others as well, after alot of search I have come to this point, and I want to share it with others as well.
//This will load all your ratings in dropdown
<v-select
v-model="customer.ratings"
:items="ratings"
item-text="text"
item-value="id"
label="Rating"
dense>
</v-select>
Now Edit Part
Lets say you want to edit a record, so you will probably pass the record id in edit method of your vuejs then inside edit method of vuejs, you will do an edit axios call for that specific record to first show it inside fields and then you will update. But before update you need to do something inside edit method of your vuejs when you will have already loaded data for that specific id.
Now lets say you have received a record from database according to a specific id, you will see a dropdown id I mean to say a foreign key for a dropdown that you had saved during storing data.
Suppose you have ratings array which holds whole data for a dropdown. Inside this you are having an id and text fields. So you have this ratings array and an object from database during edit for a specific record. Now you are good to go with below code.
Inside Edit Method of vuejs
this.customer.ratings = this.ratings.find(item => item.id === parseInt(res.data.rating_id))
this.customer.ratings = parseInt(this.customer.ratings.rating_id)
Note: I am doing parseInt() it's because when you check in console the primary key is an integer like 1 but foreign key like rating_id is string i-e "1". You can also use two equals == if you are not using parseInt() but I haven't checked that.
For clearly understanding I am just sharing a sample edit code which might help you a bit
editItem(id){
axios.get( `/api/category/${id}` ).then( res => {
if(res.data.status === 200){
console.log(res.data.data)
this.name = res.data.data.name
this.id = res.data.data.id
this.parent_id = this.list_categories.find(item => item.id === parseInt(res.data.data.parent_id))
this.parent_id = parseInt(this.parent_id.id)
this.edited = true
}else{
this.$toaster.error( res.data.message )
}
});
}

I'm not sure what you mean by "... when Im click on Edit." but I will presume you mean when you click on the dropdown menu.
From what you have provided in your jsfiddle, your v-select should be like this:
<v-select
prepend-icon="star_rate"
:items="ratings"
v-model="customer.rating"
label="Rating"
item-text="ratings.text"
item-value="ratings"
single-line
></v-select>
This can be found here, in the API props section.
item-text: Set property of items’s text value
item-value: Set property of items’s value
The text is what you see, I believe that text which is the current value of item-text is either undefined or not declared. If this answer doesn't work, then you need to provide more of your code.

Related

How to sort vuetify datatable only on header click?

In a v-data-table, I have one column with a simple text field, this column containing the text field is sortable. The problem is that when I change the value in the text field, the data is immediately re-sorted and in my case the lines change and in the worst case the line change and the focused input changes too, like in this example: codepen reproduction
For reproduction:
click on the iron header to sort the iron column
change one input
see that the line changed its position and that you're not anymore in the same field
Expected behavior:
sort the iron column
change one input
see that the line didn't change its position and you can keep modify the input
click sort again to reorder the data once you're done.
Is there a way of behaving like in the expected behavior?
Thank you very much for the answers
It looks like you should use a different event on the <v-text-field> component to listen for changes instead of using v-model to bind changes automatically to props.items.iron. Text Field Event Docs here
You could do something like using the blur event so it only updates when your user focuses away from the text field:
<v-text-field
#blur="updateIron"
:rules="[max25chars]"
label="Edit"
single-line
counter
autofocus
></v-text-field>
then in your JS file you'd add a method like this:
methods: {
// ...other stuff here
updateIron(val) {
this.item.iron = val
}
}
Try experimenting with different events to update your values at the appropriate time.
So I found the answer to that, which consist of redefining the header:
I use the slot header.iron in order to redefine a sortIron method only on click : basic demo
What I'll have to do next is to redefine arrows, style, 'asc' and 'desc'
I'm still open to other ways of doing it!
But right now I can follow my wanted behavior which is :
sort the table via the iron column
change one field
press tab, on the next field enter a value
repeat previous step until you're done
finally re-sort the table only by clicking the header

How to programmatically expand all rows in a v-data-table component (Vuetify version 1.5)

v-data-table component has a propery "expanded" that allows to show some additional info for each row.
It works fine and I need to expand all the rows immediately when a page is loaded.
Is there a way to do that?
It is used version 1.5 of Vuetify Framework.
https://v15.vuetifyjs.com/en/components/data-tables
This is fairly easy in the new Version of Vuetify, you just use the property expanded which holds an Array of the items that are currently expanded.
<v-data-table
id="issues-table"
:value="selectedIssues"
:expanded="expandedIssues"
:items="issues"
>
<v-switch #change="(v) => expandAllIssues(items, v)" />
expandAllIssues (items, status) {
if (status) {
this.expandedIssues = items
} else {
this.expandedIssues = []
}
}
In V1.5.xx of Vuetify you don't have that luxury, but when I took a look, Vuetify works with a similar system under the hood. Firstly you should set the expand prop on the table to true, so it can expand multiple rows.
You can define a reference on your data table and then access it via this.$refs.myDataTableRef. You then realise that they store the expanded rows in an Object called expanded. You can set the rows either true by the id/name of the row in this object or you simply set the whole row objects in the vuetify expanded object to true.
I have pasted the Codepen example of their old data table and made a simple expand all button, that you can obviously change to your desires, but it should make the concept clear.
Codepen example

Dynamically updating v-combobox items list

Is it possible somehow to update Vuetify v-combobox items as the user is typing? I want to change the list of available items depending on what the users started typing, to create an address input with suggestions from a geolocation API.
This is what I tried: #update:search-input='fetchAddresses'
And in fetchAddresses: this.items = newListOfItems
However, while #update:search-input fires as expected, the combobox list will only be updated after losing focus. Can I somehow trigger it to be updated? (This may very well be an X/Y problem, so any hints about other approaches are welcome)
My current, ugly, hack is to force the whole combobox component to re-render with the current value set, and then refocus on it. (There is an activateMenu() method on the combobox that I could use to make sure the list reopened:
this.$nextTick(() => {
if (this.$refs.addressCombobox) {
this.$refs.addressCombobox.focus()
this.$refs.addressCombobox.activateMenu()
}
})
I'm using Vue 2.
In my case no-filter solved this problem
<v-combobox no-filter ... >

Initially hide first group in Vue-Formulate repeatable group

I'm using Vue-Formulate's Repeatable Groups. For my requirements:
A group is optional to add
If a button is pressed to add a group, then the fields in the group must be validated
The form should not initially show the group; it should show the button to add a group
For example, the desired initial appearance is in the following screenshot, which I generated after clicking the "remove" / X button in the linked codesandbox:
I've mocked this up at codesandbox here: Vue Formulate Group with Button to Start
Is this possible? If so, how?
May 2021 UPDATED WORKAROUND
In #braid/vue-formulate#2.5.2, the workaround below (in Research: A hack that seems to UPDATE: USED TO work) no longer works, using a slot to override the close button, save a ref, and trigger a click does. See also the related feature request at https://github.com/wearebraid/vue-formulate/issues/425.
<script>
export default {
// ... fluff omitted
async mounted() {
await this.$nextTick();
if (!this.hasMessages) {
// See also feature request at https://github.com/wearebraid/vue-formulate/issues/425
this.$refs.closeButton.click();
}
},
};
</script>
<template>
<FormulateInput
type="group"
name="rangeMessages"
:minimum="0"
repeatable>
<!-- See https://vueformulate.com/guide/inputs/types/group/#slots -->
<template #remove="{removeItem}">
<button ref="closeButton" #click.prevent="removeItem"/>
</template>
</FormulateInput>
</template>
Research - Vue-Formulate's Docs
In Vue-Formulate's docs on input with type="group"'s props and slots, there is a minimum prop. I've set that to zero, but that doesn't change the initial appearance. I do see multiple slots, but I'm not quite sure which one to use or if I could use any of them to achieve what I want; it seems like default, grouping, and repeatable might be useful in preventing the initial display of the first group.
Research - Vue-Formulate's Tests
I see that FormulateInputGroup.test.js tests that it('repeats the default slot when adding more', so the default slot is the content that gets repeated. According to the docs, the default slot also receives the index as a slot prop, so that could be useful.
Research - Vue Debugger
The item which I want to initially remove is at FormulateInputGroup > FormulateGrouping > FormulateRepeatableProvider > FormulateRepeatable > FormulateInput:
When I remove the initial item to match the desired initial layout, the group hierarchy changes to:
<FormulateInput><!-- the input type="group" -->
<FormulateInputGroup>
<FormulateGrouping/>
<FormulateAddMore>...</FormulateAddMore>
</FormulateInputGroup>
</FormulateInput>
Based on this change, I would expect that I need to modify FormulateGrouping to get the desired initial appearance, but I haven't found in the source what items are available to me there.
Research: A hack that seems to UPDATE: USED TO work
This hack worked in v2.4.5, but as of 2.5.2, it no longer works. See top of post for an updated workaround.
In the mounted hook, when I first render the form, I can introspect
into the formValues passed to v-model to see if the group lacks an
initial elements that is filled out. If so, then I can make use of a
ref msgs on the FormulateInput of type group to then call
this.$refs.msgs.$children[0].$children[0].removeItem(), which
triggers an initial remove of the (empty) item. This is super hacky,
so I'd prefer a better way, but it kind of works. The only problem is
that it validates the fields when clicking on the button, before any
input has been entered.
This is a fair question, and Vue Formulate used to support the behavior of just using an empty array to begin with, however it became clear that it was confusing to users that their fields would not show up without an empty object [{}] when they bound the model, so a change was made to consider an initial value of an empty array an "empty" field and pre-hydrate it with a value. Once that initial hydration is completed however, you can easily re-assign it back to an empty array and you're good to go. This is easily done in the mounted lifecycle hook:
...
async mounted () {
await this.$nextTick()
this.formData.groupData = []
}
...
Here's a fork of your code sandbox: https://codesandbox.io/s/vue-formulate-group-with-button-to-start-forked-32jly?file=/src/components/Reproduction.vue
Provided solutions weren't working for me but thanks to previous answer I've managed to find this one:
mounted(){
Vue.set(this.formData, "groupData", [])
},
which does same effect as
data(){
formData: {
groupData: [],
},
},
mounted(){
this.formData.groupData = []
},

possible to dynamically add objects to an array and have Vuejs detect it

edit 2
I think the issue is how I'm referring to an array from a parent component. A fiddle is provided in the comments.
I have an app where we want to be able to add items to a menu_header. I have tried pushing to the bottom of the array but Vuejs doesn't seem to be detecting it.
I have read this section https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats and am trying to make this work but I'm not sure if this is possible.
Something like:
var obj = { name: "my name" }
menu_header.items.push(obj);
Do I need to use this.$set syntax? I really need to add into the middle of an array via splice.
edit 1
So this is a component that is recursive (ie a menu_header can have many menu_headers). I have tried adding a simple button in a menu_item to add to the parent component like this:
methods:{
addItem: function(){
var items = this.$parent.$data.menuHeader.menu_items;
var obj = { header: "my header", detail: "this detail"}
console.log("11 items length: " + items.length);
items.splice(1,0,obj);
console.log("22 items length: " + items.length);
},
The count of the number of items is incremented but the view doesn't rerender. This component is nested 3 levels deep (a Menu component has many MenuHeader components which can have many MenuItem components and also have many MenuHeader components). I'm pretty sure it's a reactivity / array issue - but not sure about exact problem.
Really the issue here was that you should use a key with a list in order for Vue to property render it in all cases and when you are iterating over a component you must use a key. The code in the fiddle is properly adding the elements to the array and Vue is detecting the changes, it just doesn't properly render the list because of it's update strategy. Using a key fixes that.
To that end I modified these lines in the template.
<div v-for="menu_header in menu.menu_headers" :key="menu_header.name">
and
<div v-for="(menu_item, idx) in menuHeader.menu_items" :key="menu_item.header">
The best key for these is some unique property of the object in the list. The above uses name and header, but I expect with real code you could come up with a better key.
It's best to get in the habit of always adding a key whenever you render a list in Vue.