Pass a boolean with a specific id - vue.js

Is it possible to pass a boolean with a specific id to the query parameter?
The component for toggle is used.
<v-toggle-button :defaultState='false' id='in_stock' ref='toggleAvailable'/>
toggle-component
<template>
<label :for='id + "_button"' :class='{"active": isActive}' class='toggle__button'>
<input type='checkbox' :id='id + "_button"' v-model='checkedValue'>
<span class='toggle__switch'></span>
</label>
</template>
script toggle-component
computed: {
isActive() {
return this.currentState;
},
checkedValue: {
get() {
return this.defaultState;
},
set(newValue) {
this.currentState = newValue;
this.$emit('change', newValue);
}
}
},
in one request I need to give true / false with id: in_stock, in another id: under_order

Related

Vue 2: Value prop does not update input value

So I have encountered a weird issue with my code, that I hope to get some help with.
I have a custom "Input" component where I have a normal HTML input with some styling. I have then called this component with a value and a function to call upon changes. No v-model is used as I have to do some validation on the field. However, it doesn't work. I can see that the value variable in the "Input" component changes correctly, but it does not impact the HTML input element at all, if you enter multiple values into the input field. How can this be?
InputComponent
<template>
<label class="block text-sm flex justify-end lg:justify-start w-28 h-10">
<span class="text-gray-800">{{ label }}</span>
<input
class="block text-black placeholder:text-black placeholder:opacity-40 w-14 lg:w-full rounded-lg text-center"
:placeholder="placeholder"
:type="type"
:value="value"
#input="handleInput($event.target.value)"
/>
</label>
</template>
<script>
export default {
props: {
label: String,
placeholder: String,
type: String,
value: String,
size: String,
},
methods: {
handleInput(value) {
this.$emit('input', value);
}
},
}
</script>
Page component calling Input
<template>
<Input
type="number"
placeholder="0"
size="sm"
:value="test"
#input="changePlannedVacationDay($event)"
/>
</template>
<script>
export default {
data() {
return {
test: ""
};
},
methods: {
changePlannedVacationDay(value) {
let localValue = value;
const maxValue = 5;
if (parseInt(localValue) < 0) {
localValue = "0";
} else if (parseInt(localValue) > maxValue) {
localValue = maxValue.toString();
}
this.test = localValue;
}
},
</script>
You should use a computed property with getter and setter:
<template>
<input v-model="localModel">
</template>
<script>
export default
{
name: 'CustomInputComponent',
props:
{
value:
{
type: String,
default: null,
},
},
computed:
{
localModel:
{
get()
{
return this.value;
},
set(val)
{
this.$emit('input', val);
}
},
},
}
</script>
In the parent component you should use a watcher to detect value changes and act upon them.

Vue 2 Emit selected data back to parent component

Struggling to sort out how to get a selected value from a Typeahead component to pass back to the parent component. I'm allowing the user to search from a variety of data to link a record to a post. Once the user clicks one of the typeahead drop-down records, I pass the item to the sendlink method - I've checked that the data passes ok. When I do the emit using the selected-link event, I'm not getting the data in the parent component.
PostList.vue
<template>
<div>
<div v-if='posts.length === 0' class="header">There are no posts yet!</div>
<form action="#" #submit.prevent="createPost()" class="publisher bt-1 border-fade bg-white" autocomplete="off">
<div class="input-group">
<input v-model="post.content" type="text" name="content" class="form-control publisher-input" placeholder="What's the lastest?" autofocus>
<span class="input-group-btn">
<button type="submit" class="btn btn-primary">Post</button>
</span>
</div>
<span class="publisher-btn file-group">
<i class="fa fa-camera file-browser"></i>
<input type="file">
</span>
</form>
<div #click="doit" v-on:selected-link="onSelectedLink">{{ modellink.name }}</div>
<typeahead
source="/api/typeahead"
placeholder="Link Post to Trip, Business, etc"
filter-key="title"
:start-at="3">
</typeahead>
<post v-for="post in posts"
:key="post.id"
:post="post"
#post-deleted="deletePost($event)">
</post>
</div>
</template>
<script>
var axios = require("axios");
import post from './PostItem.vue';
import typeahead from './Typeahead.vue';
export default {
components: {
post,
typeahead
},
props: ['postableId', 'postableType', 'model'],
data: function() {
return {
modellink: {
"name": "n/a",
"description": "",
"id": null,
"model": "n/a"
},
post: {
id: 1,
content: "",
edited: false,
created_at: new Date().toLocaleString(),
user: {
id: 1,
name: '',
}
},
posts: [
{
id: 1,
content: "",
edited: false,
created_at: new Date().toLocaleString(),
user: {
id: 1,
name: '',
}
}
]
};
},
created() {
this.fetchPostsList();
},
methods: {
onSelectedLink: function (talink) {
alert(JSON.stringify(talink, null, 4));
this.link = talink
},
doit() {
alert(JSON.stringify(this.modellink, null, 4));
},
fetchPostsList() {
if( this.postableId ) {
axios.get('/api/' + this.postableType + '/' + this.postableId + '/posts').then((res) => {
this.posts = res.data;
});
} else {
axios.get('/api/post').then((res) => {
//alert(JSON.stringify(res.data[0], null, 4));
this.posts = res.data;
});
}
},
createPost() {
axios.post('api/post', {content: this.post.content, user_id: Laravel.userId, vessel_id: Laravel.vesselId })
.then((res) => {
this.post.content = '';
// this.post.user_id = Laravel.userId;
// this.task.statuscolor = '#ff0000';
this.edit = false;
this.fetchPostsList();
})
.catch((err) => console.error(err));
},
deletePost(post) {
axios.delete('api/post/' + post.id)
.then((res) => {
this.fetchPostsList()
})
.catch((err) => console.error(err));
},
}
}
</script>
Typeahead.vue
<template>
<div>
<input
v-model="query"
#blur="reset"
type="text"
class="SearchInput"
:placeholder="placeholder">
<transition-group name="fade" tag="ul" class="Results">
<li v-for="item in items" :key="item.id">
<span #click="sendlink(item)">
<strong>{{ item.name }}</strong> - <small>{{ item.model }}</small><br>
<small>{{ item.description }}</small>
</span>
</li>
</transition-group>
<p v-show="isEmpty">Sorry, but we can't find any match for given term :( </p>
</div>
</template>
<script>
var axios = require("axios");
export default {
name: 'Typeahead',
props: {
modellink: {
type: Object,
required: false
},
source: {
type: [String, Array],
required: true
},
filterKey: {
type: String,
required: true
},
startAt: {
type: Number,
default: 3
},
placeholder: {
type: String,
default: ''
}
},
data() {
return {
items: [],
query: '',
taitem: ''
}
},
computed: {
lookup() {
if(this.query.length >= this.startAt) {
axios.get(this.source + '/' + this.query).then((res) => {
this.items = res.data;
return res.data;
});
}
},
isEmpty() {
if( typeof this.lookup === 'undefined' ) {
return false
} else {
return this.lookup.length < 1
}
}
},
methods: {
sendlink: function (taitem) {
this.$emit('selected-link', taitem);
},
reset() {
this.query = ''
}
}
}
</script>
In your PostList.vue, move the v-on:selected-link="onSelectedLink" from the div to typeahead like below. When emitting an event from child to parent, the listener on the parent needs to be on the child component tag for it to work.
<div #click="doit">{{ modellink.name }}</div>
<typeahead
source="/api/typeahead"
placeholder="Link Post to Trip, Business, etc"
filter-key="title"
:start-at="3"
v-on:selected-link="onSelectedLink">
</typeahead>

How can I make a reusable "CheckAll" checkbox solution in Vue2

I am trying to create a reusable "Check All" solution for displaying a list of objects retrieved from an API.
I really like the get/set methods of computed properties that I use in this example here, https://codepen.io/anon/pen/aLeLOZ but I find that rewriting the same function over and over again and maintaining a seperate checkbox state list is tedious.
index.html
<div id="app">
<input type="checkbox" v-model="selectAll1"> Check All
<div v-for="person in list1">
<input type="checkbox" v-model="checkbox" :value="person.id">
<span>{{ person.name }}</span>
</div>
<hr/>
<input type="checkbox" v-model="selectAll2"> Check All
<div v-for="person in list2">
<input type="checkbox" v-model="checkbox2" :value="person.id">
<span>{{ person.name }}</span>
</div>
</div>
main.js
new Vue({
el: '#app',
data () {
return {
list1: [
{ id: 1, name: 'Jenna1'},
{ id: 2, name: 'Jenna2'},
{ id: 3, name: 'Jenna3'},
{ id: 4, name: 'Jenna4'}
],
list2: [
{ id: 1, name: 'Mary1'},
{ id: 2, name: 'Mary2'},
{ id: 3, name: 'Mary3'},
{ id: 4, name: 'Mary4'}
],
checkbox: [],
checkbox2: []
}
},
computed: {
selectAll1: {
get: function () {
return this.list1 ? this.checkbox.length === this.list1.length : false
},
set: function (value) {
let selected = []
if (value) {
this.list1.forEach(function (bf) {
selected.push(bf.id)
})
}
this.checkbox = selected
}
},
selectAll2: {
get: function () {
return this.list2 ? this.checkbox2.length === this.list2.length : false
},
set: function (value) {
let selected = []
if (value) {
this.list2.forEach(function (bf) {
selected.push(bf.id)
})
}
this.checkbox2 = selected
}
},
}
});
How can I make a resuable selectAll() function that will work in this example that can be included as often as needed?
Is it possible to make a class that can maintain the check box state for each list and still function as a computed property to make use of the v-model directive?
It's not the same at all, but a method based solution would be
methods: {
selectUs: function(){
if (this.checkbox.length <= this.list1.length) {
this.checkbox = Array.from(Array(this.list1.length + 1).keys())
} else {
this.checkbox = []
}
}
}
with #click="selectUs" instead of v-model="selectAll1"
(you could keep the get part of your computed properties to keep track of whether all are selected, and then use if (selectAll1) { etc } in the method)

Search Bar Filter Using Vue with child component

I am creating a dynamic search bar that will filter a sidebar full of names based on user input. However, I am having trouble temporarily hiding and showing data based on the search bar's value on keyup. What is the best way to achieve this the "Vue way"?
On keyup, I want to filter through all of the this.people data and only show names that contain the value of the search input.
Below is what my code looks like
//Javascript
Vue.component('sidebar',{
props: ['people', 'tables'],
data: () => {
return {
fullName: ''
}
},
computed: {
computed() {
return [this.people, this.tables].join()
}
},
template:
`
<div id="sidebarContain" v-if="this.people">
<input id="sidebar-search" type="text" placeholder="Search..." #keydown="searchQuery">
<select id="sidebar-select" #change="sidebarChanged">
<option value="AZ">A-Z</option>
<option value="ZA">Z-A</option>
<option value="notAtTable">No Table</option>
<option value="Dean's Guest">Dean's Guest</option>
<option value="BOO | VIP">BOO | VIP</option>
</select>
<div v-for="person in people" :class="[{'checked-in': isCheckedIn(person)}, 'person']" :id="person.id" :style="calcRegColor(person)">
<span v-if="person.table_name">{{person.first_name + ' ' + person.last_name + ' - ' + person.table_name}}</span>
<span v-else>{{person.first_name + ' ' + person.last_name}}</span>
</div>
</div>
`,
methods: {
isCheckedIn(person) {
return person.reg_scan == null ? true : false;
},
isHidden(person)
{
console.log("here");
},
calcRegColor(person)
{
switch(person.registration_type)
{
case "Dean's Guest" :
return {
color: 'purple'
}
break;
case "BOO | VIP" :
return {
color: 'brown'
}
break;
case "Student" :
return {
color: 'green'
}
break;
case "Faculty":
case "Staff":
return {
color: 'blue'
}
break;
case "Alumni Club Leader":
return {
color: 'gold'
}
break;
case "Table Guest" :
return {
color: 'pink'
}
break;
default:
return {
color: 'black'
}
}
}
},
watch: {
computed() {
console.log("People and Tables Available");
}
}
});
//HTML
<div id="app">
<sidebar :people="people" :tables="tables"></sidebar>
</div>
Here is a strategy to achieve this in Vue:
A. Use a different property with v-for instead of
props.people, like myPeople.
<div v-for="person in myPeople">
B. Save your searchQuery with v-model:
<input id="sidebar-search" ... v-model="searchQuery">
...
// Include searchQuery in data so it is reactive.
data: () => {
return {
fullName: '',
searchQuery: ''
}
}
C. Compute myPeople when searchQuery changes
computed: {
myPeople: function () {
return this.people.filter((p) => {
// something based on `searchQuery`
});
}
}
The Vue docs have a longer discussion around this type of thing.

I can't set "disabled" parameter in Vue to be persistent

I can't set "disabled" parameter to be persistent. If I set disable: true inside data function, it seems that it doesn't do anything.
You can see inside mounted() that it calls checkCanVote() and in there at first the console.log says it is set to false, then I set it to true but on stars hover (star_over()) it is again false?
http://jsfiddle.net/7unqk49k/1/
Template
<div id="star-app" v-cloak class="col-md-4">
<star-rating value="<?php echo $this->rating_rounded; ?>"></star-rating>
</div>
<template id="template-star-rating">
<div class="star-rating">
<label class="star-rating__star" v-for="rating in ratings" :class="{'is-selected': ((value >= rating) && value != null), 'is-disabled': disabled}" #mouseover="star_over(rating)" #mouseout="star_out">
<input class="star-rating star-rating__checkbox" type="radio" :name="name" :disabled="disabled" :id="id" :required="required" v-model="value" #click="set(rating)"> ★
</label>
</div>
</template>
JS
Vue.component('star-rating', {
template: '#template-star-rating',
data: function data() {
return {
value: null,
temp_value: null,
ratings: [1, 2, 3, 4, 5],
disabled: true
};
},
props: {
'name': String,
'value': null,
'id': String,
'disabled': Boolean,
'required': Boolean
},
methods: {
star_over: function star_over(index) {
console.log(this.disabled);
if (this.disabled == true) {
return;
}
this.temp_value = this.value;
this.value = index;
},
star_out: function star_out() {
if (this.disabled == true) {
return;
}
this.value = this.temp_value;
},
set: function set(value) {
if (this.disabled == true) {
return;
}
this.temp_value = value;
this.value = value;
// On click disable - this works
this.disabled = true;
},
checkCanVote: function() {
console.log('Inside checkCanVote');
console.log(this.disabled);
this.disabled = true;
console.log(this.disabled);
}
},
mounted() {
this.checkCanVote();
}
});
new Vue({
el: '#star-app'
});
The actual problem is in naming things.Try to avoid to use same naming for the props that you pass to child component and data properties that you've declared in child component.
To get this working as expected, you should just remove the prop declaration for disabled prop and It should work.
http://jsfiddle.net/9debdkh1/