Set Vuetify Datepicker allowed-dates range after mount - vue.js

I'm wanting to pass through an array of allowed dates into my Datepicker as follows:
HTML:
<v-date-picker
v-model="dates"
:allowed-dates="disabledDates"
>
</v-date-picker>
JavaScript:
disabledDates: val =>
this.bookingDates.indexOf(val) === -1,
However the disabledDates method is being called when the Datepicker is rendered (before mount) and thus this.bookingDates does not exist yet. Is there a way to render the Datepicker only after the this.bookingDates array has been populated?

Related

how can i access data property in html template using loop in vue js

i'm trying to use data property commentsToShow in my html template to limit the amount of data that displays on my webpage
this is my template
<div v-if="index < products.length" v-for="(commentIndex, index) in computedProduct">
<div class="title pt-4 pb-1">{{products[index].title}}</div>
</div>
if i add commentsToShow in my for loop i get one product but the computed products doesn't work same way the other way round
this my script tag
<script>
export default {
data() {
return {
commentsToShow: 1,
totalComments: 0,
};
},
computed: {
computedProduct() {
let tempRecipes = this.products;
if (this.filterPrice !== "true");
}
};
</script>
if i change computed property to commentsToShow this the error i get in my console
The computed property "commentsToShow" is already defined in data.
please how can i get the value of commentToShow in my template
according to vue's official docs it's not recommended to use v-for and v-if on the same element
try using v-if on a wrapper div or template element
<div v-for="(commentIndex, index) in computedProduct">
<template v-if="index < products.length">
<div class="title pt-4 pb-1">{{products[index].title}}</div>
</template>
</div>
v-if has higher priority so it's executed first and index will not be defined yet.
also you have to return something on your computed property function in order to use it
You can use the slice method on a computed property, like this:
<script>
export default {
data() {
return {
commentsToShow: 1,
allComments: []
};
},
computed: {
listComments() {
return allComments.slice(0, commentsToShow);
}
};
</script>
You can also use pages to show the comments, in this case you can return like this:
return allComments.slice((currentPage - 1) * commentToShow, commentsToShow);
The first argument of slice is the start index, the second is the number of elements to get
The computed property "commentsToShow" is already defined in data.
Equivalently how you cannot have more than one variable with the same name defined in a scope. A computed property cannot have the same name as an existing data property. Essentially, they co-exist in the same namespace, thus they have to be unique.
You have a name clash, and that is what the error is saying.

Vuetify Treeview - set default selected when option items are retrieved asynchronously

I have a Vuetify TreeView component used across the app for which I need to be able to pass in a list of selected values alongside the option list.
The option list is retrieved using an http call. The problem is that the vuetify tree view component doesn't show the selected items when the option item list is not initialized before the selected list
See this codepen - https://codepen.io/amaieras/pen/eYVZJJq?editors=101
While if I initialize the items directly in the data, the default selected items appear as selected in the tree component - https://codepen.io/amaieras/pen/bGLpEBx?editors=101
<v-treeview
ref="tree"
v-model="selectedTerms"
:class="contentClass"
:filter="filter"
:indeterminate-icon="'far fa-minus-square'"
:items="applicabilityTagsValues"
:on-icon="'ph-square-logo-fill'"
:open.sync="expanded"
:search="searchValue"
class="dropdown-treeview"
selectable
selected-color="neutral lighten-4"
#input="emit('input', $event)"
>
</v-treeview>
store
.dispatch('businessContextRequirements/getApplicabilityTagsFilters',
filtersValuesPayload.value
).then((resp) => { applicabilityTagsValues.value = resp })
I can use a force mechanism to rerender the treeview component, but I am wondering if there is another way of making the component to render the selected nodes using vue's reactivity?
Using force mechanism
<v-treeview
ref="tree"
:key="dropdownKey"
v-model="selectedTerms"
:class="contentClass"
:filter="filter"
:indeterminate-icon="'far fa-minus-square'"
:items="applicabilityTagsValues"
:on-icon="'ph-square-logo-fill'"
:open.sync="expanded"
:search="searchValue"
class="dropdown-treeview"
selectable
selected-color="neutral lighten-4"
#input="emit('input', $event)"
>
</v-treeview>
setup() {
const dropdownKey = 0
store.dispatch('businessContextRequirements/getApplicabilityTagsFilters',
filtersValuesPayload.value
).then((resp) => {
dropdownKey++;
applicabilityTagsValues.value = resp
})
return {
dropdownKey,
applicabilityTagsValues
}
}

Access next index object's value within a loop - Vue JS

I wanted to check for a condition if a particular property of an object is same as the very next object's property in an array-of-objects, iterated through a v-for loop.
Sample JSON object:
[
{ Date: '21-July-2017', ...},
{ Date: '21-July-2017', ...},
{ Date: '25-July-2017', ...},
...
]
The requirement is to check if each consecutive Date value is same, so that we will hide the Date header in the UI.
<div v-for="(everyDay, dayIndex) in eachPost.values" v-bind:key="dayIndex">
<div v-if="everyDay['Date'] !== eachPost.values[dayIndex+1].Date">
THIS DOESN'T WORK
</div>
</div>
Is there an alternative to accomplish this req?
Your problem is when you get to your last item in the array your dayIndex+1 object does not exist. It is undefined. What you need to do is in your template determine if your object is defined and go from there.
<div v-for="(everyDay, dayIndex) in eachPost.values" v-bind:key="dayIndex">
<template v-if="eachPost.values[dayIndex+1]">
<div v-if="everyDay['Date'] !== eachPost.values[dayIndex+1].Date">
THIS WORKS
</div>
</template>
</div>
Here is a jsFiddle of my working example

How to encapsulate / wrap a VueJS component?

Hi everybody, please pardon my english :-)
I have a Vue component that can take dynamic slots (the names of the slots will depend on a props).
I use it on several places and some of the slots are always present.
To avoid redundancy, I'm looking for a way to create a component that "wrap" the final component to allow me to define only the additionals slots.
If there is an "obvious" way to achieve it, I may have missed it :-)
Code example
Without a "wrap component"
<b-table
show-empty
small
hover
[...some others and always present props...]
:items="aDataVarThatWillChangeBasedOnTheContext"
[...some others and uniq props...]
>
<template slot="same-1">
A slot that will always be present with the same content (for example, a checkbox in the first column)
</template>
<template slot="same-2">
A slot that will always be present with the same content (for example, some action buttons in the last column)
</template>
[...some others and always present slots...]
<template slot="not-the-same">
A slot that is only used in this context (for example, a duration based on a row timestamp and a timestamp picked by the user)
</template>
[...some others and uniq slots...]
</b-table>
With a "wrap component"
<my-b-table
:items="aDataVarThatWillChangeBasedOnTheContext"
>
<template slot="not-the-same">
A slot that is only used in this context (for example, a duration based on a row timestamp and a timestamp picked by the user)
</template>
</my-b-table>
Note: The dynamic slot name is not predictible.
If I suddenly need a "foo" column, I should be able to pass a "foo" slot (and a "HEAD_foo" slot, in my case)
Some researches
I read here that:
They’re (the functionnal components) also very useful as wrapper components. For example, when you need to:
Programmatically choose one of several other components to delegate to
Manipulate children, props, or data before passing them on to a child component
And "Manipulate children, props, or data before passing them on to a child component" seems to be exactly what I need.
I looked on render function but a lot of things seems to be not implemented, like the v-model, and I have difficulties to figure out how to pass dynamic slots...
Thank you in advance for your(s) answer(s) !
up: At the 07.03.2018 I still dont have any idea about how to solve this case
Found the answer that was somehow unclear to me that month ago.
("Dynamic" means here "not explicitely declared by the component, but gived by the parent")
Wrapper component
Props and scoped slots can be gived dynamically by the options object of createElement function.
"Simple" Slots can be gived dynamically by the childs array of createElement function.
Wrapped component
Props can't be dynamic unless the component is functional.
Slots can always be retrieved dynamically.
Scoped slots can be retrieved only if the component isn't functional.
Conclusion
It's not possible to have dynamics props and scoped slots at the same time...
But it's possible to declare all the needed props and then to use a "non-functionnal" component as wrapper and as wrapped.
How to
Retrieve from non-functional component
var component = Vue.component('component-name', {
props: ['name', 'of', 'the', 'props'],
// [...]
aMethod: function () {
this._props // all the declared props
this.$slots // all the slots
this.$scopedSlots // all the scoped slots
}
});
Retrieve from functional component
var component = Vue.component('component-name', {
functional: true,
render: function (createElement, context) {
context.props // all the props
context.children // all the slots as an array
context.slots() // all the slots as an object
}
});
Give to child component
var component = Vue.component('component-name', {
render: function (createElement) {
return createElement(
childComponent,
{
props: propsToGive,
scopedSlots: scopedSlotsToGive
},
[
// non-scoped slots to give
createElement('slot-tag-name', {slot: 'slot-name'})
]
);
}
});
References
https://v2.vuejs.org/v2/guide/render-function.html
https://v2.vuejs.org/v2/guide/render-function.html#createElement-Arguments
https://v2.vuejs.org/v2/guide/render-function.html#Functional-Components
Sandbox
https://jsfiddle.net/5umk7p52/
Just make a regular component out of your customized <b-table>.
You'll need to define an items prop for your component to pass as the items for the <b-table> component.
And, to define a slot for your component, you'll need to use the <slot> tag, specifying the name using the name attribute.
If you'd like to make one of the slots from the <b-table> component accessible in the <my-b-table> component, simply pass a <slot> tag as the content of the slot in your custom component.
It would look something like this:
Vue.component('my-b-table', {
template: `
<b-table
show-empty
small
hover
:items="items"
>
<template slot="same-1">
Content to pass to the b-table's slot
</template>
<slot name="not-the-same">
A slot that is only used in this context
</slot>
<template slot="last_edit">
<slot name="last_edit">
A slot to pass content to the b-table component's slot
</slot>
</template>
</b-table>
`,
props: { items: Array },
});

Multiple instances of a vue.js component and a hidden input file

I am experiencing a weird behavior using Vue.js 2.
I have a component that I reference twice in a single html page.
This component contains an input file control called attachment_file. I hide it using the Bootstrap class hidden and I open the file selection using another button. When a file is selected, I put in a variable called attachment_filename a certain string just like so:
<template>
<div>
<button #click="selectAttachement"><span class='glyphicon glyphicon-upload'></span></button>
<input id="attachment_file" type="file" class="hidden" #change="attachmentSelected">
{{attachment_filename}}
</div>
</template>
<script>
export default {
data () {
return: {
attachment_filename: null,
}
},
methods: {
selectAttachement () {
$('#attachment_file').click();
},
attachmentSelected () {
this.attachment_filename = 'some file here';
},
}
}
</script>
Problem With the class hidden and when a file is selected from the 2nd instance of the component, the value of this.attachment_filename is updated but in the data of 1st instance of the component!
If I remove the class hidden, it updates the value in the correct instance.
Possible solution use css opacity or width instead of the class hidden.
But is there a reason for this behavior?
Not sure why it is not working specifically with .hidden, but you have an inherent problem in the code that i think is the cause of the problem.
You are selecting the input using jquery with an id, that creates a couple of problems:
When you use the component twice or more, all these inputs generated by these components will have the same id, which is not what you want since id should be unique
Even if you change it to a class instead of id, it won't work properly since you are selecting the element using jquery, and that will select all the elements with this class, while you want to select just the input in that component.
The solution is to use refs:
<input id="attachment_file" type="file" class="hidden" #change="attachmentSelected" ref="fileInput">
selectAttachement () {
$(this.$refs.fileInput).click();
},