I have something I have been trying to do which is challenging. I have a simple div that gets appended to the top level on the click of a button. The issue is I want vuejs data appended inside of this div. I am not quite sure how to bind this data, I have tried using a simple expression, but no luck. Can someone please let me know how this can be solved--and with a div, not a bootstrap modal
new Vue({
el: "#app",
data: {
chocs:[{"title":'a man tale'},{"title":'a boy tale'}]
},
methods: {
handleTileClick: function(){
alert(this.chocs[0].title);
$("#fox").append(`<div id="popover-dialog"> data here {{this.chocs[0].title}}
</div>`);
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="app">
<h2>Todos:</h2>
<button v-on:click="handleTileClick()">
Click Me
</button>
<div id="fox">
</div>
</div>
Without JQuery, the Vue-way:
new Vue({
el: "#app",
data: () => ({
chocs:[{"title":'a man tale'}, {"title":'a boy tale'}],
titleToBeAppended: ''
}),
methods: {
handleTileClick: function(){
this.titleToBeAppended = this.chocs[0].title
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="popover-dialog">
<p>Data here: {{ titleToBeAppended }}</p>
<button v-on:click="handleTileClick()">Click Me</button>
</div>
</div>
Using template literals:
new Vue({
el: "#app",
data: () => ({
chocs:[{"title":'a man tale'}, {"title":'a boy tale'}]
}),
methods: {
handleTileClick: function(){
alert(this.chocs[0].title);
$("#fox").append(
`<div id="popover-dialog">data here: ${this.chocs[0].title}</div>`
);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="app">
<h2>Todos:</h2>
<button v-on:click="handleTileClick()">Click Me</button>
<div id="fox"></div>
</div>
Related
I need to convert some code to Vue, I have a rendering difference in the alt attribute of an image, because I can't find a way to interpret the html in the attributes, I haven't found any topics that talk about this do you have an idea please?
In the examples I made on purpose not to put src to see the alternative texts.
Vue.component('first-image', {
inheritAttrs: false,
template: '<div class="container-image"><img v-bind="$attrs"></div>'
});
Vue.component('second-image', {
template: '<img>',
});
new Vue({
el: '#app',
data() {
return {
alternativeText: '1 000€',
};
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!-- Without VueJS -->
<img alt="1 000€">
<br>
<br>
<!-- With VueJS -->
<div id="app">
<first-image :alt="alternativeText"></first-image>
<second-image alt="1 000€"></second-image>
</div>
You can try like following snippet:
Vue.component('first-image', {
inheritAttrs: false,
template: '<div class="container-image"><img v-bind="$attrs"></div>'
});
Vue.component('second-image', {
template: '<img>',
});
new Vue({
el: '#app',
data() {
return {
alternativeText: '1 000€',
};
},
methods: {
decodeHtml(html) {
const txt = document.createElement("textarea");
txt.innerHTML = html;
return txt.value;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!-- Without VueJS -->
<img alt="1 000€">
<br>
<br>
<!-- With VueJS -->
<div id="app">
<first-image :alt="decodeHtml(alternativeText)"></first-image>
<second-image alt="1 000€"></second-image>
</div>
I have multiple buttons a page and when I click one to toggle the buttons text, ALL of the buttons change. How do I use VUE to separate functionality and individualize each buttons #click to only affect the clicked button? In the snippet below you will see that all buttons change on click. I only want the clicked buttons text to change.
See example below. This example is from another post and all credit goes to:
change button while pressing it with vue.js
new Vue({
el: '#app',
data: {
isFavorite: false
},
methods: {
toggleFavorite() {
this.isFavorite = !this.isFavorite;
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<button #click="toggleFavorite" v-show="!isFavorite">Add to favorites</button>
<button #click="toggleFavorite" v-show="isFavorite">Delete from favorites</button>
<button #click="toggleFavorite" v-show="!isFavorite">Add to favorites</button>
<button #click="toggleFavorite" v-show="isFavorite">Delete from favorites</button>
</div>
Use a dictionary (object) instead of a single variable:
data() {
return {
isFavorite: {}
}
},
Instead of toggling a single boolean, toggle a property on the object:
<button #click="toggleFavorite('item1')" v-show="!isFavorite['item1']">Add to favorites</button>
<button #click="toggleFavorite('item1')" v-show="isFavorite['item1']">Delete from favorites</button>
The toggle:
methods: {
toggleFavorite(item) {
this.$set(this.isFavorite, item, !this.isFavorite[item]);
}
}
Demo if this is still unclear:
new Vue({
el: '#app',
data() {
return {
isFavorite: {}
}
},
methods: {
toggleFavorite(item) {
this.$set(this.isFavorite, item, !this.isFavorite[item]);
}
}
})
<div id="app">
<button #click="toggleFavorite('item100')" v-show="!isFavorite['item100']">Add to favorites</button>
<button #click="toggleFavorite('item100')" v-show="isFavorite['item100']">Delete from favorites</button>
<button #click="toggleFavorite('item101')" v-show="!isFavorite['item101']">Add to favorites</button>
<button #click="toggleFavorite('item101')" v-show="isFavorite['item101']">Delete from favorites</button>
<hr>
<div v-for="x in 10" :key="x">
<button #click="toggleFavorite(`item${x}`)" v-show="!isFavorite[`item${x}`]">Add to favorites</button>
<button #click="toggleFavorite(`item${x}`)" v-show="isFavorite[`item${x}`]">Delete from favorites</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
It happens because of the v-show values are same. I think this implementation is the not best practise for Vue. You can use v-if v-else for data value or just change the text by value.
new Vue({
el: '#app',
data: {
isFavorite: false,
isFavorite2:false
},
methods: {
toggleFavorite() {
this.isFavorite = !this.isFavorite;
},
toggleFavorite2() {
this.isFavorite2 = !this.isFavorite2;
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<button #click="toggleFavorite" v-show="!isFavorite">Add to favorites</button>
<button #click="toggleFavorite" v-show="isFavorite">Delete from favorites</button>
<button #click="toggleFavorite2" v-show="!isFavorite2">Add to favorites 2</button>
<button #click="toggleFavorite2" v-show="isFavorite2">Delete from favorites 2</button>
</div>
I am trying to create a simple webpage where I can add or remove textboxes using vue.js.
new Vue({
el: "#app",
data() {
return {
list: []
};
},
methods: {
deleteFromList(index) {
this.list.splice(index, 1);
},
addItem() {
this.list.push({});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button #click="addItem()">Add 1</button>
<ul>
<li v-for="(item, index) in list":key="index">
<textarea rows="1" cols="30">{{item}}</textarea>
<button #click="deleteFromList(index)">Delete</button>
</li>
</ul>
</div>
<script src="index.js"></script>
</body>
</html>
I added a snippet to the page (I think you need to expand or make it full screen to see the result properly), my problem is that on Delete button it doesn't remove the corresponding row, but the last one.
Has anyone any idea about how can I do this work fine?
Thank you very much :)
It is actually removing the correct item out of the array, but you're not seeing it because you're not changing the value of the model only the textarea which is not tied to the value instead its just cached to :key="index", below is an example which should show that, simply by adding a counter you can see it's deleting the correct object.
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: "#app",
data() {
return {
list: [],
counter: 0,
};
},
methods: {
deleteFromList(index) {
this.list.splice(index, 1);
},
addItem() {
this.list.push(this.counter++);
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button #click="addItem()">Add 1</button>
<ul>
<li v-for="(item, index) in list" :key="index">
<textarea rows="1" cols="30">{{item}}</textarea>
<button #click="deleteFromList(index)">Delete</button>
</li>
</ul>
<pre>{{ list }}</pre>
</div>
To fix the issue and have dynamic changing values/model you should use v-model on the value and indexOf when removing.
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: "#app",
data() {
return {
list: []
};
},
methods: {
deleteFromList(item) {
this.list.splice(this.list.indexOf(item), 1);
},
addItem() {
this.list.push('');
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button #click="addItem()">Add 1</button>
<ul>
<li v-for="(item, index) in list" :key="index">
<textarea rows="1" cols="30" v-model="list[index]"></textarea>
<button #click="deleteFromList(item)">Delete</button>
</li>
</ul>
</div>
index.html:
<body>
<div id="app">
{{ message }}
</div>
<div id="counter">
{{ counter }}
</div>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript" src="index.js"></script>
</body>
index.js:
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
const Counter = {
data() {
return {
counter: 0
}
}
}
Vue.createApp(Counter).mount('#counter')
and the output is:
Hello Vue!
{{ counter }}
Why is my code for counter not working?
You're using the syntax for two separate versions of Vue.
new Vue is v2, Vue.createApp is v3.
For your code to work with v2:
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
const Counter = new Vue({
el: '#counter',
data() {
return {
counter: 0
}
}
})
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
{{ message }}
</div>
<div id="counter">
{{ counter }}
</div>
For your code to work with v3:
var app = Vue.createApp({
data() {
return {
message: 'Hello Vue!'
}
}
})
const Counter = Vue.createApp({
data() {
return {
counter: 0
}
}
})
app.mount('#app');
Counter.mount('#counter');
<script src="https://unpkg.com/vue#next"></script>
<div id="app">
{{ message }}
</div>
<div id="counter">
{{ counter }}
</div>
Think i'm cracking up, this is some very basic stuff but it doesn't seem to be working...
Basically clicking the link should toggle display between true and false, but this isn't the case.
Vue.component('dropdown', {
props: [ 'expanded' ],
data: function() {
return {
display: !!(this.expanded)
}
},
template: '<div><transition name="expand"><slot :display="display"></slot></transition></div>'
});
window.app = new Vue({
el: '#app'
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<dropdown>
<div slot-scope="{ display }">
Toggle {{ display }}
<div v-if="display">
Dropdown content
</div>
</div>
</dropdown>
</div>
Edit:
Updated code, I forgot I changed that, I did infact have the click event as display = !display. But even with that said, if you had tried to click the button you would see that it doesn't change the true either...
Updating after a correcting comment from thanksd. I stumbled onto the right answer without really understanding it.
The problem is that within the slot, display refers to an item in the scope-slot object. Updating it there does not update the actual source variable. If you pass in and call a function, the proper variable is updated.
Vue.component('dropdown', {
props: ['expanded'],
data: function() {
return {
display: Boolean(this.expanded)
}
},
methods: {
toggle() {
this.display = !this.display;
}
},
template: '<div><transition name="expand"><slot :display="display" :toggle="toggle"></slot></transition></div>'
});
new Vue({
el: '#app'
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<dropdown>
<div slot-scope="{display, toggle}">
Toggle {{ display }}
<div v-if="display">
Dropdown content
</div>
</div>
</dropdown>
</div>
One solution would be to implement a v-model for the dropdown component which would allow you to two-way bind the display property to a property in the parent. That way you wouldn't need to pass anything via the slot-scope.
Here's an example of that:
Vue.component('dropdown', {
props: [ 'value' ],
data() {
return {
display: !!(this.value)
}
},
watch: {
value(value) {
this.$emit('input', value);
}
},
template: '<div><transition name="expand"><slot></slot></transition></div>'
});
new Vue({
el: '#app',
data() {
return { dropdownToggle: false }
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<dropdown v-model="dropdownToggle">
<div>
<a href="javascript:void(0)" #click="dropdownToggle = !dropdownToggle">
Toggle {{ dropdownToggle }}
</a>
<div v-if="dropdownToggle">
Dropdown content
</div>
</div>
</dropdown>
</div>