Pass object into data attribute - javascript

I have a data attribute like so:
<div data-id="">
In my markdown file I have frontmatter variable like so:
id: rick
Now I want to pass that object into data-id which only lets me add string.
How to make like so:
<div data-id="id"> or <div data-id={{ id }}> or <div :data-id={{ id }}>
I use vuejs.

To bind attributes to an element (or component) you use
<div :data-id="id">
...
</div>
window.onload = () => {
new Vue({
el: '#app',
data () {
return {
id: 123
}
}
})
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.0/vue.js"></script>
<div id="app">
<div :data-id="id">
This is rendered as div with and data-id="123"
</div>
</div>

Related

Vue - Emitting a data object but changing one changes them all

I have a TODO app and want to pass by props from one component to another an array of objects. An object is added every time you click a button but I'm having trouble with it. The problem is that the property value becomes the same for every single object added to the array. It seems like it's not saving correctly each tareas.tarea data.
App.vue
<template>
<div>
<Header></Header>
<AgregarTarea #tareaAgregada="agregarTarea"></AgregarTarea>
<div class="container">
<div class="columns">
<div class="column">
<Lista :tareas = 'tareas' #eliminarItem="eliminarTarea"></Lista>
<!-- here i pass through props the array of objects -->
</div>
<div class="column">
<TareaFinalizada></TareaFinalizada>
{}
</div>
</div>
</div>
</div>
</template>
<script>
import Header from './components/Header'
import AgregarTarea from './components/AgregarTarea'
import Lista from './components/Lista'
import TareaFinalizada from './components/TareaFinalizada'
export default {
data(){
return {
tareas:[]
}
},
components: {
Header,
AgregarTarea,
Lista,
TareaFinalizada
},
methods: {
agregarTarea(data){
//add new object to the array
this.tareas.push(data)
},
eliminarTarea(data) {
this.tareas.splice(data.id, 1);
}
}
};
</script>
AgregarTarea.vue || Here is where i add a new ToDo
<template>
<div class="container">
<input class="input" type="text" placeholder="Text input" v-model="tareas.tarea">
<button class="button is-primary" #click="agregarTarea">Agregar Tarea</button>
</div>
</template>
<script>
export default {
data(){
return {
tareas: {
tarea:'',
id:null,
editar:false
}
}
},
methods: {
agregarTarea(){
this.$emit('tareaAgregada', this.tareas)
this.tareas.tarea = ' ';
}
}
}
</script>
Lista.vue || And here is where i display the ToDo's
<template>
<div>
<div class="list is-hoverable">
<ul>
<li v-for="(tarea, index) in tareas" :key="index">
<a class="list-item has-text-centered" #click="editarTexto(index)">
{{ tarea }}
<div class="editar" v-if="editar">
<input class="input" type="text" placeholder="Text input" v-model="nuevaTarea">
</div>
</a>
<button class="button is-danger" #click="eliminarItem(index)">Eliminar</button>
<div><input type="checkbox"> Finalizada</div>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props:['tareas'],
data(){
return {
nuevaTarea: ' ',
editar:false,
}
},
methods: {
eliminarItem(index){
this.$emit('eliminarItem', index)
},
editarTexto(){
this.editar = true
}
}
}
</script>
<style scoped>
</style>
JavaScript objects are passed by reference (not cloned by value). Each time you $emit the tareas object from AgregarTarea.vue, it's the same object reference as before, even if the properties have changed. So all of the objects in your tareas array in App.vue are the same object.
To fix this, change AgregarTarea.vue to $emit a clone each time:
methods: {
agregarTarea(){
this.$emit('tareaAgregada', Object.assign({}, this.tareas)) // clone
this.tareas.tarea = ' ';
}
}
(This is a shallow clone and would not work properly if this.tareas had nested objects, but it doesn't.)
Option #2
Here's a different way that works easily for nested objects:
new Vue({
el: "#app",
data(){
return {
tareas: null // <-- It's not filled here
}
},
methods: {
resetTareas() { // <-- it's filled here instead
this.tareas = {
tarea:'',
id:null,
editar:false
}
},
agregarTarea(){
this.$emit('tareaAgregada', this.tareas);
this.resetTareas(); // <-- Create a brand new object after emitting
}
},
created() {
this.resetTareas(); // <-- This is for the first one
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
Tarea: <input type="text" v-model="tareas.tarea" /><br /><br />
<button #click="agregarTarea">Emit</button><br /><br />
Object: {{ tareas }}
</div>
Since resetTareas creates a brand new object every time, you don't have to worry about cloning anything, and it works even if tareas is a complex nested object.

Hide div onclick in Vue.js

What is the Vue.js equivalent of the following jQuery?
$('.btn').click(function(){ $('.hideMe').hide() });
jQuery works out of the box, Vue.js does not. To initialize Vue.js component or App you must bind that component with its data to one specific HTML tag inside your template.
In this example the specified element is <div id="app"></div> and is targeted through el: #app. This you will know from jQuery.
After you declare some variable that holds the toggle state, in this case been isHidden, the initial state is false and has to be declared inside the data object.
The rest is Vue-specific code like v-on:click="" and v-if="". For better understand please read the documentation of Vue.js:
The Vue Instance
Template Syntax
Event Handling
Conditionals
Note: consider reading the whole or at least longer parts of the documentation for better understanding.
var app = new Vue({
el: '#app',
data: {
isHidden: false
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.js"></script>
<div id="app">
<button v-on:click="isHidden = true">Hide the text below</button>
<button v-on:click="isHidden = !isHidden">Toggle hide and show</button>
<h1 v-if="!isHidden">Hide me on click event!</h1>
</div>
This is a very basic Vue question. I suggest your read the guide, even the first page will answer your question.
However, if you still need the answer this is how you hide/show elements in Vue.
new Vue({
el: '#app',
data () {
return {
toggle: true
}
},
})
<script src="https://unpkg.com/vue#2.5.3/dist/vue.js"></script>
<div id="app">
<button #click='toggle = !toggle'> click here </button>
<div v-show='toggle'>showing</div>
</div>
<div>
<div>
<button v-on:click="isHidden = !isHidden">Toggle hide and show</button>
<h1 v-if="!isHidden">Hide me on click event!</h1>
</div>
</div>
name: "Modal",
data () {
return {
isHidden: false
}
}
The up-voted answer is definitely a way to do it, but when I was trying to do this it was with a dynamic array instead of a single Div, so a single static Vue variable wouldn't quite cut it.
As #samayo mentions, there isn't a difference between the hide action from jQuery vs Vue, so another way to do this is to trigger the jQuery through the #click function.
The Vue Dev kit will tell you not to mix JS inline with #click events and I had the same problem as #user9046370 trying to put the jQuery command inline with #click, so anyway,
Here's another way to do this:
<tr v-for="Obj1,index in Array1">
<td >{{index}}</td>
<td >
<a #click="ToggleDiv('THEDiv-'+index)">Show/Hide List</a><BR>
<div style='display:none;' :id="'THEDiv-'+index" >
<ul><li v-for="Obj2 in Array2">{{Obj2}}</li></ul>
</div>
</td>
</tr>
Method:
ToggleDiv: function(txtDivID)
{
$("#"+txtDivID).toggle(400);
},
The other perk of this is that if you want to use fancy jQuery transitions you can with this method.
<template>
<button class="btn btn-outline-secondary" type="button"><i class="fas fa-filter" #click="showFilter = !showFilter"></i></button>
</template>
<script>
export default {
methods:{
showFilter() {
eventHub.$emit('show-guest-advanced-filter');
}
}
}
</script>
But it's not worked this method.
<template>
<button class="btn btn-outline-secondary" type="button"><i class="fas fa-filter" #click="filtersMethod"></i></button>
</template>
<script>
export default {
data: () => ({
filter: true,
}),
methods: {
showFilter() {
eventHub.$emit('show-guest-advanced-filter');
this.filter = false;
},
hideFilter() {
eventHub.$emit('hide-guest-advanced-filter');
this.filter = true;
},
filtersMethod() {
return this.filter ? this.showFilter() : this.hideFilter();
}
}
}
</script>
This is worked.

How can I pass data to nested components from Vue instance

I get my data via AJAX from the Vue instance, and I need to pass that data to the components. I am now learning how Vue.js works, but I find the documentation a little fragmentary...
Here is aproximately my code:
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<title>mysite</title>
</head>
<body>
<div id="app">
<parent-component></parent-component>
</div>
<template id="parent-component-template">
<div id="the-template">
<div class="the-list">
<span is="sector-item" v-for="item in sectors" :sector="item"></span>
</div>
<button>Button</button>
</div>
</template>
<template id="sector-item-template">
<span>
{{ sector.name }}
</span>
</template>
<!-- Vue.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<script>
Vue.component('parent-component', {
template: '#parent-component-template'
});
Vue.component('sector-item', {
props: ['sector'],
template: '#sector-item-template'
});
let app = new Vue({
el: '#app',
data: {
sectors: [{
'id': 1,
'name': 'Industry'
}]
}
});
</script>
</body>
</html>
I get the following error:
[Vue warn]: Property or method "sectors" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
Where do I make a mistake?
I think your code is not complete. I tried to simulate what you trying to, in the snippet bellow:
Vue.component('parent-component', {
props: ['sectors']
});
Vue.component('child-component', {
props: ['item']
});
new Vue({
el: '#app',
data: {
sectors: [
{
'id': 1,
'name': 'Industry'
},
{
'id': 2,
'name': 'Education'
}
]
}
});
.the-list > div {
padding: 5px;
border: 1px solid gray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<parent-component :sectors="sectors" inline-template>
<div class="the-list">
<child-component :item="sector" :key="sector.id" v-for="sector in sectors" inline-template>
<div>
<span v-text="item.name"></span>
<button>Button</button>
</div>
</child-component>
</div>
</parent-component>
</div>
The Vue instance owns the property sectors and I passed this property as a prop to the <parent-component>.
Now <parent-component> has a prop called sectors(it could be another name) that received the value of sectors from the main Vue instance. I've used v-for to iterate over all items of the parent-component prop passing each item of the array to the <child-component>.
The <child-component> has a prop called item in which I passed the value of each element of the array.
You can learn more, here for free.
I hope this answer can be helpful.

Inserting a v-model into a vuejs element

I'm trying to do something like this, do not know how to describe in technical term, can't seem to find a solution for this.
<div id="app">
<input type="text" v-model="model1" />
</div>
<div>
<div id="model2">ABCDEFG</div>
<input type="text" />
</div>
<script>
new Vue({
el: '#app',
data: {'model1': 'value'},
...
...
...
});
</script>
How can i add model2 element into my #app data? I do not want to wrap my model2 inside of #app because it is a partial, and is shared throughout the application. Is there a way i can inject it on a particular page when it is needed?
You can make that model2 div a separate component o that it can be reused anywhere you want like this:
html
<div id="app">
<input type="text" v-model="model1" />
<reusable-comp></reusable-comp>
</div>
script
<script>
var reusableComp = {
template: `
<div id="model2">
<div>ABCDEFG</div>
<input type="text" />
</div>
`,
data(){
return{
//reactive properties for this component
}
}
}
new Vue({
el: '#app',
data: {'model1': 'value'},
components:{
reusableComp
}
...
...
...
});
</script>
You can also register that as a global component like this
Vue,.component('reusableComp',{ //...options })`
See docs for more on components

On hover change multiple elements data in vue framework

I'm new to vue! I have 3 divs, All divs have a message data (One source)! I've bind a method, that when hover on one div it will change the message! The thing is working fine, but it change all div's message! And I know it's logical! But How can I only changed on that hovered element data! Not affecting others!
Here is my JSFiddle.
Html Is :
<div id="app">
<div class="one" v-on:mouseover="change">
{{ message }}
</div>
<div class="one" v-on:mouseover="change">
{{ message }}
</div>
<div class="one" v-on:mouseover="change">
{{ message }}
</div>
</div>
Vue :
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
},
methods : {
change : function() {
this.message = "Changed"
}
}
}
)
You need to create separate data bindings, one for each message div. There are a number of ways to solve this. The best solution depends on your use case. But, here's a simple solution:
Template:
<div id="app">
<div class="one" v-on:mouseover="change('foo', 'this is a message')">
{{ messages.foo }}
</div>
<div class="one" v-on:mouseover="change('bar', 'here is a different message')">
{{ messages.bar }}
</div>
<div class="one" v-on:mouseover="change('baz', 'message for baz')">
{{ messages.baz }}
</div>
</div>
Vue component:
new Vue({
el: '#app',
data: function () {
return { messages: {} }
},
methods : {
change : function(key, message) {
this.$set(this.messages, key, message)
}
}
})

Categories

Resources