Right now I trying to use draggable to build a kanban (with four columns). I started creating two columns to learn about vue-draggable, but I can't figure out how to access the column of task.
My first two columns:
<draggable v-model="myArray" class="simple-a"
:options="{group:'people'}" :move="onMove"
#start="changeDrag" #end="changeDrag"
#change="seeChange">
<div v-for="(element, aIndex) in myArray" :key="aIndex" class="element-a">
{{ element.name }}
</div>
</draggable>
<draggable v-model="myArray2" class="simple-a" style="background:red;"
:options="{group:'people'}" :move="onMove" #start="changeDrag"
#end="changeDrag" #change="seeChange(1)">
<div v-for="(element2, aIndex) in myArray2" :key="aIndex" class="element-a">
{{ element2.name }}
</div>
</draggable>
I am using seeChange function to get which element has changed:
seeChange({moved, added, removed}, col) {
if(added){
console.log(added);
console.log('column: '+col);
}
if(moved){
console.log(moved);
}
if(removed){
console.log(removed);
}
}
As you can see I'm trying to pass col attribute to this function (change event), but I can't, is always undefined.
How can I pass an attribute to a change event of vue draggable ?
Or how is the correct/better way to get the new column of a edited item?
The syntax you need to pass additional parameters to an event handler is
template
<draggable ... #change="seeChange($event, 1)">
...
</draggable>
component
methods: {
seeChange(event, col) {
console.log(event, col)
...
}
},
Ref: Passing event and argument to v-on in Vue.js
Related
What or where is individual id or any other element that I can call to run a function on component.
Example: using add button I'm dynamically creating colored squares. Each square has close button.
Then I want to delete one of squares, let's say the blue one (third child of template).
v-bind:id='var' doesn't works because then all squares have the same id.
You can use ref, you can define ref in every added component. The ref is array. you can refrence component through index of the ref.
for example;<div v-for="(item) in arr" :key="item.id"> <span ref="testRef"> item.name </span> </div>, you can use 'this.$refs.testRef[index]' find component which you want.
There are multiple options. For instance, in your v-for loop you can get the index this way: (official docs)
<div v-for="(item, index) in myList" :key="index">
{{ item.name }}
</div>
You could then for example use the index in a ref to access the element for the script.
Another option is to pass the event instance to the onclick listener with the special keyword $event, and use this to get the element:
<div ... #click="myFunction($event)">
{{ item.name }}
</div>
And then in your script
myFunction(ev) {
// do something with the element that was clicked on
console.log(ev.target)
}
However, a more 'vue' way would be to not mess with the elements, but only manipulate the underlying data and let vue worry about representing the data with elements on your page. For instance, you could make your squares be represented by a list of objects, containing their own data own the state (opened or closed). So in your script you have:
data() {
return {
squares: [
{ color: "ff0000", opened: true },
...
]
}
},
And in your template something like
<div
v-for="square in squares"
v-show="suare.opened"
#click="square.opened = false"
> ...
I'm creating a to-do list in vue.js and the following piece of code in the child element returns undefined
<input v-model="titleText" type='text'>
<input v-model="projectText" type='text'>
<button class='ui basic blue button' v-on:click="sendForm()">
Create
</button>
<button class='ui basic red button' v-on:click="closeForm()">
Cancel
</button>
sendForm () {
if (this.titleText.length > 0 && this.projectText.length > 0) {
this.$emit('create-todo', {
title: this.titleText,
project: this.projectText,
done: false
})
}
this.titleText = ''
this.projectText = ''
this.isCreating = false
}
}
Parent element:
<template>
<div id="app">
<todo-list v-bind:todos="todos"></todo-list>
<create-todo v-on:create-todo="createTodo()"></create-todo>
</div>
</template>
methods: {
createTodo (newTodo) {
console.log(newTodo)
this.todos.push(newTodo)
}
}
The problem is a simple one: when you handle the create-todo event, you're explicitly invoking the createTodo() method without allowing any arguments to be passed to it. You must either allow Vue to interpret which arguments to supply implicitly by omitting the parentheses, or use a combination of spread syntax and the arguments object to explicitly pass all arguments provided by the emitted event into the method call.
Using omission:
<template>
<div id="app">
<todo-list v-bind:todos="todos"></todo-list>
<create-todo v-on:create-todo="createTodo"></create-todo>
</div>
</template>
Using spread syntax + arguments object:
<template>
<div id="app">
<todo-list v-bind:todos="todos"></todo-list>
<create-todo v-on:create-todo="createTodo(...arguments)"></create-todo>
</div>
</template>
Either solution is acceptable. If, however, you need to be able to include additional arguments into your method call in the future, then using the spread syntax + arguments object would be necessary with the additional arguments supplied before the event arguments. For example, if you wanted to supply the values "foo" and "bar" to createTodo() as well, then you would do the following:
<template>
<div id="app">
<todo-list v-bind:todos="todos"></todo-list>
<create-todo v-on:create-todo="createTodo('foo', 'bar', ...arguments)"></create-todo>
</div>
</template>
You haven't shown the v-dom of your parent component, but perhaps you didn't insert your #create-todo listener into the custom component tag. I don't have 50 rep, so I can't comment and ask.
I'm generating a list of multiple input elements in which one is <el-select>. On changing this select menu, I'm getting value bounded with that select. But here, question is, I also want to get index/row number of the parent v-for items.
You can understand what I meant from the following code:
<el-form-item v-for="(domain, index) in Prescription.domains">
<div class="col-md-2" v-if="medicineIsSelected === true">
<small>Select Brand:</small>
<el-select v-model="domain.SelectedBrand" clearable placeholder="Select" #change="updateDropdowns"> <!-- Here I want to pass {{index}} also -->
<el-option
v-for="item in selectedMedicineMetaInfo.BrandName"
:key="item.value.name"
:label="item.value.name"
:value="item.value.rxcui">
</el-option>
</el-select>
</div>
</el-form-item>
As you can see from above code, I want to pass index in updateDropdowns.
I tried passing updateDropdowns(index), here I got the index number but lost the selected value of that dropdown. How can I pass both?
Here is the solution :
#change="updateDropdowns(index, $event)"
you can use $event to reference current event.
you can use custom event to manage this
<div>
<child #clicked="ongetChild"></child>
</div>
== child ==
watch your dropdown changes
export default {
watch: {
'domain.SelectedBrand':function(value) {
this.$emit('clicked', 'value')
}
}}
=== parent ==
export default {
ongetChild (value) {
console.log(value) // someValue
}
}
}
Use #change="updateDropdowns" in el-select tag
Use vue method:
updateDropdowns(index) {
this.selectedMedicineMetaInfo.BrandName[index-1]; // this gives selected option details
}
I created two separated Vue components and I able to emit a message thru a bus.
How can I render/display the message in the component that receives the message.
Example of the Vue component that receives the message:
<template>
<div v-model="cars">
Car model: {{ model }}
<input type="button" #click="display" value="example" />
</div>
</template>
<script>
export default {
data() {
return {
cars: null
}
},
mounted() {
bus.$on('CARS_LOADED', (cars) => {
this.cars = cars;
});
},
methods: {
display()
{
console.log(this.cars);
}
}
}
</script>
I can successfully emit and received the message, however the car model is not updated. I checked the message received and it contains the "model" key with a right value.
I cannot see any error in the Vue console and however if I replace "{{ model }}" by "{{ cars }}" I can see the full message object updated.
I am using Vue 2.x.
Update:
I enclose an example:
https://jsfiddle.net/kvzvxk4f/1/
As you can see in the example I cannot render an specific field from the object, however I can render the object as string.
I think that you are misunderstanding some parts of the vue syntax.
How to access properties of an object:
You just need to write {{ car.model }} to access a property of an object.
How to iterate through an array in a template:
If you want to display all the cars in your template, you should write:
<div v-for="car in cars">
{{ car }}
</div>
As you see, the v-for directive allows you to iterate through an array.
What is v-model?
v-model is used to bind a variable to an input or a component.
<template>
<div>
<input type="text" v-model="foo" />
</div>
</template>
<script>
export default {
data () {
return {
foo: 'bar'
}
}
}
</script>
In that case, the foo property will be bound to the input text.
Last point:
In your case, to make it work, you also need to create a root element for your template, because a template can't have multiple root elements:
<template>
<div>
<div v-for="car in cars">
{{ car }}
</div>
</div>
</div>
I found the answer.
I just have to type property separated by ".". Like for example {{cars.model}}.
<template id="compo2">
<div>
<div>
{{ field.name }}
</div>
<div>
Received: {{ field }}
</div>
</div>
</template>
Example:
https://jsfiddle.net/zuhb7s8q/3/
I have a component named controls:
<li class="controls__item" v-if="options[0].save == 'show'">
<button class="btn" :options[0].saveAttr>Save</button>
</li>
I'm having trouble rendering an attribute defined in the options property:
<controls :options='[{ save: "show", saveAttr: "sampleAttr='0' "}]'></controls>
This is what I'm trying to achieve:
<button class="btn" sampleAttr='0'>Save</button>
That's not the correct syntax for binding in Vue.
If the name of the attribute to bind to is never going to change, you should specify the name in the controls component:
<li class="controls__item" v-if="options[0].save == 'show'">
<button class="btn" :sampleAttr="options[0].saveAttr">Save</button>
</li>
And just change the options to pass in a value for saveAttr:
<controls :options='[{ save: "show", saveAttr: "0" }]'></controls>
If the name of the attribute (or the number of attributes) could change, then you should pass an object to the v-bind directive like so:
<li class="controls__item" v-if="options[0].save == 'show'">
<button class="btn" v-bind="options[0].saveAttrs">Save</button>
</li>
And then pass in an object for saveAttrs:
<controls :options='[{save : "show", saveAttrs: { sampleAttr: 0 }]'></controls>
Let's start with your testdata (just a little clean up) let's say you have two buttons since it seems like you want to do that later on. I'm not yet sure what the save : "show" is supposed to do - so I do my best to give a flexible example.
[{
'text': 'Save',
'click': function() { alert('save'); }
,{
'text': 'Delete',
'click': function() { alert('delete'); }
}]
Not lets say you have that testdata in your component called "controls"
<controls :options="[{'text': 'Save','click': function() { alert('save'); },{'text': 'Delete','click': function() { alert('delete'); }}]"> </controls>
As we can see your controls has an property called options. So your code for your component should look like:
<template>
<div class="controls">
<li class="controls__item" v-for="control in options">
<button class="btn" #click="control.click">{{ control.text }}</button>
</li>
</div>
</template>
<script>
export default {
props: ['options']
}
</script>
You need to define the prop you want to bind on the component (options). Options is now bound according to our test date. Since it's an array we can use v-for to loop through it. We then bind the given text as button content and the given click function as on click event.
I hope this helps.