Vue bootstrap form tags allowing duplicates - vue.js

I'm trying to allow duplicates in Vue bootstrap's form tags.
I've tried using :tag-validator (in the example) and #tag-state to externally modify the v-model value. However it seems like it is getting rid of the duplicate somewhere. Is this impossible?
Jsfiddle of the example: https://jsfiddle.net/yts54fpd/.
<div id="app">
<template>
<div>
<b-form-group label="Tagged input using select" label-for="tags-component-select">
<!-- Prop `add-on-change` is needed to enable adding tags vie the `change` event -->
<b-form-tags
:tag-validator="tagValidator"
id="tags-component-select"
v-model="value"
size="lg"
class="mb-2"
add-on-change
no-outer-focus
>
<template v-slot="{ tags, inputAttrs, inputHandlers, disabled, removeTag }">
<ul v-if="tags.length > 0" class="list-inline d-inline-block mb-2">
<li v-for="tag in tags" :key="tag" class="list-inline-item">
<b-form-tag
#remove="removeTag(tag)"
:title="tag"
:disabled="disabled"
variant="info"
>{{ tag }}</b-form-tag>
</li>
</ul>
<b-form-select
v-bind="inputAttrs"
v-on="inputHandlers"
:disabled="disabled"
:options="options"
>
<template #first>
<!-- This is required to prevent bugs with Safari -->
<option disabled value="">Choose a tag...</option>
</template>
</b-form-select>
</template>
</b-form-tags>
</b-form-group>
</div>
</template>
</div>
window.onload = () => {
new Vue({
el: '#app',
data() {
return {
options: ['Apple', 'Orange', 'Banana', 'Lime', 'Peach', 'Chocolate', 'Strawberry'],
value: []
}
},
methods: {
tagValidator(tag) {
this.value.push(tag)
return true
}
}
})
}

Related

How to bind data in a link inserted to a v-html in vuejs?

Here's my code:
<pre
class="pre-text-formatted feed mt-2"
v-html="post.description.length >= 200 ? post.description.substring(0,200) + `... <a #click='readMore' class='text-muted pull-right' href>...read more</a>` : post.description">
</pre>
And here's the output:
The readMore method does not trigger its function.
Hello I personally don't like using v-html except in some rare cases. For this question I will suggest you render your templates conditionally. here's a sample that might help.
var app = new Vue({
el: '#app',
data: {
post: {
description: 'Hello you\'re awesome today.',
},
},
methods: {
readMore() {
alert('You click read more');
},
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<pre
class="pre-text-formatted feed mt-2">
<template v-if="post.description.length >= 200">
{{ post.description.substring(0,200)}} <a #click='readMore' class='text-muted pull-right' href>...read more</a>
</template><template v-else>{{post.description}}</template>
</pre>
</div>
you should try with conditional rendering, as below:
<pre
class="pre-text-formatted feed mt-2">
<template v-if="post.description.length >= 200">
{{ post.description.substring(0,200) }}...
<a #click='readMore' class='text-muted pull-right' href>...read more</a>
</template>
<template v-else>
{{ post.description }}
</template>
</pre>

Condition on template with v-if using v-slot prop

I'm trying to make a condition to enable a named slot like this:
<template v-slot:item="{ item }" v-if="item.loading">
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</template>
My use case is a Vuetify datatable: each item has a "loading" property, and I'd like to activate "item" slot only if the row is loading ("item" slot is Slot to replace the default rendering of a row)
The error is that item is undefined in the v-if, which seems logic : item is only defined for template children tag.
Is there a way to solve this problem?
You can filter the items that you pass to the datatable with a computed property.
Can you just not swap element based on loading ?
Vue.config.devtools = false;
Vue.config.productionTip = false;
var app = new Vue({
el: '#app',
data: {
items: [{data : "", loading: true}, {data : "Some data", loading: false}]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="item in items">
<div>
<div v-if="item.loading">
Loading...
</div>
<div v-else>
{{item.data}}
</div>
</div>
</div>
</div>
I had a similar problem, and I solved it in Vuetify 2 by importing VDataTable/Row as 'v-data-table-row', and using it to render 'regular' table rows, and for custom rows I used my own template.
JavaScript
import Row from 'vuetify/lib/components/VDataTable/Row.js';
export default {
components: { 'v-data-table-row': Row },
data() {
return {
currentItemName: 'Ice cream sandwich'
}
}
// headers, items, etc...
}
HTML
<template v-slot:item="{ item }">
<tr v-if="item.name == currentItemName" class="blue-grey lighten-4">
<td>Custom prefix - {{ item.name }}</td>
<td colspan="2">{{ item.calories }} - Custom suffix</td>
</tr>
<v-data-table-row v-else :headers="headers" :item="item">
<template
v-for="(index, name) in $scopedSlots"
v-slot:[name.substr(5)]="data"
>
<slot
v-if="name.substr(0, 5) === 'item.'"
:name="name"
v-bind="data"
></slot>
</template>
</v-data-table-row> </template
You can check out working example here.
You can just put the v-if on the child element
<template #item="{ item }">
<v-progress-circular
v-if="item.loading"
color="primary"
indeterminate
></v-progress-circular>
</template>

bootstrap-vue <b-pagination> component not changing pages on click

I want to implement a pagination component b-pagination w/bootstrap-vue but it will only display page one. I am following the setup in documentation but they only show an example using a table not an unordered list. I have :
<template>
<div class="results overflow-auto" v-cloak>
<h3>Search Results</h3>
<modal v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<template v-slot:header>
<h1>NASA Image</h1>
</template>
<template v-slot:body>
<b-img class="modal-image" v-bind:src="attribute"></b-img>
</template>
</modal>
<!-- ======== Pagination Markup ============ -->
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
:items="items"
aria-controls="my-list"
></b-pagination>
<p class="mt-3">Current Page: {{ currentPage }}</p>
<!-- ==========End Pagination Markup ======== -->
<!-- Limit output to 100 items -->
<ul
class="search-results"
id="my-list"
>
<li v-for="(item, index) in propsResults.items.slice(0,100)" :key="index">
{{ item.data[0].title}}
<span>
<b-img
thumbnail
class="thumbnail"
:src="item.links[0].href"
alt="Fluid image"
id="show-modal"
v-on:click="imageModal"
></b-img>
</span>
</li>
</ul>
</div>
</template>
and my javascript is :
export default {
name: "SearchResults",
props: ["propsResults"],
data() {
return {
showModal: false,
attribute: "",
perPage: 10,
currentPage: 1,
items: this.$props.propsResults.items
};
},
computed: {
rows() {
return this.$props.propsResults.items.length;
}
}
The pagination component is displaying all 100 items of items array on one page. I should also note I do not see the items array in the b-pagination props object per Vue dev tools in FF. is this normal? Any insight appreciated..
You should still be using currentPage to choose which items to show. The b-pagination component only changes that number.
Try using this line:
<li v-for="(item, index) in items.slice(10*(currentPage-1),10*(currentPage))" :key="index">

How can I get value in select vue.js? vue.js 2

My case is like this
I have a component like this :
<template>
<div class="panel panel-default panel-filter">
...
<div id="collapse-location" class="collapse in">
<!-- province -->
<div style="margin-bottom: 10px">
<location-bs-select element-name="province_id" level="provinceList" type="1" module="searchByLocation"/>
</div>
<!-- city -->
<location-bs-select element-name="city_id" level="cityList" type="2" module="searchByLocation"/>
</div>
<!-- button search -->
<div class="panel-item">
<br>
<a href="javascript:;" class="btn btn-block btn-success" v-on:click="searchData">
Search
</a>
</div>
...
</div>
</template>
<script>
export default{
...
data() {
return{
...
province_id:'',
}
},
...
methods: {
...
searchData: function() {
console.log(this.province_id)
console.log(document.getElementsByName("province_id")[0].value)
console.log('testtt')
}
}
}
</script>
The component have child component, that is location-bs-select. The component used to display provincy and city
The component child like this :
<template>
<select class="form-control" v-model="selected" :name="elementName" #change="changeLocation">
<template v-for="option in options">
<template>
<option v-bind:value="option.id" >{{ option.name }}</option>
</template>
</template>
</select>
</template>
<script>
export default{
props: ['elementName', 'level','type','module'],
...
};
</script>
If I do inspect element, the result like this :
When click button search, I want to get the value of province and city
I try javascript like this :
console.log(document.getElementsByName("province_id")[0].value)
it works
But I want to use vue step. I try like this :
console.log(this.province_id)
It does not work
How can I solve it?
I hope I got you right. You want to propagate the value of the select back to the parent. The Child component COULD be like this.
removed template nesting
added change event listener and emit method
added data
And all together:
<template>
<select #change="emitChange" class="form-control" v-model="selected" :name="elementName">
<option v-for="option in options" v-bind:value="option.id" >{{ option.name }}</option>
</select>
</template>
<script>
export default{
props: ['elementName', 'level','type','module'],
data: function() {
return { selected: null }
},
methods: {
emitChange: function() {
this.$emit('changeval', this.selected);
}
}
};
</script>
Now your parent needs to listen to this emit. Here just the relevant parts of your parent
...
<location-bs-select element-name="city_id"
level="cityList"
type="2"
#changeval="changeval"
module="searchByLocation"/>
...
methods: {
changeval: function(sValue) {
this.province_id = sValue;
console.log(this.province_id);
}
}
Quickly summed up
the select value is bound to the selected prop of your data
the select has an attached change event which will emit changes
the parent will listen to this emit and will update it's relevant data prop

Vue JS – Using v-if with components

I'm using VueJS components to create a dynamic pricing table. One of the more 'static' elements is a 'most popular' label which is added to the Team plan. I want to be able to use v-if to display a and add an extra class on the plan marked as most popular. I've simplified the code for brevity.
You can see I have tried multiple ways of formatting the expression (currently differs between the v-bind and the v-if) but I'm not sure if this approach is even possible.
Here is the HTML.
<div id="app">
<ul class="plans">
<plan-component :
name="Basic"
most-popular=false
></plan-component>
<plan-component :
name="Recreational"
most-popular=false
></plan-component>
<plan-component :
name="Team"
most-popular=true
></plan-component>
<plan-component :
name="Club"
most-popular=false
></plan-component>
</ul>
<template id="plan-component">
<li v-bind:class="{ 'most-popular': mostPopular == true }">
<template v-if="most-popular === true">
<span class="popular-plan-label">Most popular</span>
</template>
<p>{{ name }}</p>
</li>
</template>
</div>
And here is the JS.
Vue.component('plan-component', {
template: '#plan-component',
props: ['name', 'mostPopular'],
});
new Vue({
el: '#app';
});
You need to validate the mostPopular property type, since it's Boolean it won't work when you place most-popular=true because it's considered as a string "true" not true instead put most-popular tag on popular plan only. Here is example:
Vue.component('plan-component', {
template: '#plan-component',
props: {
name: String,
mostPopular: {
type: Boolean,
default: false,
}
},
});
new Vue({
el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.25/vue.min.js"></script>
<div id="app">
<ul class="plans">
<plan-component name="Basic"></plan-component>
<plan-component name="Recreational"></plan-component>
<plan-component name="Team" most-popular></plan-component>
<plan-component name="Club"></plan-component>
</ul>
</div>
<template id="plan-component">
<li v-bind:class="{ 'most-popular': mostPopular }">
<p>{{ name }} <small v-if="mostPopular" class="popular-plan-label" style="color: red">Most popular</small></p>
</li>
</template>
Use <template v-if="ok"> for conditional rendering.