Vue.Draggable div items display left and right - javascript

I am new to Vue.js and for this project, I am using Vuedraggable to drag items. Currently, the items inside the draggabble div are displayed as
Text 1
Text 2
Text 3
Text 4
Is there a way we can change that and display as
Text 1 Text 2
Text 3 Text 4
JsFiddle Link = https://jsfiddle.net/ujjumaki/y1xw95rc/41/
View
<div id="app">
<div>
<draggable id="first" data-source="juju" :list="todos" class="list-group" draggable=".item">
<div class="list-group-item item" v-for="(element, index) in todos" :key="index" style="border-style: outset;
margin-top:0.5%; width: 10%; border-color:#17a2b8; border-width:thin;">
<p>
{{element.text}} id {{element.id}}
</p>
</div>
</draggable>
</div>
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/sortablejs#1.8.4/Sortable.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.20.0/vuedraggable.umd.min.js"></script>
Method
new Vue({
el: "#app",
data: {
todos: [
{ text: "Text 1", id: "1" },
{ text: "Text 2", id: "2" },
{ text: "Text 3", id: "3"},
{ text: "Text 4", id: "4" }
]
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})

Try to add following css:
#first {
display: grid;
grid-template-columns: 1fr 1fr;
justify-items: center;
text-align: center;
}
.list-group-item {
width: 100% !important;
}

Related

How to display selected list below select box container?

I am making an application where I have multi select dropdown..
In which there is a requirement that I need to place the selected items below the select container.
Working Snippet:
#container {
position: relative;
text-align: left;
width:100%;
}
#container > div {
padding-top: 2em;
}
._2iA8p44d0WZ {
border: 1px solid #cccccc;
border-radius: 4px;
padding: 5px;
min-height: 22px;
position: relative;
}
._7ahQImy {
padding: 4px 10px;
background: #0096fb;
margin-right: 5px;
margin-bottom: 5px;
border-radius: 10px;
display: inline-flex;
align-items: center;
font-size: 13px;
color: #fff;
white-space: nowrap;
}
#search_input {
position: absolute;
top: 0;
left: 0;
}
<div id="container">
<div class="_2iA8p44d0WZ">
<span class="chip _7ahQImy">This is the main label</span>
<span class="chip _7ahQImy false false">secondary label</span>
<span class="chip _7ahQImy">Another label</span>
<span class="chip _7ahQImy false false">even more labels labels labels labels labels labels</span>
<input type="text" class="searchBox" id="search_input" placeholder="Select" autocomplete="off" value="">
</div>
</div>
The above one provides the result of making the selected items and select box inside a container.
Expected Output
|------ (#container) Start -----|
| --------------------- |
| | Search Input | |
| --------------------- |
| |
|------ (#container) End -------|
| This is the main label |
| secondary label |
| Another label |
| even more labels labels labels labels labels labels |
Note:
-> I cannot modify any of the HTML elements given.
-> There are some dynamic classes inside it for which I cannot modify the css classes for those dynamic classes.
-> List of dynamic classes for which css properties cannot be modified, _2iA8p44d0WZ and _7ahQImy .
-> List of ids/classes, I can modify the css properties are #container and .chip (span).
The exact library that I am trying to modify in my real app is here along with css code,
Please help me to place the selected items below the container box as like the above given expected result.
You can hide the internal chips of the multi-select using the style prop.
CSS Customization
style={{
chips: {
display: 'none',
}
}}
Now you need to render your selectedValues outside the Multiselect component. In order to do this you need to update your state.selectedValues state array, and map state.selectedValues to your own custom chip components.
Add an onSelect callback.
onSelect={(selectedValues) => this.setState({ selectedValues })}
Map state.selectedValues to "chips". I used a span, but you can use any wrapping element and style it accordingly.
<div>
{selectedValues.map((chip) => (
<span>{chip.key}</span>
))}
</div>
Fullcode
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
plainArray: ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"],
objectArray: [
{ key: "Option 1", cat: "Group 1" },
{ key: "Option 2", cat: "Group 1" },
{ key: "Option 3", cat: "Group 1" },
{ key: "Option 4", cat: "Group 2" },
{ key: "Option 5", cat: "Group 2" },
{ key: "Option 6", cat: "Group 2" },
{ key: "Option 7", cat: "Group 2" }
],
selectedValues: [
{ key: "Option 1", cat: "Group 1" },
{ key: "Option 2", cat: "Group 1" }
]
};
this.style = {
chips: {
background: "red"
},
searchBox: {
border: "none",
"border-bottom": "1px solid blue",
"border-radius": "0px"
},
multiselectContainer: {
color: "red"
}
};
}
render() {
const { objectArray, selectedValues } = this.state;
return (
<div className="App">
<h4 id="checkbox" className="mt40 mx20">
<b>
{" "}
How can I customize the css for below below multi select to display
only select box inside container and selected items after container
box?{" "}
</b>
</h4>
<Multiselect
options={objectArray}
displayValue="key"
onSelect={(selectedValues) => this.setState({ selectedValues })}
showCheckbox={true}
selectedValues={selectedValues}
style={{
chips: {
display: "none"
}
}}
/>
<div>Some Content</div>
<div>Some More Content</div>
<div>
Selected Values:
{selectedValues.map((chip) => (
<span>{chip.key}</span>
))}
</div>
</div>
);
}
}
Edit
To enable removing selected items then also implement the onRemove callback. To duplicate the chip style copy the applied chip CSS rules to your own style object.
const styles = {
chip: {
padding: "4px 10px",
background: "#0096fb",
marginRight: "5px",
marginBottom: "5px",
borderRadius: "10px",
display: "inline-flex",
alignItems: "center",
fontSize: "13px",
color: "#fff",
whiteSpace: "nowrap"
}
};
Also start with empty selected state
this.state = {
plainArray: ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"],
objectArray: [
{ key: "Option 1", cat: "Group 1" },
{ key: "Option 2", cat: "Group 1" },
{ key: "Option 3", cat: "Group 1" },
{ key: "Option 4", cat: "Group 2" },
{ key: "Option 5", cat: "Group 2" },
{ key: "Option 6", cat: "Group 2" },
{ key: "Option 7", cat: "Group 2" }
],
selectedValues: []
};
...
<Multiselect
options={objectArray}
displayValue="key"
onSelect={(selectedValues) => this.setState({ selectedValues })}
onRemove={(selectedValues) => this.setState({ selectedValues })} // <-- implement
showCheckbox={true}
selectedValues={selectedValues}
style={{
chips: {
display: "none"
}
}}
/>
...
<div>
Selected Values:
{selectedValues.map((chip) => (
<span key={chip.key} style={styles.chip}> // <-- set chip style prop
{chip.key}
</span>
))}
</div>

Vuetify - Search function in table that jumps to the found row

I have 2 Vuetify data tables without pagination. Every row of the second one got exactly one parent in the first one. If I click on one of those entries in the second one, I want to search for the parent and jump to that row. All I found for now is filtering, but I only want to have that row on top of my table.
Is something like this possible?
We can't really help you without code, even if i've seen that you can't, it should be cool if you could modify some parts of your code like variables and datas ...
However, i'll try to do my best to explain
What you have to do is to reorder your data array binded on your table depending on a given id (or other data) to identify it.
I made a similar exemple of your needs, but i repeat i can't really be exhausitve :
Parent component:
<template>
<div id="app">
<listone :list="listOne" :toggled="toggledParent"></listone>
<listtwo :list="listTwo" v-model="toggledParent"></listtwo>
</div>
</template>
<script>
export default {
name: "App",
data: () => ({
toggledParent: 0,
listOne: [
{
id: 1,
title: "parent1",
},
{
id: 2,
title: "parent2",
},
{
id: 3,
title: "parent3",
},
],
listTwo: [
{
title: "title1",
parent: 3,
},
{
title: "title2",
parent: 1,
},
{
title: "title3",
parent: 2,
},
],
}),
components: {
listone: () => import("#/components/listone"),
listtwo: () => import("#/components/listtwo"),
},
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
}
</style>
ListOne component :
<template>
<div class="list">
<a v-for="item in treatedList" :key="item.title">
{{ item.title }}
</a>
</div>
</template>
<script>
export default {
name: "listone",
props: {
list: Array,
toggled: Number,
},
computed: {
treatedList: function () {
let tmp = this.list;
let $this = this
return tmp.sort(function (a, b) {
return a.id === $this.toggled ? -1 : b.id === $this.toggled ? 1 : 0;
});
},
},
};
</script>
<style>
.list {
display: flex;
flex-flow: column nowrap;
}
.list > a {
border: 1px solid red;
}
</style>
ListTwo component :
<template>
<div class="list">
<a
v-for="item in list"
:key="item.title"
#click="$emit('input', item.parent)">
{{ item.title }}
</a>
</div>
</template>
<script>
export default {
name: "listtwo",
props: {
list: Array,
toggledParent: Number
},
};
</script>
<style scoped>
.list {
display: flex;
flex-flow: column nowrap;
}
.list > a {
border: 1px solid red;
}
</style>
Try it and say me it helps you as wanted
Demo on codesandbox.io : https://codesandbox.io/s/mutable-thunder-zo8vn?fontsize=14&hidenavigation=1&theme=dark
So without knowing what your data looks like i'll use a standard array of objects without meta data.
What you could do, is use the sort function inside of computed property like below, this will re-organize your list every time you match or filter the list.
(Note: This re-arranges your entire list every time)
Here is a really basic example:
new Vue({
el: "#app",
data: {
search: 'Bananas',
tableData: [
{
item: "Cherries",
price: 3.99,
type: "Fruit"
},
{
item: "Chicken",
price: 6.99,
type: "Meat"
},
{
item: "Bananas",
price: 1.99,
type: "Fruit"
},
{
item: "Cola",
price: 0.99,
type: "Drink"
},
{
item: "Coffee",
price: 2.99,
type: "Drink"
},
]
},
computed: {
getTableData: function() {
return this.tableData.sort((x,y) => { return x.item == this.search ? -1 : y.item == this.search ? 1 : 0; });
}
}
})
table {
background: #ccc;
padding: 20px;
width:50%;
}
table tr {
background: #f1f1f1;
}
table tr td {
padding: 10px;
}
.firstRow {
background: green;
color:white;
}
.searchBar {
padding:20px;
width: 40%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="searchBar">
Search <input type="text" v-model="search">
</div>
<table>
<tr class="firstRow"><td>Item</td> <td>Price</td> <td>Type</td></tr>
<tr v-for="(product, index) in getTableData" :key="index">
<td>{{product.item}}</td>
<td>{{product.type}}</td>
<td>{{product.price}}</td>
</tr>
</table>
</div>

Vue js data binding doesn't work

I'm trying to create a vue component but whenever I want to hide some elements with v-show it doesn't work.
When you click any element on the list I want to hide it and on the click event element.visible is set to false, so in the component template I bind that value to v-show but it wont hide.
I guess it's because element.visible it's kind of nested attribute but I'm not really sure.
var collection = [
{ id: 1, name: 'element 1' },
{ id: 2, name: 'element 2' },
{ id: 3, name: 'element 3' },
{ id: 4, name: 'element 4' },
{ id: 5, name: 'element 5' },
{ id: 6, name: 'element 6' },
{ id: 7, name: 'element 7' },
{ id: 8, name: 'element 8' },
];
var multiselect = {
props: ['collection'],
data: function() {
return {
subscribed: [],
toSubscribe: [],
toUnsubscribe: [],
dataset: []
}
},
mounted: function(){
this.dataset = _.map(this.collection, function(element){
element.visible = true;
return element;
});
},
methods: {
subscribe: function(element){
element.visible = false;
}
}
}
new Vue({
el: '#app',
components: {
'multiselect': multiselect
},
data: {
elements: collection
}
})
.multiselect .list {
border: 1px solid #000;
height: 215px;
max-height: 215px;
overflow: scroll;
}
.multiselect .list .list-element {
text-align: center;
padding: 0.2em;
cursor: pointer;
}
.multiselect .list .list-element:hover {
background-color: #d6dbdf;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.4/lodash.min.js"></script>
<script src="https://unpkg.com/vue#2.5.13/dist/vue.js"></script>
<div id="app">
<multiselect inline-template :collection="elements">
<div class="col-sm-12 multiselect">
<div class="col-sm-5 list">
<div class="col-sm-12">
<div v-for="element in dataset" class="list-element" #click="subscribe(element)" v-show="element.visible">
{{element.name}}
</div>
</div>
</div>
<div class="col-sm-2">
<button class="btn btn-primary btn-fill">
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</button>
<button class="btn btn-primary btn-fill">
<i class="fa fa-arrow-left" aria-hidden="true"></i>
</button>
</div>
<div class="col-sm-5 list">
</div>
</div>
</multiselect>
</div>
As an interesting variation, you don't need to clone the collection elements or set a property on them.
It is enough to have a parallel array of flag, but you have to be careful of the syntax to update them and the flag must be contained in an object in order to be observable.
i.e an array of { visible: true } rather than an array of true.
Ref: Mutation-Methods
var collection = [
{ id: 1, name: 'element 1' },
{ id: 2, name: 'element 2' },
{ id: 3, name: 'element 3' },
{ id: 4, name: 'element 4' },
];
var multiselect = {
props: ['collection'],
data: function() {
return {
visibleFlags: []
}
},
created: function(){
this.collection.forEach(x => {
this.visibleFlags.push({visible: true}); // Vue mutation method
})
},
methods: {
subscribe: function(index){
this.$set(this.visibleFlags, index, false)
}
}
}
new Vue({
el: '#app',
components: {
'multiselect': multiselect
},
data: {
elements: collection
}
})
.multiselect .list {
border: 1px solid #000;
height: 125px;
max-height: 215px;
overflow: scroll;
}
.multiselect .list .list-element {
text-align: center;
padding: 0.2em;
cursor: pointer;
}
.multiselect .list .list-element:hover {
background-color: #d6dbdf;
}
<script src="https://unpkg.com/vue#2.5.13/dist/vue.js"></script>
<div id="app">
<multiselect inline-template :collection="elements">
<div class="col-sm-12 multiselect">
<div class="col-sm-5 list">
<div class="col-sm-12">
<div v-for="(element, index) in collection"
class="list-element" v-show="visibleFlags[index].visible"
#click="subscribe(index)">
{{element.name}}
</div>
</div>
</div>
</div>
</multiselect>
</div>
The problem is that you are modifying an already-responsive object. Vue cannot detect property additions.
It's obscured by the fact that you're copying via map, and assigning it to a new array, but it's an array of references to responsive objects, to each of which you have added the visible property. If you examine the data items in the parent, you'll see that it gets visible added, too.
The minimal fix is to use Object.assign to create a new object and copy properties into it. This way all properties are inserted into a non-responsive object, which is then made responsive during assignment.
mounted: function(){
this.dataset = _.map(this.collection, function(element){
return Object.assign({}, element, {visible: true});
});
},
You could do this in created, since you don't need the DOM element.

Vue.js directives on html rendering

I made this pen. Simple tabs using Vue.js.
Each tab get it's content from this object:
var tabs = [
{
title: "Pictures",
content: "Pictures content"
},
{
title: "Music",
content: "Music content. Wanna see some <a #click.prevent=\"show = 3\">Documents</a> content?"
},
{
title: "Videos",
content: "Videos content."
},
{
title: "Documents",
content: "Documents content. Wanna see some <a #click.prevent=\"show = 1\">Music</a> content?"
},
];
To render each tab content:
<div v-for="(tab, index) in tabs" v-if="show == index" :key="index" v-html="tab.content"></div>
I'm stuck trying to make those click directives on 'tab.content' work :( Am I missing something?
Thanks in advance.
v-html is not Vue content, it is simply innerHTML for an element. You will not be able to use Vue directives or components(!) in v-html content.
What you can do is catch and handle a native click event inside a component. The transition-group is convenient.
const tabs = [{
title: "Pictures",
content: "Pictures content"
},
{
title: "Music",
content: "Music content. Wanna see some <a data-show=\"3\">Documents</a> content?"
},
{
title: "Videos",
content: "Videos content."
},
{
title: "Documents",
content: "Documents content. Wanna see some <a data-show=\"1\">Music</a> content?"
},
];
var vue = new Vue({
el: "#app",
data: {
show: 0,
tabs
},
methods: {
navigate(event) {
const target = event.target;
if (target.dataset.show) {
event.preventDefault();
this.show = target.dataset.show;
}
}
}
});
.section {
padding: 2em 0;
}
.fade-up-enter-active,
.fade-up-leave-active {
transition: all 0.3s ease-in-out;
}
.fade-up-enter,
.fade-up-leave-to {
height: 0;
transform: translateY(30px);
opacity: 0;
}
<link href="//cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css" rel="stylesheet" />
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div class="container section" id="app">
<div class="tabs">
<ul>
<li v-for="(tab, index) in tabs" :class="{'is-active': show == index}"><a #click.prevent="show = index">{{tab.title}}</a></li>
</ul>
</div>
<div class="texts">
<transition-group name="fade-up" target="div" appear #click.native="navigate">
<div v-for="(tab, index) in tabs" v-if="show == index" :key="index" v-html="tab.content"></div>
</transition-group>
</div>
</div>

How to show an elements value in a vue modal?

I have several elements that are displayed as <li> elements in a loop. For each element I want behavior such that when the element is clicked a modal box opens up. Inside the modal box I want contents that are specific to the element that was clicked.
The data below shows all the elements:
{value: 10, name: "foo"},
{value: 12, name: "bar"},
{value: 14, name: "foobar"},
{value: 22, name: "test"},
{value: 1, name: "testtooo"},
{value: 8, name: "something"}
When I click on an element, I want to see the value property for it inside the modal box.
I've created a fiddle for this: https://jsfiddle.net/hvb9hvog/14/
Question
I've gotten the modal working, however, how can I show each elements value property inside the modal?
I am sure there are multiple ways to go about this, but one way would be to create a new data property, let's call it value. When you #click the li you get it's value, set it to the value property and display that value property in the body of the modal ({{this.value}}).
You can have two #click methods, so create another one that updates the data property you just created, called value.
Here's a fiddle
Relevant code changes:
In your li element:
<li v-for="request in filteredRequests">
{{request.name}}
</li>
In your modal markup:
<modal v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
<div slot="body">
{{this.value}}
</div>
</modal>
In vue data:
data: {
requests: [
{value: 10, name: "foo"},
{value: 12, name: "bar"},
{value: 14, name: "foobar"},
{value: 22, name: "test"},
{value: 1, name: "testtooo"},
{value: 8, name: "something"}
],
num: 0,
showModal: false,
value: 9999999999
},
In vue methods:
methods: {
setVal(val) {
this.value = val;
}
},
Vue.component('modal', {
template: '#modal-template'
})
var vm = new Vue({
el: "#app",
data: {
requests: [{
value: 10,
name: "foo"
},
{
value: 12,
name: "bar"
},
{
value: 14,
name: "foobar"
},
{
value: 22,
name: "test"
},
{
value: 1,
name: "testtooo"
},
{
value: 8,
name: "something"
}
],
num: 0,
showModal: false,
value: 9999999999
},
methods: {
setVal(val) {
this.value = val;
}
},
computed: {
c: function() {
return `Slider Number: (${this.num})`
},
filteredRequests() {
return this.requests.filter(r => r.value > this.num)
}
},
});
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
display: table;
transition: opacity .3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 300px;
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
transition: all .3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
.modal-body {
margin: 20px 0;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://unpkg.com/vue#2.3.4/dist/vue.js"></script>
<script type="text/x-template" id="modal-template">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
default footer
<button class="modal-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<div id="app">
<div class="form-horizontal">
<div class="form-group">
<label class="col-md-2 control-label">色</label>
<div class="col-md-10">
<input class="form-control" v-model="c" :style="{backgroundColor: c}" />
<div class="help-block">
<input type="range" min="0" max="360" v-model.number="num" />
<ul class="ml-thumbs">
<li v-for="request in filteredRequests">
{{request.name}}
</li>
</ul>
<modal v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
<div slot="body">
{{this.value}}
</div>
</modal>
</div>
</div>
</div>
</div>
</div>
Add "req" property to data
data() {
return {
...
req: {},
...
}
}
set click event:
{{request.name}}
add body slot
...
<h3 slot="header">custom header</h3>
<div slot="body">
{{req.value}}
</div>
...
https://jsfiddle.net/w4e6hr86/
I'm not sure if you are asking this using Vue.js or just JS. So, here are my answers (basic examples). I recommend you to read about event delegation + events on vuejs.
Vue Js
<template>
<div class="content">
<ul>
<li v-for="item in items" #click.prevent="showModal(item)">{{ item }}</li>
</ul>
<div class="modal" v-show="isModalVisible">
{{ JSON.stringify(selectedItem) }}
close modal
</div>
</div>
</template>
<script>
export default {
name: 'something',
data () {
return {
selectedItem: item,
items: [{
id: 1,
name: 'something'
}, {
id: 2,
name: 'something #2'
}]
}
},
computed: {
isModalVisible () {
return this.selectedItem !== null
}
}
methods: {
showModal (item) {
this.selectedItem = item
}
}
}
</script>
Plain javascript
const toggleModal = content => {
const $body = document.querySelector('body')
const $modal = $body.querySelector('.modal')
$modal && $modal.remove()
$body.insertAdjacentHTML('beforeend',`<div class="modal">${content}</div>`)
}
document.querySelector('ul').addEventListener('click', e => {
if (! e.target.matches('li')) {
return
}
toggleModal(e.target.innerText)
});
About Event delegation.
About insertAdjacentHtml.
About Vuejs Event handling

Categories