Vue v-html renders [object HTMLQuoteElement] - javascript

I'm trying to create a generic slideshow component using slots. I'm able to access the elements passed into the slot, and when I log them they appear to be DOM elements, but when they appear on the page they're just [object HTMLQuoteElement].
Here's the component:
<template>
<div :class="cssClasses">
<div v-show="false">
<slot></slot>
</div>
<transition v-if="slots.length" name="carousel-fade" tag="div">
<div v-html="currentSlide"></div>
</transition>
</div>
</template>
<script>
export default {
props: {
// Classes to apply to wrapping element.
cssClasses: { default: '' },
// Integer for miliseconds to remain on each slide.
interval: { default: 5000 }
},
data() {
return {
// Internal: Timer for playing through slides.
timer: null,
// Internal: Current slide.
index: 0
}
},
computed: {
currentSlide() {
if (this.$slots.default[this.index].elm) {
console.log('currentSlide', this.$slots.default[this.index].elm) // prints correctly
return this.$slots.default[this.index].elm // renders wrong
}
return ''
},
slots() {
return this.$slots.default
}
},
methods: {
// Internal: Start slideshow.
startSlide() {
if (this.timer) clearInterval(this.timer)
this.timer = setInterval(this.next, this.interval)
},
// Internal: Render next slide. If at end, return to the beginning.
next() {
this.startSlide()
if (this.index === this.slots.length - 1) {
this.index = 0
} else {
this.index += 1
}
}
},
mounted() {
this.startSlide()
}
}
</script>
The goal is to be able to pass any html elements into the slot so the slideshow goes through them. At this point I'm just adding nonsense text because stack overflow won't let me post my question because it's mostly code. But really, there isn't much more to say. You can read the code. You know what I'm trying to do. If I'm doing something wrong, let me know. There isn't a point in me wasting both of our time so a robot can count characters to decide one has enough information.

Related

TipTap Vue component - how to toggle wrap on node from component button

The awesome tiptap wrapper for prosemirror comes with nice documentation but it lacks some clarification how to approach some (i think) basic scenarios when developing custom extensions.
My question is how to invoke toggleWrap on the node when in vue component's context.
I found example that uses transactions and allows for delete - but what i want is to clear the node leaving the text of node intact.
get view() {
return {
directives: {
"click-outside": clickOutside
},
props: ['node', 'updateAttrs', 'view', 'selected', 'getPos'],
data() {
return {
showMenu: false
}
},
computed: {
href: {
get() {
return this.node.attrs.href
},
set(href) {
this.updateAttrs({
href,
})
},
},
},
methods: {
// deleteNode() {
// let transaction = this.view.state.tr // tr - transaction
// let pos = this.getPos()
// transaction.delete(pos, pos + this.node.nodeSize)
// this.view.dispatch(transaction)
// },
stopLinkPropagation(){
return null;
},
hideMenu(){
this.showMenu = false
}
},
template: `<div #click="showMenu = true" v-click-outside="hideMenu">
<a class="email-button" #click.prevent="stopLinkPropagation" :href="href" v-text="node.textContent"></a>
<input class="iframe__input" type="text" v-model="href" v-if="showMenu" />
<button #click="clearNode">clear button wrap</button>
</div>`,
}
}
Any help would be awesome. Thanks.

Perform operation on data table row in Vue child component once async data is loaded

I have child component that utilizes a Vuetify v-data-table, and when the page that displays this component and its parent are displayed, I want to have the first item in the list highlighted (the data for the item is displayed above it in the parent component, too). I also want to have the row highlighted when it is selected and the data for that row is displayed in the parent.
Based on this answer, I have the second part working fine, and the first part (highlighting the first row on initial display) working, but only to an extent.
<template>
<div>
<v-data-table
:headers="headers"
:items="items"
:search="search"
:key="tableKey"
:pagination.sync="pagination"
disable-initial-sort
rowKey
>
<template slot="items" slot-scope="props">
<tr #click="clicked(props.item)" :class="{'secondary': props.item[rowKey]===selectedCode}">
<td v-for="header in headers" :key="header.value">
<BaseTableColumn
:item="props.item"
:index="header.value"
:format="header.format"
/>
</td>
</tr>
</template>
</v-data-table>
</div>
</template>
<script>
export default {
name: 'BaseTable',
props: {
headers: Array,
items: Array,
search: String,
tableKey: String,
rowKey: String,
},
data: () => ({
pagination: {
rowsPerPage: 10,
totalItems: -1,
},
selectedCode: -1,
itemsYN: false,
}),
components: {
BaseTableColumn: () => import('#/components/base/BaseTableColumn'),
},
methods: {
clicked(row) {
window.scrollTo(0, 0);
this.selectedCode = row[this.rowKey];
this.$set(row, 'selected', true);
this.$emit('rowClick', row);
},
},
mounted() {
// Select the first item in the list of items (if there are any)
// and highlight it.
if (this.items.length > 0) {
this.selectedCode = this.items[0][this.rowKey];
this.$set(this.items[0], 'selected', true);
}
},
};
</script>
where this component is called from the parent like so:
<BaseTable
:headers="headers"
:items="alerts"
:search="search"
rowKey="messageId"
#rowClick="rowClick"
/>
As of now, I have the code for the initial highlighting in the mounted() hook. This works fine when all of the items data is already available at mount time, but if the call to get the data takes longer and isn't loaded until it's past that point in the lifecycle, then I don't get the highlighting. The same is true if I used the created() hook
My thought was to watch the items prop, and once it is filled, call the highlighting code, like so:
watch: {
items(val) {
if (this.items.length > 0) {
this.highlightFirst(val)
}
},
},
methods: {
clicked(row) {
window.scrollTo(0, 0);
this.selectedCode = row[this.rowKey];
this.$set(row, 'selected', true);
this.$emit('rowClick', row);
},
highlightFirst(items) {
this.selectedCode = this.items[0][this.rowKey];
this.$set(this.items[0], 'selected', true);
},
},
mounted() {
// Select the first item in the list of items (if there are any)
// and highlight it.
if (this.items.length > 0) {
this.highlightFirst(this.items);
}
},
but since items is updated whenever a row is selected, this overrides the clicked() method, and so the first item is highlighted, not the one that was clicked on.
Since this component is a child of 14 components, I would like to handle this in this component instead of adding a passed in prop from all the parents to indicate when the data is loaded. How can I highlight the first row on initial page load, waiting for async data to passed in, without stomping on the clicked() method when an individual row is clicked?
You can declare a variable where you can store true when click the button and set false when entering the watch
data: (){
return {
fromClick: true;
}
},
watch: {
items(val) {
if (!fromClick) {
this.highlightFirst();
}
this.fromClick = false;
}
},
methods: {
clicked(row) {
this.fromClick = true;
window.scrollTo(0, 0);
this.hightlightRow(row);
this.$emit('rowClick', row);
},
highlightFirst() {
if (this.items.length > 0) {
this.hightlightRow(this.items[0]);
}
},
hightlightRow(row) {
this.selectedCode = row[this.rowKey];
this.$set(row, 'selected', true);
}
},
mounted() {
// Select the first item in the list of items (if there are any)
// and highlight it.
this.highlightFirst();
},
I managed to fix this in a simpler way with the following code.
props: {
headers: Array,
items: Array,
search: String,
tableKey: String,
rowKey: String,
},
data: () => ({
...
selectedCode: -1,
}),
methods: {
clicked(row) {
window.scrollTo(0, 0);
this.selectedCode = row[this.rowKey];
this.$set(row, 'selected', true);
this.$emit('rowClick', row);
},
highlightFirst(items) {
this.selectedCode = this.items[0][this.rowKey];
this.$set(this.items[0], 'selected', true);
},
},
updated() {
if (this.selectedCode === -1 && && (typeof this.items === 'object') && this.items.length > 0) {
this.highlightFirst(this.items);
}
},
Once this.selectedCode has a value after highlightFirst() is run, nothing happens in update(), and the clicked() method works as it should when a row is clicked.

VueJS / JS DOM Watch / Observer in a multi phase render scenario

Scenario:
I’m developing a Vue scroll component that wraps around a dynamic number of HTML sections and then dynamically builds out vertical page navigation allowing the user to scroll or jump to page locations onScroll.
Detail:
a. In my example my scroll component wraps 3 sections. All section id’s start with "js-page-section-{{index}}"
b. The objective is to get the list of section nodes (above) and then dynamically build out vertical page (nav) navigation based on the n number of nodes found in the query matching selector criteria. Therefore, three sections will result in three page section navigation items. All side navigation start with “js-side-nav-{{index}}>".
c. Once the side navigation is rendered I need to query all the navigation nodes in order to control classes, heights, display, opacity, etc. i.e document.querySelectorAll('*[id^="js-side-nav"]');
EDIT
Based on some research here are the options for my problem. Again my problem being 3 phase DOM state management i.e. STEP 1. Read all nodes equal to x, then STEP 2. Build Side Nav scroll based on n number of nodes in document, and then STEP 3. Read all nav nodes to sync with scroll of document nodes:
Create some sort of event system is $emit() && $on. In my opinion this gets messy very quickly and feels like a poor solution. I found myself quickly jumping to $root
Vuex. but that feels like an overkill
sync. Works but really that is for parent child property state management but that again requires $emit() && $on.
Promise. based service class. This seems like the right solution, but frankly it became a bit of pain managing multiple promises.
I attempted to use Vue $ref but frankly it seems better for managing state rather than multi stage DOM manipulation where a observer event approach is better.
The solution that seems to work is Vues $nextTick(). which seems to be similar to AngularJS $digest. In essence it is a . setTimeout(). type approach just pausing for next digest cycle. That said there is the scenario where the tick doesn’t sync the time requires so I built a throttle method. Below is the code update for what is worth.
The refactored watch with nextTick()
watch: {
'page.sections': {
handler(nodeList, oldNodeList){
if (this.isNodeList(nodeList) && _.size(nodeList) && this.sideNavActive) {
return this.$nextTick(this.sideNavInit);
}
},
deep: true
},
},
The REFACTORED Vue component
<template>
<div v-scroll="handleScroll">
<nav class="nav__wrapper" id="navbar-example">
<ul class="nav">
<li role="presentation"
:id="sideNavPrefix + '-' + (index + 1)"
v-for="(item, key,index) in page.sections">
<a :href="'#' + getAttribute(item,'id')">
<p class="nav__counter" v-text="('0' + (index + 1))"></p>
<h3 class="nav__title" v-text="getAttribute(item,'data-title')"></h3>
<p class="nav__body" v-text="getAttribute(item,'data-body')"></p>
</a>
</li>
</ul>
</nav>
<slot></slot>
</div>
</template>
<script>
import ScrollPageService from '../services/ScrollPageService.js';
const _S = "section", _N = "sidenavs";
export default {
name: "ScrollSection",
props: {
nodeId: {
type: String,
required: true
},
sideNavActive: {
type: Boolean,
default: true,
required: false
},
sideNavPrefix: {
type: String,
default: "js-side-nav",
required: false
},
sideNavClass: {
type: String,
default: "active",
required: false
},
sectionClass: {
type: String,
default: "inview",
required: false
}
},
directives: {
scroll: {
inserted: function (el, binding, vnode) {
let f = function(evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
};
window.addEventListener('scroll', f);
}
},
},
data: function () {
return {
scrollService: {},
page: {
sections: {},
sidenavs: {}
}
}
},
methods: {
getAttribute: function(element, key) {
return element.getAttribute(key);
},
updateViewPort: function() {
if (this.scrollService.isInCurrent(window.scrollY)) return;
[this.page.sections, this.page.sidenavs] = this.scrollService.updateNodeList(window.scrollY);
},
handleScroll: function(evt, el) {
if ( !(this.isScrollInstance()) ) {
return this.$nextTick(this.inViewportInit);
}
this.updateViewPort();
},
getNodeList: function(key) {
this.page[key] = this.scrollService.getNodeList(key);
},
isScrollInstance: function() {
return this.scrollService instanceof ScrollPageService;
},
sideNavInit: function() {
if (this.isScrollInstance() && this.scrollService.navInit(this.sideNavPrefix, this.sideNavClass)) this.getNodeList(_N);
},
inViewportInit: function() {
if (!(this.isScrollInstance()) && ((this.scrollService = new ScrollPageService(this.nodeId, this.sectionClass)) instanceof ScrollPageService)) this.getNodeList(_S);
},
isNodeList: function(nodes) {
return NodeList.prototype.isPrototypeOf(nodes);
},
},
watch: {
'page.sections': {
handler(nodeList, oldNodeList){
if (this.isNodeList(nodeList) && _.size(nodeList) && this.sideNavActive) {
return this.$nextTick(this.sideNavInit);
}
},
deep: true
},
},
mounted() {
return this.$nextTick(this.inViewportInit);
},
}
</script>
END EDIT
ORIGINAL POST
Problem & Question:
PROBLEM:
The query of sections and render of navs work fine. However, querying the nav elements fails as the DOM has not completed the render. Therefore, I’m forced to use a setTimeout() function. Even if I use a watch I’m still forced to use timeout.
QUESTION:
Is there a promise or observer in Vue or JS I can use to check to see when the DOM has finished rendering the nav elements so that I can then read them? Example in AngularJS we might use $observe
HTML EXAMPLE
<html>
<head></head>
<body>
<scroll-section>
<div id="js-page-section-1"
data-title="One"
data-body="One Body">
</div>
<div id="js-page-section-2"
data-title="Two"
data-body="Two Body">
</div>
<div id="js-page-section-3"
data-title="Three"
data-body="THree Body">
</div>
</scroll-section>
</body>
</html>
Vue Compenent
<template>
<div v-scroll="handleScroll">
<nav class="nav__wrapper" id="navbar-example">
<ul class="nav">
<li role="presentation"
:id="[idOfSideNav(key)]"
v-for="(item, key,index) in page.sections.items">
<a :href="getId(item)">
<p class="nav__counter">{{key}}</p>
<h3 class="nav__title" v-text="item.getAttribute('data-title')"></h3>
<p class="nav__body" v-text="item.getAttribute('data-body')"></p>
</a>
</li>
</ul>
</nav>
<slot></slot>
</div>
</template>
<script>
export default {
name: "ScrollSection",
directives: {
scroll: {
inserted: function (el, binding, vnode) {
let f = function(evt) {
_.forEach(vnode.context.page.sections.items, function (elem,k) {
if (window.scrollY >= elem.offsetTop && window.scrollY <= (elem.offsetTop + elem.offsetHeight)) {
if (!vnode.context.page.sections.items[k].classList.contains("in-viewport") ) {
vnode.context.page.sections.items[k].classList.add("in-viewport");
}
if (!vnode.context.page.sidenavs.items[k].classList.contains("active") ) {
vnode.context.page.sidenavs.items[k].classList.add("active");
}
} else {
if (elem.classList.contains("in-viewport") ) {
elem.classList.remove("in-viewport");
}
vnode.context.page.sidenavs.items[k].classList.remove("active");
}
});
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
};
window.addEventListener('scroll', f);
},
},
},
data: function () {
return {
page: {
sections: {},
sidenavs: {}
}
}
},
methods: {
handleScroll: function(evt, el) {
// Remove for brevity
},
idOfSideNav: function(key) {
return "js-side-nav-" + (key+1);
},
classOfSideNav: function(key) {
if (key==="0") {return "active"}
},
elementsOfSideNav:function() {
this.page.sidenavs = document.querySelectorAll('*[id^="js-side-nav"]');
},
elementsOfSections:function() {
this.page.sections = document.querySelectorAll('*[id^="page-section"]');
},
},
watch: {
'page.sections': function (val) {
if (_.has(val,'items') && _.size(val.items)) {
var self = this;
setTimeout(function(){
self.elementsOfSideNavs();
}, 300);
}
}
},
mounted() {
this.elementsOfSections();
},
}
</script>
I hope I can help you with what I'm going to post here. A friend of mine developed a function that we use in several places, and reading your question reminded me of it.
"Is there a promise or observer in Vue or JS I can use to check to see when the DOM has finished rendering the nav elements so that I can then read them?"
I thought about this function (source), here below. It takes a function (observe) and tries to satisfy it a number of times.
I believe you can use it at some point in component creation or page initialization; I admit that I didn't understand your scenario very well. However, some points of your question immediately made me think about this functionality. "...wait for something to happen and then make something else happen."
<> Credits to #Markkop the creator of that snippet/func =)
/**
* Waits for object existence using a function to retrieve its value.
*
* #param { function() : T } getValueFunction
* #param { number } [maxTries=10] - Number of tries before the error catch.
* #param { number } [timeInterval=200] - Time interval between the requests in milis.
* #returns { Promise.<T> } Promise of the checked value.
*/
export function waitForExistence(getValueFunction, maxTries = 10, timeInterval = 200) {
return new Promise((resolve, reject) => {
let tries = 0
const interval = setInterval(() => {
tries += 1
const value = getValueFunction()
if (value) {
clearInterval(interval)
return resolve(value)
}
if (tries >= maxTries) {
clearInterval(interval)
return reject(new Error(`Could not find any value using ${tries} tentatives`))
}
}, timeInterval)
})
}
Example
function getPotatoElement () {
return window.document.querySelector('#potato-scroller')
}
function hasPotatoElement () {
return Boolean(getPotatoElement())
}
// when something load
window.document.addEventListener('load', async () => {
// we try sometimes to check if our element exists
const has = await waitForExistence(hasPotatoElement)
if (has) {
// and if it exists, we do this
doThingThatNeedPotato()
}
// or you could use a promise chain
waitForExistence(hasPotatoElement)
.then(returnFromWaitedFunction => { /* hasPotatoElement */
if (has) {
doThingThatNeedPotato(getPotatoElement())
}
})
})

Displaying backend responses on the webpage

I'm new to this, please be kind!
How do I transfer the value of the object that was returned to me in the console to the webpage? As of now, the balance value is in the console but it is not displayed on the page.
edit: If I wish to display the objects in the console separately, do I use myObj.key? eg. I want to display the value of balance on the left and the value of block on the right of my webpage, do I use myObj.balance and myObj.block ?
attached a screenshot of my browser
This is my code, do guide me, thank you!
<template>
<div class="box-card">
<p class="title-text">余额</p>
<p class="number-text">{{Balance}}</p>
</div>
</template>
<script>
export default {
data() {
return {
userId: 0,
// page config
currentPage: 1,
total: 0,
pageSize: 20,
userBalance: [],
Balance: '',
}
},
watch: {},
mounted() {
this.userId = this.$route.query["user_id"];
this.userId = 41;
this.getUserBalance();
this.getUserIncomeRecord();
console.log('hello');
},
methods: {
pageChange(val) {
this.currentPage = val;
},
getUserBalance() {
Core.Api.User.getUserBalance(this.userId).then(res => {
console.log(res);
res == this.Balance;
})
},
</script>
EDITED: If you want to print in a element with certain ID instead of console.log("WHAT YOU WANT TO PRINT") use this:
document.getlementById("YOUR ELEMENT ID HERE").innerHtml("WHAT YOU WANT TO PRINT");
If you use Jquery this is equivalent to the above code:
$("#ELEMENT ID HERE").html("WHAT YOU WANT TO PRINT");
make a slight change:
getUserBalance() {
Core.Api.User.getUserBalance(this.userId).then(res => {
console.log(res);
this.Balance = res;
})
},

vue.js: how to handle click and dblclick events on same element

I have a vue component with separate events for click/dblclick. Single click (de)selects row, dblclick opens edit form.
<ul class="data_row"
v-for="(row,index) in gridData"
#dblclick="showEditForm(row,$event)"
#click="rowSelect(row,$event)"
>
Doing it like this, i get 3 events fired on double click. Two click events and lastly one dblclick. Since the click event fires first , is there a way (short of deferring click event for a fixed amount of ms) for stopping propagation of click event on double click ?
Fiddle here
As suggested in comments, You can simulate the dblclick event by setting up a timer for a certain period of time(say x).
If we do not get another click during that time span, go for the single_click_function().
If we do get one, call double_click_function().
Timer will be cleared once the second click is received.
It will also be cleared once x milliseconds are lapsed.
See below code and working fiddle.
new Vue({
el: '#app',
data: {
result: [],
delay: 700,
clicks: 0,
timer: null
},
mounted: function() {
console.log('mounted');
},
methods: {
oneClick(event) {
this.clicks++;
if (this.clicks === 1) {
this.timer = setTimeout( () => {
this.result.push(event.type);
this.clicks = 0
}, this.delay);
} else {
clearTimeout(this.timer);
this.result.push('dblclick');
this.clicks = 0;
}
}
}
});
<div id="example-1">
<button v-on:dblclick="counter += 1, funcao()">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
var example1 = new Vue({
el: '#example-1',
data: {
counter: 0
},
methods: {
funcao: function(){
alert("Sou uma funcao");
}
}
})
check out this working fiddle https://codepen.io/robertourias/pen/LxVNZX
i have a simpler solution i think (i'm using vue-class but same principle apply):
private timeoutId = null;
onClick() {
if(!this.timeoutId)
{
this.timeoutId = setTimeout(() => {
// simple click
}, 50);//tolerance in ms
}else{
clearTimeout(this.timeoutId);
// double click
}
}
it does not need to count the number of clicks.
The time must be short between click and click.
In order to get the click and double click, only one counter is required to carry the number of clicks(for example 0.2s) and it is enough to trap the user's intention when he clicks slowly or when he performs several that would be the case of the double click or default case.
I leave here with code how I implement these features.
new Vue({
el: '#app',
data: {numClicks:0, msg:''},
methods: {
// detect click event
detectClick: function() {
this.numClicks++;
if (this.numClicks === 1) { // the first click in .2s
var self = this;
setTimeout(function() {
switch(self.numClicks) { // check the event type
case 1:
self.msg = 'One click';
break;
default:
self.msg = 'Double click';
}
self.numClicks = 0; // reset the first click
}, 200); // wait 0.2s
} // if
} // detectClick function
}
});
span { color: red }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js"></script>
<div id='app'>
<button #click='detectClick'>
Test Click Event, num clicks
<span>{{ numClicks }}</span>
</button>
<h2>Last Event: <span>{{ msg }}</span></h2>
</div>
I use this approach for the same problem. I use a promise that is resolved either by the timeout of 200ms being triggered, or by a second click being detected. It works quite well in my recent web apps.
<div id="app">
<div
#click="clicked().then((text) => {clickType = text})">
{{clickType}}
</div>
</div>
<script>
new Vue({
el: "#app",
data: {
click: undefined,
clickType: 'Click or Doubleclick ME'
},
methods: {
clicked () {
return new Promise ((resolve, reject) => {
if (this.click) {
clearTimeout(this.click)
resolve('Detected DoubleClick')
}
this.click = setTimeout(() => {
this.click = undefined
resolve('Detected SingleClick')
}, 200)
})
}
}
})
</script>
Working fiddle:
https://jsfiddle.net/MapletoneMartin/9m62Lrwf/
vue Component
// html
<div class="grid-content">
<el-button
   #click.native="singleClick"
   #dblclick.native="doubleClick"
   class="inline-cell">
click&dbclickOnSameElement</el-button>
</div>
// script
<script>
let time = null; // define time be null
export default {
name: 'testComponent',
data() {
return {
test:''
};
},
methods: {
singleClick() {
// first clear time
clearTimeout(time);
time = setTimeout(() => {
console.log('single click ing')
}, 300);
},
  
doubleClick() {
clearTimeout(time);
console.log('double click ing');
}
}
}
</script>
selectedFolder = ''; // string of currently selected item
folderSelected = false; // preview selected item
selectFolder(folder) {
if (this.selectedFolder == folder) {
// double click
this.folderSelected = false;
this.$store.dispatch('get_data_for_this_folder', folder);
} else {
// single click
this.selectedFolder = folder;
this.folderSelected = true;
}
},
#click.stop handles a single click and #dblclick.stop handles double click
<v-btn :ripple="false"
class="ma-0"
#click.stop="$emit('editCompleteGrvEvent', props.item)"
#dblclick.stop="$emit('sendCompleteGrvEvent',props.item)">
<v-icon>send</v-icon>
</v-btn>
Unless you need to do expensive operations on single select, you can rework rowSelect into a toggle. Setting a simple array is going to be a lot faster, reliable, and more straightforward compared to setting up and canceling timers. It won't matter much if the click event fires twice, but you can easily handle that in the edit function.
<template>
<ul>
<li :key="index" v-for="(item, index) in items">
<a
:class="{ 'active-class': selected.indexOf(item) !== -1 }"
#click="toggleSelect(item)"
#dblclick="editItem(item)"
>
{{ item.title }}
</a>
<!-- Or use a checkbox with v-model
<label #dblclick="editItem(item)">
<input type="checkbox" :value="item.id" v-model.lazy="selected" />
{{ item.title }}
</label>
-->
</li>
</ul>
</template>
<script>
export default {
data: function () {
return {
items: [
{
id: 1,
title: "Item 1",
},
{
id: 2,
title: "Item 2",
},
{
id: 3,
title: "Item 3",
},
],
selected: [],
};
},
methods: {
editItem(item) {
/*
* Optionally put the item in selected
* A few examples, pick one that works for you:
*/
// this.toggleSelect(item); // If the item was selected before dblclick, it will still be selected. If it was unselected, it will still be unselected.
// this.selected = []; // Unselect everything.
// Make sure this item is selected:
// let index = this.selected.indexOf(item.id);
// if (index === -1) {
// this.selected.push(item.id);
// }
// Make sure this item is unselected:
// let index = this.selected.indexOf(item.id);
// if (index !== -1) {
// this.selected.splice(index, 1);
// }
this.doTheThingThatOpensTheEditorHere(item);
},
toggleSelect(item) {
let index = this.selected.indexOf(item.id);
index === -1
? this.selected.push(item.id)
: this.selected.splice(index, 1);
},
// For fun, get an array of items that are selected:
getSelected() {
return this.items.filter((item) => this.selected.indexOf(item.id) !== -1);
},
},
};
</script>

Categories

Resources