How to override default values of a vuejs component? - vue.js

I've implemented a VUEJS plugin (via CDN) and it works, but I cannot change the default props.. any idea how to change the defaults?
In the code below you can see my attempt to accomplish this
html:
<tags-dic element-id="tags" v-model="selectedTags" :typeahead="true"></tags-input>
<script src="https://cdn.jsdelivr.net/npm/#voerro/vue-tagsinput#1.11.2/dist/voerro-vue-tagsinput.js"></script>
vue/javascript:
<script type="text/javascript">
var app = new Vue({
el: '#searchapp',
components: { "tags-dic": VoerroTagsInput },
data: {
query: "",
typeahead: true,
placeholder: 'Add a new tag',
limit: 1,
onlyExistingTags: true,
existingTags: [
'DNA',
'RNA',
'Protein',
],
selectedTags: [],
},
methods: {
submit: function() {
console.log("clicked");
if (this.query) {
console.log("OK");
}
}
}
})
</script>
Thanks

You can supply your own property values in the template. (See the docs for details.)
<tags-dic
element-id="tags"
v-model="selectedTags"
:typeahead="true"
:existing-tags="existingTags"
:placeholder="placeholder"
/>
and so on

Related

How to use v-model in QuillJS in vue 3 app?

If I try to use v-model in the div with editor reference it gives me this error:
"'v-model' directives aren't supported on elements."
<div ref="editor"></div>
<script>
import Quill from "quill";
export default {
data() {
return {
description: "", // variable that I'm trying to use in v-model
options: {
modules: {
toolbar: ["bold", "italic", { list: "ordered" }, { list: "bullet" }],
},
theme: "snow",
},
};
},
watch: {
isDescription(newVal, oldVal) {
if (newVal == true) {
setTimeout(() => {
new Quill(this.$refs.editor, this.options);
}, 1);
}
},
},
};
</script>

How to use google data-table chart in vuejs project?

In my vuejs project how to use google data-table chart? Google data-table chart link given below:
https://developers.google.com/chart/interactive/docs/gallery/table
I can implement this chart in normal javascript code. But how to use in vuejs code.
You can use your own component. Here I have made one simple example.
Vue.component('google-data-table', {
template: `<div id='app' ref="table_div"></div>`,
props: {
columns: {
type: Array,
required: true
},
tableData: {
type: Array,
required: true
}
},
mounted() {
google.charts.load('current', {
'packages': ['table']
});
google.charts.setOnLoadCallback(this.drawTable);
},
methods: {
drawTable: function() {
var data = new google.visualization.DataTable();
this.columns.forEach(element => {
data.addColumn(element.type, element.title);
});
data.addRows(this.tableData);
var table = new google.visualization.Table(this.$refs.table_div);
table.draw(data, {
showRowNumber: true,
width: '100%',
height: '100%'
});
}
}
});
new Vue({
el: '#app',
data: {
columns: [{
type: 'string',
title: 'Name'
},
{
type: 'number',
title: 'Salary'
},
{
type: 'boolean',
title: 'Full Time Employee'
}
],
tableData: [
['Mike', {
v: 10000,
f: '$10,000'
}, true],
['Jim', {
v: 8000,
f: '$8,000'
}, false],
['Alice', {
v: 12500,
f: '$12,500'
}, true],
['Bob', {
v: 7000,
f: '$7,000'
}, true]
]
}
});
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
</head>
<body>
<div id="app">
<google-data-table :columns='columns' :table-data='tableData' />
</div>
</body>
</html>

Vuejs - list - How to pass click functions as string

I have an array of objects, each with a click property (a string) that is passed to a click-event handler. I can print the .click property to the console, but it is not recognized as Vue data. I tried to eval(todo.click), but it didn't work.
html:
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<label #click="clickMethod(todo)">{{todo.text}}</label>
</li>
</ol>
<br>
<div v-if="infoVisible">infoVisible</div>
<div v-if="tresVisible">tresVisible</div>
</div>
and my js:
new Vue({
el: "#app",
data: {
infoVisible:false,
tresVisible:true,
todos: [
{ text: "Learn JavaScript", done: false, click:'infoVisible=!infoVisible' },
{ text: "Learn Vue", done: false, click:'infoVisible=!infoVisible' },
{ text: "Play around in JSFiddle", done: true , click:'infoVisible=!infoVisible'},
{ text: "Build something awesome", done: true , click:'tresVisible=!tresVisible'}
]
},
methods: {
clickMethod(todo){
console.log(todo.click)
todo.click()
}
}
})
Fiddle
Instead of using strings as functions (which would require eval()), you could define function expressions:
new Vue({
el: "#app",
data: (vm) => ({
infoVisible: false,
tresVisible: true,
todos: [
{ ..., click() { vm.infoVisible = !vm.infoVisible } },
{ ..., click() { vm.infoVisible = !vm.infoVisible } },
{ ..., click() { vm.infoVisible = !vm.infoVisible } },
{ ..., click() { vm.tresVisible = !vm.tresVisible } },
]
}),
methods: {
clickMethod(todo){
todo.click()
}
}
})
Steps:
In todos[], change the type of .click properties from strings to function expressions:
//click: 'infoVisible = !infoVisible' // from strings
click() { infoVisible = !infoVisible } // to function expressions (to be updated in step 3)
In the function body, a reference to the Vue instance is required so that click() can change the data properties (i.e., infoVisible and tresVisible). Update the Vue declaration's data property to be a function that takes an argument (the argument will be the Vue instance itself):
data: (vm) => ({/* ... */})
Update click() to use that argument to reference the target data properties:
click() { vm.infoVisible = !vm.infoVisible }
^^^ ^^^
updated fiddle
eval(todo.click) will work but you need to add "this." to all of the todo properties in the click attributes so they have the right context, that is the context of the Vue instance.
new Vue({
el: "#app",
data: {
infoVisible:false,
tresVisible:true,
todos: [
{ text: "Learn JavaScript", done: false, click:'this.infoVisible=!this.infoVisible' },
{ text: "Learn Vue", done: false, click:'this.infoVisible=!this.infoVisible' },
{ text: "Play around in JSFiddle", done: true , click:'this.infoVisible=!this.infoVisible'},
{ text: "Build something awesome", done: true , click:'this.tresVisible=!this.tresVisible'},
]
},
methods: {
clickMethod(todo){
eval(todo.click)
}
}
})

VueJs: Form handling with Vuex and inputs generated with an API

Here's an example of a component:
<script>
export default {
name: 'my-form',
computed: {
myModules() {
return this.$store.state.myModules;
}
}
</script>
<template>
<form>
<p v-for="module in myModules">
<input type="checkbox" :value="module.id" />
<label>module.name</label>
</p>
<button type="submit">Submit</button>
</form>
</template>
The associated store:
state: {
myModules: []
},
mutations: {
setModules(state, modules) {
state.myModules = modules;
}
},
actions: {
getModules({commit}) {
return axios.get('modules')
.then((response) => {
commit('setModules', response.data.modules);
});
}
}
And finally, an example of return of the API "getModules":
modules : [
{
id: 1,
name: 'Module 1',
isActive: false
},
{
id: 2,
name: 'Module 2',
isActive: false
},
{
id: 3,
name: 'Module 3',
isActive: false
}
]
My question: what's the best way to change the "isActive" property of each module to "true" when I check the checkbox corresponding to the associated module, directly in the store?
I know that Vuex's documentation recommends to use "Two-way Computed Property" to manage the forms, but here I don't know the number of modules that the API can potentially return, and I don't know their name.
Thank you in advance!
This is a little bit wicked approach, but it works. You can create an accessor object for every item you access in a loop:
const store = new Vuex.Store({
mutations: {
setActive (state, {index, value}) {
state.modules[index].isActive = value
}
},
state: {
modules : [
{
id: 1,
name: 'Module 1',
isActive: false
},
{
id: 2,
name: 'Module 2',
isActive: false
},
{
id: 3,
name: 'Module 3',
isActive: false
}
]
}
});
const app = new Vue({
el: '#target',
store,
methods: {
model (id) {
const store = this.$store;
// here i return an object with value property that is bound to
// specific module and - thanks to Vue - retains reactivity
return Object.defineProperty({}, 'value', {
get () {
return store.state.modules[id].isActive
},
set (value) {
store.commit('setActive', {index: id, value});
}
});
}
}
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.min.js"></script>
<div id="target">
<div v-for="(item, id) in $store.state.modules">
Module #{{ item.id }} state: {{ item.isActive }}
</div>
<div v-for="(item, id) in $store.state.modules">
<label>
Module #{{ item.id }}
<input type="checkbox" v-model="model(id).value"/>
</label>
</div>
</div>
This is still quite a messy approach, but at least you don't have to commit mutations directly in template. With a little help of Vue.set() you can use this approach even to overcome standard reactivity caveats.
I have an alternative solution for you. You could make a child component for the checkboxes to clean up the code a bit.
UPD: I just realised that everything that I and #etki proposed is an overkill. I left the old version of my code below in case you still want to take a look. Here is a new one:
const modules = [{
id: 1,
name: 'Module 1',
isActive: true,
},
{
id: 2,
name: 'Module 2',
isActive: false,
},
{
id: 3,
name: 'Module 3',
isActive: false,
},
];
const store = new Vuex.Store({
state: {
myModules: [],
},
mutations: {
SET_MODULES(state, modules) {
state.myModules = modules;
},
TOGGLE_MODULE(state, id) {
state.myModules.some((el) => {
if (el.id === id) {
el.isActive = !el.isActive;
return true;
}
})
}
},
actions: {
getModules({
commit
}) {
return new Promise((fulfill) => {
setTimeout(() => {
commit('SET_MODULES', modules);
fulfill(modules);
}, 500)
});
}
}
});
const app = new Vue({
el: "#app",
store,
data: {},
methods: {
toggle(id) {
console.log(id);
this.$store.commit('TOGGLE_MODULE', id);
}
},
computed: {
myModules() {
return this.$store.state.myModules;
},
output() {
return JSON.stringify(this.myModules, null, 2);
},
},
mounted() {
this.$store.dispatch('getModules').then(() => console.log(this.myModules));
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<script src="https://unpkg.com/vue"></script>
<div id="app">
<form>
<div v-for="data in myModules">
<label :for="data.id">{{ data.name }}: {{data.isActive}}</label>
<input type="checkbox" :id="data.id" :name="'checkbox-' + data.id" :checked="data.isActive" #change="toggle(data.id)">
</div>
</form>
<h3>Vuex state:</h3>
<pre v-text="output"></pre>
</div>
As you can see above you could just call a function on input change and pass an id as a parameter to a method that fires vuex action.
The old version of my code.
A new one on jsfiddle

Vue filters migration from vue 1 to vue 2

I have problem with migratiing filters from vue 1 to vue 2, I created exactly what I need here (highlighting text which match the input text):
Vue.component('demo-grid', {
template: '#grid-template',
props: {
filterKey: String
},
data: function () {
return {
searchParams: [
{ key: '' }
],
suggestions: [
{ message: 'Foo' },
{ message: 'Bar' },
{ message: 'Foobar' },
{ message: 'pikachu' },
{ message: 'raichu' }
]
}
},
filters: {
highlight: function(words, query){
var iQuery = new RegExp(query, "ig");
return words.replace(iQuery, function(matchedTxt,a,b){
return ('<span class=\'highlight\'>' + matchedTxt + '</span>');
});
}
}
})
// bootstrap the demo
var demo = new Vue({
el: '#demo'
})
https://jsfiddle.net/t5ac1quc/23/ VUE-1 resource
https://jsfiddle.net/t5ac1quc/25/ VUE-2 resource
I would be very grateful, for all the answers
Updated fiddle.
<template id="grid-template">
<ul>
<li v-for="suggest in suggestions" v-html="highlight(suggest.message, filterKey)"></li>
</ul>
</template>
<div id="demo">
<form>
Search <input v-model="searchParams.key">
</form>
<demo-grid :filter-key="searchParams.key"></demo-grid>
</div>
Vue.component('demo-grid', {
template: '#grid-template',
props: {
filterKey: String
},
data: function () {
return {
suggestions: [
{ message: 'Foo' },
{ message: 'Bar' },
{ message: 'Foobar' },
{ message: 'pikachu' },
{ message: 'raichu' }
]
}
},
methods: {
highlight: function(words, query) {
var iQuery = new RegExp(query, "ig");
return words.replace(iQuery, function(matchedTxt,a,b){
return ('<span class=\'highlight\'>' + matchedTxt + '</span>');
});
}
}
})
new Vue({
el: '#demo',
data: {
searchParams: {
key: '',
},
},
});
Summary:
When using <script> tags to store templates, set type="template" (or similar) to prevent the browser from executing the template as JavaScript. Or better yet use <template> instead.
{{{ html }}} syntax is no longer supported. In Vue 2 you must use the v-html directive instead.
Since v-html is a directive (and doesn't use {{ }} interpolation), it doesn't use the filter syntax. Use a method instead.
You had some issues with the scope of the data. The root component needs to define data for searchParams which is used in its template. Also searchParams was an array but you weren't using it as an array (searchParams.key); this will not work with Vue 2 (all reactive data properties must be properly declared upfront).