How can I make the placeholder of a button dynamic in Vue? - vue.js

At this moment, I have a component which is a component for a Selectbox which is used throughout the application. I want to set the placeholder dynamically, so that you can use the button wherever you want, and I know you can do this with Vue Slots, but I don't know how:
For example, I want to achieve this:
<SDSelectBox>Amount of Items</SDSelectBox>
and another use case
<SDSelectBox>How many items do you want?</SDSelectBox>
which basically replaces the placeholder of the item.
Thanks in advance.

You can make the placeholder dynamic by passing a prop to your component and then setting the placeholder to the value of the prop.
Like so:
<SDSelectBox :placeHolder="someValueFromCurrentComponent"></SDSelectBox>
//Inside the SDSelectBox
<template>
<select>
<option value="" disabled selected>{{placeholder}}</option>
...
props: ['placeHolder'],
Or with a slot you can simply insert into the SDSelectBox:
<select>
<slot></slot>
...
//parent component
<SDSelectBox>
<option value="" disabled selected>{{placeholder}}</option>
</SDSelectBox>

Related

how to use template in vue3 instead of native template?

I'm tring to make a SelectBox component
<Options>
<Option
v-for="person in people"
:value="person"
>
{{ person.name }}
</Option>
</Options>
And I want Option to be a dynamic component:
<component :is="props.as || 'li'">
<slot />
</component>
So I can custom content in Option (not only with <li> tag), for example use div or template to render
<Options>
<Option
v-for="person in people"
:value="person"
as="template"
>
<li>
<span>{{ person.name }}</span>
<span>other</span>
</li>
</Option>
</Options>
But if prop.as is 'template', it's rendered in html native template and can't see it in browser
I expect the result:
Vue document show some detail
But it can't work for me to add any director on it, like this
<component
:is="props.as || 'li'"
v-if="true"
>
Anyone can help me?
You probably shouldn't be using the component tag for what you're trying to do.
According to the Vue docs, here are the options of what you can pass for the is prop:
The actual component to render is determined by the is prop.
When is is a string, it could be either an HTML tag name or a component's registered name.
Alternatively, is can also be directly bound to the definition of a component.
You are trying to pass a template instead of a Vue component, which component is not designed to work with. It is unclear exactly what you are trying to do, but you can probably use a slot to accomplish it. Otherwise, to get the component tag working, define a Vue component and pass that in.

How can we use v-for and v-if in the same element?

I am building a component in which I have to iterate over each action and check conditions on each action. So, how can I use v-for and v-if in the same element?
The Vue.js Style Guide recommends against this:
Never use v-if on the same element as v-for.
There are two common cases where this can be tempting:
To filter items in a list (e.g. v-for="user in users" v-if="user.isActive"). In these cases, replace users with a new computed property that returns your filtered list (e.g. activeUsers).
To avoid rendering a list if it should be hidden (e.g. v-for="user in users" v-if="shouldShowUsers"). In these cases, move the v-if to a container element (e.g. ul, ol).
Your best option is to use a <template> tag for your v-for and apply your v-if inside that on whichever HTML tag you're using. For an instance:
<template v-for="(user, index) in users">
<div v-if="user.isActive" :key="index">
// your HTML code here
</div>
</template>
or use a computed value as mentioned in the docs. For example, something like this:
computed: {
activeUsers() {
return this.users.filter(user => user.isActive)
}
}
Without seeing an example of your current code, I could only guess how you might adapt the above to suit your individual needs.

When to use prop modifier in vue?

When to use prop modifier in vue?
In vue document,I find the prop modifier in v-bind here: https://v2.vuejs.org/v2/api/#v-bind
my question is this:
https://v2.vuejs.org/v2/api/#v-bind
From the docs:
Modifiers:
.prop - Bind as a DOM property instead of an attribute (what’s the difference?). If the tag is a component then .prop will set the property on the component’s $el.
This is useful, because some HTML inputs can't receive a value as attribute, but need to be passed on the ref itself.
See for example the indeterminate state of a checkbox. Normally you'd need to do
<template>
<!-- this doesn't work, because there's no indeterminate prop on the checkbox, it only exists on the DOM element -->
<input type="checkbox" :indeterminate="indeterminateProp" />
</template>
<script>
beforeUpdate() {
//set indeterminate directly on the dom element object
// this is what you'd always have to do if v-bind.prop didn't exist
this.$refs.myCheckbox.indeterminate = this.indeterminateProp;
}
</script>
and keep track of it manually outside of vue's reactivity system.
But thanks to .prop, you can just do
<input type="checkbox" :indeterminate.prop="indeterminateProp"/>
Without having to play with lifecycle hooks.
So .prop basically tells vue "apply this value on the DOM node itself (the one you'd normally get from $refs) instead of trying to apply it as an attribute or property"
You can use this modifier to pass a property to a component.
<myComponent v-bind:<PropName></myComponend> is the same as <myComponent :<PropName>></myComponend>
Checkout this link here: https://v2.vuejs.org/v2/guide/components-props.html.

Is it possible to find a Vue component based on its "el"?

Suppose I have this component:
<b-select id="selectfield" :src="['a', 'b']"></b-select>
Which renders into:
<select id="selectfield">
<option value="a">a</option>
<option value="b">b</option>
</select>
Can I "find" the instance for my b-select component based on its "el" (which in this case would be its id)?
I don't know if it's possible with the "public" API but you can get the Vue instance from the __vue__ DOM property of any element that is a root mount for a component.
document.getElementById('selectfield').__vue__
As to whether or not you should use it.. Vue's author says the Vue devtools rely on it, so it's unlikely to change. See https://github.com/vuejs/vue/issues/5621

Vuex nested loop, how to handle v-model on select/option

In my application I need to use a nested v-for to display a list of elements with a select-option.. This is the scenario
<div class="stuck" v-for="box in items">
<p>Pick an option for this box:</p>
<select v-model="box">
<option v-for="package in packages"
:value="package.id">{{ package.name }} </option>
</select>
</div>
The variable items come from Vuex store. In this way, i'm getting the error:
You are binding v-model directly to a v-for iteration alias. This will
not be able to modify the v-for source array because writing to the
alias is like modifying a function local variable. Consider using an
array of objects and use v-model on an object property instead.
With this in mind, i'm going to change the code like so:
<div class="stuck" v-for="box in items">
<p>Pick an option for this box:</p>
<select v-model="box.id">
<option v-for="package in packages"
:value="package.id">{{ package.name }} </option>
</select>
</div>
I've just changed the select v-model from the alias box, to the right id: box.id
In this way, all works... or... half works. Because, if i'm going to pick an option from the select, i got another error:
[vuex] Do not mutate vuex store state outside mutation handlers.
This is correct, because the v-model is bind to box.id (that is not an alias but a real value). But, when i pick an option the v-model "try" to change box.id that come from Vuex store.
Now, in a simple scenario i will create a computed property for set/get to avoid vuex store mutation.
But... here i have a nested loop, so i cant create a computed on 'box.id'.
Do you have a solution for this ?
Thanks a lot!
you could try a different data flow pattern.
Your select listens to the store (but does not directly update it)
<div class="stuck" v-for="box in items">
<p>Pick an option for this box:</p>
<select :value="box.id" #change="updateBox">
<option v-for="package in packages" :value="package.id">
{{ package.name }}
</option>
</select>
</div>
Then you create a method that fires whenever the selected option changes
updateBox(e) {
const id = e.target.value;
this.$store.commit('changeYourBox', id);
},
This function should commit a vuex mutation that alteres the box id. So you'd need that mutation too.
Once the store value updates, your components box object updates and the select that listens to that store will update it's selected value accordingly.
That way, you can alter the store value from anywhere and the selected value will change as well.
with usage of mine library vuex-dot in this situation you can do so:
let's go with such state
{
state: {
boxes: []
},
mutations: {
editBox(state, {target, key, value}) {
Vue.set(target, key, value);
}
}
};
So let's create additional component BoxEdit:
<template>
<div class="stuck">
<p>Pick an option for this box:</p>
<select v-model="id">
<option v-for="package in packages"
:value="package.id">{{ package.name }} </option>
</select>
</div>
</template>
<script>
import { take } from 'vuex-dot'
export default {
props: ['box', 'packages'],
computed: {
...take('box')
.expose(['id'])
.commit('editBox', true)
.map()
}
}
</script>
and now you can make simply write
<box-edit v-for="box in boxes" :box="box" :packages="packages"></box-edit>
in your subject component template.
link to library site: https://github.com/yarsky-tgz/vuex-dot