Select2 is not working on dynamically added field in Vue.js - vue.js

In my vue laravel application ...i have dynamicllay added some select option by onclick function.
For the intial select option select2 is working fine but when i am trying to added more field dynamically the select 2 is not working . i have used (npm install v-select2-component --save )
but unfortunatlley does not work
<script>
import Select2 from 'v-select2-component';
export default {
components: {Select2},
data(){
return{
event_Category_Remove: [],
index: 0,
eventsElement_id: [],
}
},
methods:{
addEvent() {
this.eventsElement_id = [];
this.event_Category_Remove.push({
id: this.index,
name: "ecr" + this.index,
});
this.index++;
},
/** ========= Remove Event ========= */
removeEvent(index) {
this.event_Category_Remove.splice(index, 1);
},
}
</script>
<template>
<div
class="
form-group
row
without-form-background
mb-2
"
>
<label class="col-md-2 label-control" for="weight"
>Event (can be multiple)</label
>
<a class="text-primary" #click="addEvent">
<i>Add</i> <i class="fa fa-plus"></i>
</a>
</div>
<!-- ======== Adding Multiple Event Button End ======== -->
<!-- ///////////////////// -->
<!-- ======== Event Start ======== -->
<div
class="event_Category_Remove"
v-for="(ecr, index) in event_Category_Remove"
:key="ecr.id"
:id="'eventChild_' + index"
>
<div
class="
form-group
row
without-form-background
mb2
"
>
<label class="col-md-2 label-control" for="name"
>Event</label
>
<div class="col-md-10">
<select
:name="'event_' + index"
id=""
class="form-control"
>
<option
name="event"
v-for="event in event"
:key="event.id"
:value="event.id"
:selected="event.id == event_selected"
>
{{ event.name }}
</option>
</select>
</div>
</div>
<!-- ======== Event Ends ======== -->
<!-- ////////////////////// -->
<!-- ======== Category Start ======== -->
<div
class="
form-group
row
without-form-background
mb2
"
>
<label class="col-md-2 label-control" for="name"
>Category</label
>
<div class="col-md-10">
<Select2
:name="'category[]_' + index"
id=""
class="form-control multiselect"
multiple="multiple"
tabindex="-1"
selected
value="cate.id"
>
<option
v-for="cate in categoryarr"
:key="cate.id"
:value="cate.id"
:selected="
categoryarr_selected.includes(
String(cate.id)
)
"
>
{{ cate.title }}
</option>
</Select2>
</div>
</div>
<!-- ======== Category End ======== -->
<!-- /////////////// -->
<!-- ======== Remove Button1 Start ======== -->
<div
class="form-group without-form-background mb2"
>
<button
class="btn btn-danger text-white"
#click="removeEvent(ecr.id)"
>
Remove
</button>
<hr class="bg-danger" />
</div>
</div>
</template>

Related

laravel 9 vue 3 edit multiple checked checkbox value

when editing a checkbox array, I cannot select (checked) that are in the database
how to select those that exist in the checkbox database (checked) ?
please, help
Edit.vue
<template>
<div>
<admin-layout>
<template #header>
<div class="row">
<div class="col-md-12">
<h4>Емделуші</h4>
</div>
</div>
</template>
<div class="row">
<div class="col-md-12 mb-3">
<div class="card">
<div class="card-header">
<span><i class="bi bi-table me-2"></i></span> Емделушіні өзгерту
<div class="card-header-pills float-end">
<inertia-link :href="route('admin.schedules.index')" class="btn btn-primary text-white text-uppercase" style="letter-spacing: 0.1em;">
Кері қайту
</inertia-link>
</div>
</div>
<form #submit.prevent="updateSchedule">
<div class="card-body">
<div class="mb-3">
<label for="name" class="form-label">Аты-жөні</label>
<input type="text" class="form-control" id="name" v-model="form.name" :class="{'is-invalid' : form.errors.name }" autofocus="autofocus" autocomplete="off">
</div>
<div class="invalid-feedback mb-3" :class="{ 'd-block' : form.errors.name }">
{{ form.errors.name }}
</div>
<div class="mb-3">
<label class="form-label" for="email">Email</label>
<input type="text" class="form-control" id="email" v-model="form.email" :class="{'is-invalid' : form.errors.email }" autofocus="autofocus" autocomplete="off">
</div>
<div class="invalid-feedback mb-3" :class="{ 'd-block' : form.errors.email }">
{{ form.errors.email }}
</div>
<div class="mb-3">
<label class="form-label" for="phone">Телефон</label>
<input type="text" class="form-control" id="phone" v-model="form.phone" :class="{'is-invalid' : form.errors.phone }" autofocus="autofocus" autocomplete="off">
</div>
<div class="invalid-feedback mb-3" :class="{ 'd-block' : form.errors.phone }">
{{ form.errors.phone }}
</div>
<div class="form-check form-check-inline" v-for="(time, index) in times" :key="index">
<input class="form-check-input" type="checkbox" id="inlineCheckbox1" :value="time.time" v-model="form.times" :class="{'is-invalid' : form.errors.times }">
<label class="form-check-label" for="inlineCheckbox1">{{ time.time }}</label>
</div>
<div class="invalid-feedback mb-3" :class="{ 'd-block' : form.errors.times }">
{{ form.errors.times }}
</div>
</div>
<div class="card-footer clearfix">
<div class="float-end">
<jet-button class="ms-4 btn-primary text-white" :class="{ 'text-white-50': form.processing }" :disabled="form.processing">
<div v-show="form.processing" class="spinner-border spinner-border-sm" role="status">
<span class="visually-hidden">Өзгертілуде...</span>
</div>
Өзгерту
</jet-button>
</div>
</div>
</form>
</div>
</div>
</div>
</admin-layout>
</div>
</template>
<script>
import AdminLayout from '#/Layouts/AdminLayout';
import JetButton from '#/Jetstream/Button.vue'
import { useForm } from '#inertiajs/inertia-vue3';
import InertiaLink from "#inertiajs/inertia-vue3/src/link";
export default {
name: "Edit",
components: {
AdminLayout,
JetButton,
InertiaLink,
},
props: {
appointment: {},
times: {},
},
setup (props) {
const form = useForm({
name: props.appointment.name,
email: props.appointment.email,
phone: props.appointment.phone,
times: props.times,
});
return {
form,
}
},
methods: {
},
}
}
</script>
when editing a checkbox array, I cannot select (checked) that are in the database how to select those that exist in the checkbox database (checked) ? please, help

VUEJS: Model not changing in for loop

The V-model:"question.answer" is the same for each loop.
The content of rating_questions is:
rating_question = [
{
"id":1,
"question":"How did you like this?",
"amount_of_stars":8,
"answer":0
},
{
"id":2,
"question":"Second question?",
"amount_of_stars":3,
"answer":0
}]
When I select an answer for the first question, the answer is saved in rating_question[0].answer but if I select an answer for the second question, it is also saved in rating_question[0].answer and not in rating_questions[1].answer as I would expect.
<template>
<div class="ratings">
<div class="rating" v-for="(question, index) in rating_questions">
<div class="question">
{{ question.question }}
</div>
<div class="answer">
<div class="rating-stars">
<span v-for="i in question.amount_of_stars">
<input :id="i" name="rating" v-model="question.answer" type="radio" :value="i" class="radio-btn hide" />
<label :for="i" >☆</label>
</span>
{{ rating_questions[index]['answer'] }}
{{index}}
<div class="clear"></div>
</div>
</div>
</div>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendRating">
Send
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user', 'event', 'rating_questions'],
methods: {
sendRating() {
this.$emit('ratingsent', {
rating_questions: this.rating_questions
});
}
}
}
</script>
Your problem is not in Vue usage but how you use <input> and <label> HTML elements...
<input> id and <label> for attributes are assigned with simple number
1..question.amount_of_stars...which means first combo for every question will have id = 1, second 2 etc. Moreover you are using same name for every combo!
Now if you click on the label (star) in second question, browser just switch active combo on 1st question.
Try this:
<input :id="`rating-${question.id}-${i}`" :name="`rating-${question.id}`" v-model="question.answer" type="radio" :value="i" class="radio-btn hide" />
<label :for="`rating-${question.id}-${i}`" >☆</label>
Now:
every combo in the group (single question) will have same name (OK!)
every combo (and it's corresponding label) will have different id (OK!)
Also it's usually better to use :key together with v-for
new Vue({
data() {
return {
rating_questions: [
{
"id":1,
"question":"How did you like this?",
"amount_of_stars":8,
"answer":0
},
{
"id":2,
"question":"Second question?",
"amount_of_stars":3,
"answer":0
}]
}
}
}).$mount("#app")
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="ratings">
<div class="rating" v-for="(question, index) in rating_questions" :key="question.id">
<div class="question">
{{ question.question }}
</div>
<div class="answer">
<div class="rating-stars">
<span v-for="i in question.amount_of_stars">
<input :id="`rating-${question.id}-${i}`" :name="`rating-${question.id}`" v-model="question.answer" type="radio" :value="i" class="radio-btn hide" />
<label :for="`rating-${question.id}-${i}`" >☆</label>
</span>
{{ question.answer }}
<div class="clear"></div>
</div>
</div>
</div>
</div>
</div>
The error was in my input id's...
Each new question had the same id's.
<template>
<div class="ratings">
<div class="rating" v-for="(question, index) in rating_questions">
<div class="question">
{{ question.question }}
</div>
<div class="answer">
<div class="rating-stars">
<span v-for="i in question.amount_of_stars">
<input :id="'rating' + index + i" name="rating" v-model="question.answer" type="radio" :value="i" class="radio-btn hide" />
<label :for="'rating' + index + i" >☆</label>
</span>
<div class="clear"></div>
</div>
</div>
</div>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendRating">
Send
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user', 'event', 'rating_questions'],
methods: {
sendRating() {
this.$emit('ratingsent', {
rating_questions: this.rating_questions
});
}
}
}
</script>
There is very trivial fix of this problem.
See you are modifying the props. In vuejs, props are not supposed to be updated. I hope you might have encountered some error in the console (not sure though, as sometimes in my case also it doesn't appear)
Please use this SFC file
<template>
<div class="ratings">
<!-- using the data variable rather than props -->
<div class="rating" v-for="(question, index) in questions" :key="index">
<div class="question">
{{ question.question }}
</div>
<div class="answer">
<div class="rating-stars">
<span v-for="i in question.amount_of_stars" :key="i">
<input
:id="i"
name="rating"
v-model="question.answer"
type="radio"
:value="i"
class="radio-btn hide"
/>
<label :for="i">☆</label>
</span>
{{ questions[index]["answer"] }}
{{ index }}
<div class="clear"></div>
</div>
</div>
</div>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendRating">
Send
</button>
</span>
</div>
</template>
<script>
export default {
props: ["user", "event", "rating_questions"],
data() {
return {
questions: this.rating_questions, // because you can not change props in vuejs
};
},
methods: {
sendRating() {
this.$emit("ratingsent", {
rating_questions: this.questions,
});
},
},
};
</script>

Validate specific amount of input fields with vee-validate

I want to validate varios steps in a wizard, without validating all inputs, when clicking on the next button. When clicking on the next button it should fire the function to validate the input fields of the first step. Then in the next step the input fields of the second step and so on. The next button is no submit button.
<tab-content title="Company" icon="fas fa-building" :before-change="validateThirdStep">
<div class="col-md-8 offset-md-2">
<label class="col-form-label text-md-right">Do you have a chicken?</label>
<div class="form-goup row">
<div class="col-md-7">
<input type="radio" name="dsb" id="radios" value="yes" v-model="pickeddsb">Yes
<input type="radio" name="dsb" id="radios" value="no" v-model="pickeddsb">No
</div>
</div>
</div>
<div class="form-group" v-if="pickeddsb=='yes'">
<div class="col-md-8 offset-md-2">
<h4>Data</h4>
</div>
<div class="col-lg-8 m-auto">
<!-- Name -->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{ $t('name') }}</label>
<div class="col-md-7">
<input
v-model="namedsb"
v-validate="'required|namedsb'"
:class="{ 'has-error': errors.has('namedsb') }"
type="text"
name="namedsb"
>
{{ errors.first('namedsb') }}
</div>
</div>
<!-- Firm -->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{ $t('companyname') }}</label>
<div class="col-md-7">
<input
v-model="firm"
v-validate="'required|firmdsb'"
:class="{ 'has-error': errors.has('firmdsb') }"
class="form-control"
type="text"
name="firmdsb"
>
{{ errors.first('firmdsb') }}
</div>
</div>
<!--Telephone-->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{$t('telephone')}}</label>
<div class="col-md-7">
<input
v-model="telephonedsb"
v-validate="'required|telephonedsb'"
:class="{ 'has-error': errors.has('telephonedsb')}"
class="form-control"
type="tel"
name="telephonedsb"
>
{{ errors.first('telephonedsb') }}
</div>
</div>
<!-- Email -->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{ $t('email') }}</label>
<div class="col-md-7">
<input
v-model="emaildsb"
v-validate="'required|emaildsb'"
:class="{ 'has-error': errors.has('emaildsb') }"
class="form-control"
type="email"
name="emaildsb"
>
{{ errors.first('emaildsb') }}
</div>
</div>
</div>
</div>
</tab-content>
export default {
data() {
return {
namedsb: "",
telephonedsb: "",
emaildsb: "",
namere: "",
telephonere:"",
emailre: "",
}
},
methods: {
validateThirdStep: function() {
this.$validator.validate('namedsb', this.namedsb);
this.$validator.validate('firmdsb', this.firmdsb);
this.$validator.validate('telephonedsb', this.state);
this.$validator.validate('emaildsb', this.emaildsb);
}
}
}
It's fairly easy with the built-in scopes of VeeValidate, you can read about it on this page: enter link description here
A simple explanation is to add a specific scope for each tab/step, by adding this on the fields:
data-vv-scope="step1"
And then use this method when pressing the button for validation:
methods: {
validateForm(scope) {
this.$validator.validateAll('step1').then((result) => {
if (result) {
alert('Form Submitted!');
}
});
}
}

Using vue js with selectpicker

I'm using Vue.js to add multiple rows, each row contain two datetimepicker inputs and a bootstrap-select.
My problem is when I fill the inputs and click to add a new row the previous ones clear out, the reason is each time I add a new row I'm using setTimeout to referesh the selectpicker and the datetimepicker.
So I want to know if there is a way to trigger the last added element them without refreshing the previous ones.
Here is my code :
HTML
<div class="cols" id="app">
<ul style="list-style-type: none;">
<li>
<button style="float: right;margin-right: 20px;margin-top: 5px;" type="button" class="btn btn-success btn-xs" v-on:click="addRow()">
<i class="fa fa-plus"></i> Ajouter
</button>
</li>
<li v-for="(row, id) in rows">
<div class="form-inline cp-out" style="padding-bottom: 9px;border-radius:4px;background-color:white;margin-left:-20px;display:inline-block;width:100%;margin-top:10px;">
<div class="col-md-3">
<label :for="['time_start'+id]" class="control-label">start time</label>
<div class="input-group date form_time" style="width:100%;" data-date="" data-date-format="hh:ii" :data-link-field="['time_start'+id]" data-link-format="hh:ii">
<input v-model="row.startTime" :name="'rows['+id+'][startTime]'" class="form-control" :id="['startTime' + id]" size="16" type="text" value="" >
<span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
</div>
</div>
<div class="col-md-3">
<label :for="['time_end'+id]" class="control-label" style="margin-left:7px;">end time</label>
<div class="input-group date form_time" style="width:100%;" data-date="" data-date-format="hh:ii" :data-link-field="['time_end'+id]" data-link-format="hh:ii">
<input v-model="row.endTime" :name="'rows['+id+'][endTime]'" class="form-control" :id="['endTime'+id]" size="16" type="text" value="" >
<span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
</div>
</div>
<div class="col-md-4">
<div class="form-group select_group" style="margin-left:5px;">
<label :for="['status' + id]" class="control-label">Status</label>
<select data-width="100%" v-model="row.status" :name="'rows['+id+'][status]'" :id="['status' + id]" class="select_picker" data-live-search="true" multiple >
<option value="Status 1">Status 1</option>
<option value="Status 2">Status 2</option>
</select>
</div>
</div>
<div class="col-xs-1">
<button type="button" class="btn btn_delete btn-xs btn-danger" v-on:click="delRow(id)">
<i class="fa fa-remove"></i> delete
</button>
</div>
</div>
</li>
</ul>
</div>
JS
app = new Vue({
el: '#app',
data: {
rows: []
},
methods: {
addRow: function () {
this.rows.push({startTime: '', endTime: '', status: []});
setTimeout(function () {
$('.select_picker').selectpicker('refresh');
$('.form_time').datetimepicker({format: 'LT'});
}.bind(this), 10);
},
delRow: function (id) {
this.rows.splice(id, 1);
}
},created:function() {
this.addRow();
}
});
This is the example : https://jsfiddle.net/rypLz1qg/9/
You really need to write a wrapper component. Vue expects to control the DOM and not to have you making DOM-changing things like the *picker calls at arbitrary times. However, a component gives you the opportunity to tell your component how to interact with the DOM in each of its lifecycle hooks so that its behavior can be consistent. See the JavaScript tab on the wrapper component example page.

Vue.js not updating template when changing child objects

I'm extending laravel spark and wanted to try to validate registration before actually sending it off.
All data is handled nicely and correctly from the server but the errors do not pop-up.
The code being used for validation is as following:
module.exports = {
...
methods: {
...
validate(field, value) {
var formData = {
field: field,
value: value
};
var form = new SparkForm(formData);
Spark.post('/register_validate', form).then(response => {
this.registerForm.addSuccess(field);
}).catch(errors => {
this.registerForm.addError(field, errors[field]);
});
}
}
};
After, i extended SparkForm and added these methods (successes is just a copy of errors, used to display validation success messages):
/**
* SparkForm helper class. Used to set common properties on all forms.
*/
window.SparkForm = function (data) {
...
this.addError = function(field, errors) {
form.successes.remove(field);
form.errors.add(field, errors);
},
this.addSuccess = function(field) {
form.errors.remove(field);
form.successes.add(field, true);
}
};
And finally i added some methods on the SparkFormErrors.
/**
* Spark form error collection class.
*/
window.SparkFormErrors = function () {
...
this.add = function(field, errors) {
this.errors[field] = errors;
};
this.remove = function(field) {
delete this.errors[field];
}
};
In the console no errors are shown and in the network tab i can see the correct messages coming true, also when i add a console log in for example the response callback i can see the actual errors or success messages. But they are not drawn on screen.
For completeness i'll include the important content of the template blade file:
#extends('spark::layouts.app')
#section('content')
<spark-register-stripe inline-template>
<!-- Basic Profile -->
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">
{{ trans('auth.register.title') }}
</div>
<div class="panel-body">
<!-- Generic Error Message -->
<div class="alert alert-danger" v-if="registerForm.errors.has('form')">
#{{ registerForm.errors.get('form') }}
</div>
<!-- Registration Form -->
<form class="form-horizontal" role="form">
<!-- Name -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('name')}">
<label class="col-md-4 control-label">{{ trans('user.name') }}</label>
<div class="col-md-6">
<input type="name" class="form-control" name="name" v-model="registerForm.name" autofocus #blur="validate('name', registerForm.name)">
<span class="help-block" v-show="registerForm.errors.has('name')">
#{{ registerForm.errors.get('name') }}
</span>
</div>
</div>
<!-- E-Mail Address -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('email')}">
<label class="col-md-4 control-label">{{ trans('user.email') }}</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" v-model="registerForm.email" #blur="validate('email', registerForm.email)">
<span class="help-block" v-show="registerForm.errors.has('email')">
#{{ registerForm.errors.get('email') }}
</span>
</div>
</div>
<!-- Password -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('password')}">
<label class="col-md-4 control-label">{{ trans('user.password') }}</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password" v-model="registerForm.password" #blur="validate('password', registerForm.password)">
<span class="help-block" v-show="registerForm.errors.has('password')">
#{{ registerForm.errors.get('password') }}
</span>
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button class="btn btn-primary" #click.prevent="register" :disabled="registerForm.busy">
<span v-if="registerForm.busy">
<i class="fa fa-btn fa-spinner fa-spin"></i>{{ trans('auth.register.submitting') }}
</span>
<span v-else>
<i class="fa fa-btn fa-check-circle"></i>{{ trans('auth.register.submit') }}
</span>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</spark-register-stripe>
#endsection
Any bright mind seeing what i'm missing/forgetting?