Vue.js2 v-for separate protperties - vuejs2

With the code below, if I press the "Edit" button, I change the disabled state all the rows, how can I separate this? I mean, once i just want to edit one row.
cols="12"
class="contact-container"
v-for="contact in contacts"
:key="contact.id"
>
<b-form inline>
<b-input
type="text"
:value="contact.name"
:disabled="editMode ? disabled : ''"
/>
<b-input
type="tel"
:value="contact.phoneNumber"
:disabled="editMode ? disabled : ''"
/>
<b-input
type="email"
:value="contact.email"
:disabled="editMode ? disabled : ''"
/>
<b-input
type="text"
:value="contact.title"
:disabled="editMode ? disabled : ''"
/>
<b-button-group>
<button type="button" size="lg" class="btn">
<b-icon-x-circle-fill variant="danger"></b-icon-x-circle-fill>
</button>
<button type="button" size="lg" class="btn" #click="startEdit">
<b-icon-pencil-fill variant="primary"></b-icon-pencil-fill>
</button>
</b-button-group>

Assuming that editMode is part of the components' data. If it's a prop this solution might be a bit tricky to implement.
Set up editMode as an empty object in your component's data. And for the method startEdit it should take, as a parameter, the id of the contact being edited.
So something like this: #click="startEdit(contact.id)". and in the method body, this.$set(this.editMode, contact.id, true). See Reactivity in Depth in Vue docs for information on this.$set.
To check if a row is disabled use :disabled="editMode[contact.id]" (no need for ternary operator checking as it's a boolean)
This approach will make it possible to edit multiple rows at the same time. Though a name such as editedContacts might be better in this case.

Related

vue-formulate group custom remove not working

I have a piece of code that use Vue-Formulate with group feature and I try to implement custom button to remove nested items;
<FormulateInput
type="group"
:name="field.name"
v-bind="field.attributes"
remove-position="after"
>
<div ....>
<div .... v-for loop>
<FormulateInput
:type="_field.type"
:name="_field.name"
....
/>
</div>
</div>
<div slot="remove"> <!-- adding slot to customize remove -->
<FormulateInput
type="button"
>
Remove Student
</FormulateInput>
</div>
</FormulateInput>
Such addiction change default <a ...> link to button but functionality of removing item being lost.
Documentation of this slot says:
"The remove button when repeatable. The context object in this slot
includes the index and a removeItem function that should be called to
remove that item."
I am not sure how to add removeItem function call to it.
The removeItem slot prop is only provided to repeatable groups, so make sure to set repeatable on the FormulateInput with type=group.
To insert a custom remove-button in the remove scoped slot, wrap the button in a <template v-slot:remove="{ removeItem }">, and set removeItem as the button's click-handler via the v-on directive (#click for shorthand):
<FormulateInput type="group" repeatable 1️⃣>
<FormulateInput name="name" label="Student’s name" />
<FormulateInput type="email" name="email" label="Student’s email" />
2️⃣
<template v-slot:remove="{ removeItem }">
<FormulateInput type="button" #click="removeItem"> Remove Student </FormulateInput>
</template>
</FormulateInput>
demo

How to update an ancestral element class in response to child input change with Vue.js?

I'm using Vue (v2.6.11) and I want to add/remove a class on an ancestor (grandparent) element of an input (checkbox) when it's value is changed. There are an unknown number of checkboxes so they are generated using v-for on the element that I want to add/remove the class. I have a function registered with my Vue instance methods when the checkbox value is changed.
In my code below, the <label> is the element to which I want to add/remove the class in response to the checkbox value changing. I'm trying to resist the urge to apply an :id attribute to the label and then do a lookup in my updateCounter method that will use the id of the checkbox to find the label and add/remove the class using pure JS. Is there a more Vue-esque way to do this?
<label class="item"
v-for="item in myItems"
v-bind:key="item.id"
:for="'item'+item.id">
<div>
<input type="checkbox"
:id="'item'+item.id"
v-model="item.isAccepted"
#change="updateCounter($event)" />
<span>{{ item.name }}</span>
<span>{{ item.status }}</span>
</div>
<div>{{ item.date }}</div>
</label>
just use a dynamic class like so: :class="item.applyClass ? 'item' : ' ' " so put a property on the item and then you can dynamically change that in your updatedCounter function
You can do
<label class="item"
v-for="item in myItems"
v-bind:key="item.id"
:for="'item'+item.id"
:class="{test: item.isAccepted === true}">
<div>
<input type="checkbox"
:id="'item'+item.id"
v-model="item.isAccepted"
#change="updateCounter($event)" />
<span>{{ item.name }}</span>
<span>{{ item.status }}</span>
</div>
<div>{{ item.date }}</div>
This would apply test class only when is Accepted is true for that particular checkbox.

V-if in a bootsrap vue form

I am trying to render different form elements (placeholder and submit action) in a bootstrap vue form. Here is the form:
<template>
<b-form-input
v-if="input"
placeholder="Name Your Swatch, Enter and Save Edit"
#keypress="republishSwatch"
v-model="value3"
ref="value3"
id="name"
size="lg"
type="text"
class="search-bar"
/>
<b-form-input
v-else
placeholder="Name Your Swatch and Enter to Save"
#keypress="publishSwatch"
v-model="value3"
size="lg"
ref="value3"
id="name"
type="text"
class="search-bar"
/>
</template>
This works, and the default form shows, collects the name etc and runs the publishSwatch function. The other form I want to use when someone is editing the swatch and changing the colors/name, using either the setName or the republishSwatch function so need some kind of condition in there to get it to show instead of the default one. At this point the the Save Edit (id saveBtn) button is showing in the DOM (shows after clicking the edit button) so wondered if I could somehow use that as a reference in condition, as its not there normally. The condition there at the moment doesn't seem to do anything, the default form shows, which is what I want to start with.
Any tips welcome
Thanks
Because your 2 situations(v-if/v-else) are very different, you should duplicate your b-form-input, by this way, you give v-if to the 1st one and v-else to the other one.
<template>
<b-form-input
v-if=""
placeholder="Name Your Swatch and Enter to Save"
#keypress="publishSwatch"
/>
<b-form-input
v-else
placeholder="Name Your Swatch, Enter and Save Edit"
#keypress="republishSwatch"
v-model="value3"
ref="value3"
id="name"
size="lg"
type="text"
class="search-bar"
/>
</template>
With simpler examples, i.e. only a the placeholder which changes, you could do that
<template>
<b-form-input
:placeholder="test ? placeholder1 : placeholder2"
/>
</template>
<script>
export new Vue({
data() {
return {
test: true,
placeholder1: 'hi',
placeholder2: 'bye',
};
}
});
</script>
If you mutate test, the input placeholder will automatically change.

vee-validate not working with bootstrap-vue

I'm trying to use vee-validate for form validation with bootstrap-vue, and cannot get anything to work. Basically, I want to do:
<b-form-input v-model="emailText"
placeholder="Enter email"
v-validate="'required|email'"
name="email"
type="text">
<b-row>
<span>{{ errors.first('email') }}</span>
</b-row>
</b-form-input>
But I don't see anything when I type a non-email address in the field. However, if I change:
b-form-input to input
then everything works. Is there a workaround for this behavior? Any help would be greatly appreciated.
You have put the error messages inside the <b-form-input>, which has no internal slot, so the error messages aren't rendered. If you move them to after the input, it should fix your issue:
<b-form-input v-model="emailText"
placeholder="Enter email"
v-validate="'required|email'"
name="email"
type="text">
</b-form-input>
<b-row>
<span>{{ errors.first('email') }}</span>
</b-row>
You can also use Bootstrap-Vue's state and invalid-feedback properties on the <b-form-input> and a surrounding <b-form-group> to display validation errors with a better accessibility. All of this is demonstrated in this codepen

Vuelidate how to conditionally disable submit button

How can I conditionally disable the submit button of my Vuelidate form if all the fields don't meet the required criteria?
I tried the below but :disabled will only accept the word disabled in there.
<form>
<ol>
<li class="inputQuestion" v-bind:class="{ 'error': $v.user.username.$error }">
<label>Username:</label>
<input v-model.trim="user.username" #input="$v.user.username.$touch()" />
</li>
<li class="inputQuestion" v-bind:class="{ 'error': $v.user.password.$error }">
<label>Password:</label>
<input v-model.trim="user.password" #input="$v.user.password.$touch()" />
</li>
<li class="submission">
<button #click.prevent="submitForm" :disabled="$v.form.valid()">Sign In</button>
</li>
</ol>
</form>
Currently, you are binding disabled to the value returned by $v.form.valid(), which will only be run once when the component's template is rendered and won't change after that point.
From the Vuelidate documentation, it looks like you are provided a $invalid property for the form model which:
Indicates the state of validation for given model. becomes true when any of it's child validators specified in options returns a falsy value. In case of validation groups, all grouped validators are considered.
Use that instead:
<button #click.prevent="submitForm" :disabled="$v.form.$invalid">
Another way to disable/enable the submit button with vuelidate:
<button #click.prevent="submitForm" :disabled="$v.$anyError">