Using vue js with selectpicker - vue.js

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.

Related

Correct bootstrap3 way to give padding on grid

I have four inputs in the same row and one of the input is conditionally visible by clicking "Click" button.
So if all four inputs are visible, the inputs datepicker1 and datepicker2 are sticked on the inputs above.
What is the correct bootstrap way to arrange and beautify the distances between the inputs?.
Gutters are not available on bootstrap 3.
<div class="col-md-3">
<select class="lookup-type-select form-control" name="created_lookup_type_1">
<option value="range">Range</option>
<option value="range__exclude">Exclude Range</option>
</select>
</div>
<div class="lookup-value">
<div class="col-md-3">
<select name="created__1_0" class="filter-input shortcut form-control" id="id_created__1_0">
</select>
</div>
<div class="col-md-8 row custom" style="display: inline;">
<div class="col-md-6">
<div class="datetimepicker input-group start-date date" data-date-format="YYYY-MM-DD HH:mm:ss">
<input class="filter-input form-control" name="created__1_1" value="" type="text" id="datepicker1" placeholder="From">
<span class="input-group-addon">
<span class="glyphicon-calendar glyphicon"></span>
</span>
</div>
</div>
<div class="col-md-6">
<div class="datetimepicker input-group end-date date" data-date-format="YYYY-MM-DD HH:mm:ss">
<input class="filter-input form-control" name="created__1_2" value="" type="text" id="datepicker2" placeholder="To">
<span class="input-group-addon">
<span class="glyphicon-calendar glyphicon"></span>
</span>
</div>
</div>
</div>
<div class="col-md-3 row month_only" style="display: none;">
<div>
<div class="datetimepicker input-group start-date date month_only" style="display: none;">
<input class="filter-input form-control" name="created__1_3" value="" type="text" id="id_created__1_3" placeholder="Month">
<span class="input-group-addon">
<span class="glyphicon-calendar glyphicon"></span>
</span>
</div>
</div>
</div>
</div>
<button type="button" class="btn remove-button">
<span class="glyphicon glyphicon-remove"></span>
</button>
<button onclick="myFunction()">Ckick</button>
<script>
function myFunction() {
if (document.getElementById('id_created__1_0').style.display != "none") {
document.getElementById("id_created__1_0").style.display = "none";
} else {
document.getElementById("id_created__1_0").style.display = "inline";
}
}
</script>
Jsfiddle example
Should be like the following pic

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>

Insert an element into template but no v-model

use vue
i want to insert an element when i click createItem:
<template>
<div class="form-row group">
<h5 class="p-2 col-md-12">item</h5>
<div class="form-row">
<div class="form-group mr-2">
<input type="number" class="form-control" placeholder="Num" v-model="tempitemNum">
</div>
<div class="form-group">
<button class="btn btn-primary btn-sm mt-1" #click="createItem">create</button>
</div>
</div>
<div class="items col-md-12 mt-1 mb-1">
//create item here
</div>
</div>
</template>
my script function
createItem: function(){
let items = document.querySelector('.items');
if(this.itemNum == 0){
this.itemNum = parseInt(this.tempitemNum);
for (let i = 0; i < this.itemNum; i++) {
let item = document.createElement('div');
item.className = "col-md-12 mb-1 pl-0 pr-0";
item.innerHTML = `
<div>
<span>${i+1}.</span>
<input type="text" class="form-control">
<input type="text" class="form-control">
<input type="text" class="form-control">
</div>
`
items.insertAdjacentElement("beforeend", item);
}}}
how can i insert item with v-model in every input element?
You can use jsx to render Dom elements and now you can use v-model with it you can check: https://github.com/nickmessing/babel-plugin-jsx-v-model

Modal event is not working angular 2

I am trying to clear form values when modal is hidden using its event but it not working I am referencing all the required files but it not trigger. Below I attach the code of my client side. I am using it in my angular 2 application as an component.
html
<script src="../../../Scripts/bootstrap.min.js"></script>
<script src="../../../Scripts/jquery-2.2.0.min.js"></script>
<script>
$('#myModal').on('hidden.bs.modal', function () {
$(this).find('form')[0].reset();
});
</script>
<button type="button" class="btn-u pull-right margin-bottom-10" data-toggle="modal" data-target="#myModal"><span class="fa fa-plus" aria-hidden="true"></span> Invite User</button>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Invite User</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" id='myForm' role="form" [ngFormModel]="InviteUserForm">
<div class="input-group margin-bottom-20">
<span class="input-group-addon"><i class="fa fa-user"></i></span>
<input type="text" [(ngModel)]='inviteUser.username' class="form-control" ngControl="username" required>
</div>
<div class="input-group margin-bottom-20">
<span class="input-group-addon"><i class="fa fa-envelope"></i></span>
<input type="email" required [(ngModel)]='inviteUser.email' class="form-control" ngControl="email" pattern="[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,3}$">
</div>
<div class="input-group margin-bottom-20">
<span class="input-group-addon"><i class="fa fa-glass"></i></span>
<select [(ngModel)]='inviteUser.partnerId' class="form-control" ngControl="partner" required>
<option>Select one</option>
<option *ngFor="let partner of _partners" value={{partner.Id}}>
{{partner.Name}}
</option>
</select>
</div>
</form>
<button type="button" class="btn-u btn-u-default margin-right-5" data-dismiss="modal">Close</button>
<button type="button" [disabled]="!InviteUserForm.valid" class="btn-u pull-right" (click)="Invite(inviteUser)" data-dismiss="modal">Invite</button>
</div>
</div>
</div>
</div>
You can use angular2 bootstrap modal as https://github.com/dougludlow/ng2-bs3-modal. You can import this plugin into your project.
use this code
constructor() {
this.activate();
}
activate() {
////This event is fired immediately when the hide instance method has been called.
///called to reset the events and the headers.
$('#myModal').on('hidden.bs.modal', function () {
////debugger;
// do your work over here
console.log("modal is closed hidden");
})
////This event is fired when the modal has finished being hidden from the user (will wait for css transitions to complete).
///called to reset the events and the headers.
$('#myModal').on('hide.bs.modal', function () {
////debugger;
// do your work over here;
console.log("modal is closed hide");
})
}

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?