Using Vue components - setattr - invalid attribute name - javascript

I am in the early stages of using Vue.js, and have come unstuck when attempting to use components. The non component version of this code worked fine.
The following returns an error, which I am having trouble deciphering, but it looks like I am passing a comma somewhere where there should be an attribute of the object.
Is it clear where the issue is arising here?
Error
Uncaught DOMException: Failed to execute 'setAttribute' on 'Element':
',' is not a valid attribute name.
HTML
<div id="list_render">
<ol>
<todo-item
v-for="item in todo_list",
v-bind:todo="item",
v-bind:key="item.id">
</todo-item>
</ol>
</div>
JS
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
var todo = new Vue({
el: '#list_render',
data: {
todo_list: [
{ id: 0, text: 'Learn Vue' },
{ id: 1, text: 'Plan project' }
]
}
})

Remove commas here:
<todo-item
v-for="item in todo_list"
v-bind:todo="item"
v-bind:key="item.id">
It should look like a regular HTML element, with no commas inside.

In extension to previous answer
error: <input v-model="text" , type="text"/>
works: <input v-model="text" type="text"/>

Related

Vue.delete warning to avoid using JavaScript unary operator as property name on click

I get the following warning when using Vue.delete:
[Vue warn]: Error compiling template: avoid using JavaScript unary operator as property name: "delete(testObj,)" in expression #click="Vue.delete(testObj,'label')"
I can use Vue.delete anywhere else and it seems fine. Am I using it wrong?
new Vue({
el: '#app',
data() {
return {
testObj: {
label: "The label"
}
};
}
});
<div id="app">
{{testObj.label}}
<button #click="Vue.delete(testObj,'label')">Delete</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.11/dist/vue.js"></script>
The global Vue will not be available inside your template. Everything in a template is scoped to the current Vue instance, so you're effectively trying to access this.Vue. Trying to access any of the properties of the global Vue won't work.
You can use $delete instead of Vue.delete inside a template.
https://v2.vuejs.org/v2/api/#vm-delete
new Vue({
el: '#app',
data() {
return {
testObj: {
label: "The label"
}
};
}
});
<div id="app">
{{testObj.label}}
<button #click="$delete(testObj, 'label')">Delete</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.11/dist/vue.js"></script>
I would add that the specific error message you're seeing relates more generally to trying to use any property called delete but that's something of a moot point as you should be using $delete anyway.

Vue 2 Prop value not rendering in the template

I have this code where I am trying to render a value from prop in the template but getting a
Uncaught ReferenceError: channel is not defined
<script>
Vue.component('itemstable', {
template: `<div>${channel}</div>`, // this is where the error occurs.
props: ['channel'],
data() {
return {
}
}
})
new Vue({
el: '#items_app',
data: {
selectedChannel: 'pos',
channels: JSON.parse(`["pos","kiosk"]`)
}
})
</script>
and here is the markup:
<div id="items_app">
<itemstable
:channel="selectedChannel"
></itemstable>
</div>
I have tried changing the name of the prop thinking 'channel' might be a reserve word, but the
same thing happens.
Change the javascript interpolation ${} to vue expression {{}}
template: `<div>{{channel}}</div>`,

Vue.js 2.0 filters in text interpolations

I'm using vue.js 2.0 (standalone) build.
HTML:
<div id="app">
<p> ${ number | results_found } </p>
</div>
JS:
<script>
var app = new Vue({
delimiters: ['${', '}'],
el: '#app',
data: {
number: 0,
},
filters: {
results_found: function(value) {
console.log(value + " results found!");
return value + " results found!";
}
}
})
</script>
I changed the delimiters (see above) so that they would not conflict with Django's templating syntax.
When I run this I see in the console:
[Vue warn]: Failed to resolve filter: results_found (found in anonymous component - use the "name" option for better debugging messages.)
0 results found!
Yet in the HTML all I see is:
0
What am I doing wrong? All new to Vue.js, by the way.
EDIT: Also how do I "name" components for better debugging? My filter is on my instance, not a component...

bind data to vue model dynamically in component

I'm trying to make a simple form that will accept user's input for different types of currency.
Here's a (broken) fiddle that hopefully gets across what I want to do:
https://jsfiddle.net/4erk8yLj/7/
I'd like my component to bind data to my root vue instance, but I'm not sure if my v-model string is allowable. Check it out:
Vue.component('conversion-row', {
props: ['currency', 'values'],
template: '<div>{{currency}}:</div><div><input v-model="values[currency]></div><',
});
var vm = new Vue({
el: "#app",
data: {
currencies: ['USD', 'BTC'],
values: {
'BTC': '',
'USD': ''
}
}
});
template:
<div id="app">
<li>
<conversion-row is li v-for="currency in currencies" v-bind:currency="currency">
</conversion-row>
</li>
</div>
What's a good way to fix this?
Couple of things you might need to correct:
First, the data property must be a function rather than an object. This allows every instance to get data recomputed every time it is being created, see:
var vm = new Vue({
el: "#app",
data() {
return {
currencies: ['USD', 'BTC'],
values: {
'BTC': 'BTC Value',
'USD': 'USD Value',
},
};
}
});
Second, <conversion-row> doesn't have values property bound. Here's what you can do:
<div id="app">
<li v-for="currency in currencies">
<conversion-row :currency="currency" :values="values"></conversion-row>
</li>
</div>
Last, the component should always aim for one root element (wrapper) and then you can nest as many children inside as you want. What's more, instead of using v-model, you can bind value which is the proper way to pass a value to an input (one-way data binding), check the following:
Vue.component('conversion-row', {
props: ['currency', 'values'],
template: '<div>{{currency}}:<input type="text" :value="values[currency]"></div>'
});
There's more improvements you could possibly make here like re-thinking if you need to pass values as well as currency to the conversion-row but I'm pretty sure you'll figure it out later on.
All that above will make your code run and execute properly, here's the working example (fork of yours):
https://jsfiddle.net/maciejsmolinski/mp8m0ben/1/
Does this help?
Not sure what you're aiming for in terms of using v-model, but here's an example of working v-model (based on your example):
Vue.component('conversion-row', {
props: ['currency', 'values'],
template: '<div>{{currency}}:<input type="text" v-model="values[currency]"></div>'
});
And the corresponding template:
<div id="app">
<p><strong>USD Value:</strong> {{ values.USD }}</p>
<p><strong>BTC Value:</strong> {{ values.BTC }}</p>
<br>
<li v-for="currency in currencies">
<conversion-row :currency="currency" :values="values"></conversion-row>
</li>
</div>
You can find it under the following URL:
https://jsfiddle.net/maciejsmolinski/0xng8v86/2/

Checkbox form array data Vue 2

I have a checkbox list which is generated using a for loop that consists of an id and a name:
Data:
yards[{id:1,name:'test'}] etc
HTML:
<ul class="checkbox-list">
<template v-for="(yard, index) in yards">
<li>
<input type="checkbox"
v-bind:id="'yardlist_'+yard.name"
v-bind:value="yard.id"
v-model="newSchedule.yards.id">
<label v-bind:for="'yardlist_'+yard.name">{{ yard.name }}</label>
</li>
<li>
<input type="text"
class="form-control"
placeholder="Yard notes..."
v-model="newSchedule.yards.notes">
</li>
</template>
</ul>
I want to save the selected checkbox with the id and notes field in an array:
newSchedule: {
due_at: '',
notes: '',
users: [],
yards: [{id:'',notes:'']
}
I have tried using the index from the yards array: newSchedule.yards[index].notes but am getting the following error "TypeError: undefined is not an object (evaluating 'newSchedule.yards[index].id')"
Any ideas how I can achieve this?
** Update **
Here is a basic fiddle of what I am wanting to achieve:
https://jsfiddle.net/j7mxe5p2/13/
I think you are trying to mix the old jQuery or javascript way of doing things with Vue framework. You should not have to set id on <input> elements to capture or set its value.
The correct way to do this is as follows:
new Vue({
el: '#app',
data: function() {
return {
yards: [
{id: 1, name: 'test', selected: true},
{id: 2,name: 'test 2', selected: false},
{id: 3,name: 'test 3', selected: false},
{id: 4,name: 'test 4', selected: true}
]
};
},
template: `
<div class="list-of-yards"> <!-- You cannot use v-for on the top-level element -->
<label for="jack" v-for="yard in yards">
<input type="checkbox" v-model="yard.selected"> {{yard.name}}
</label>
</div>
`,
});
Here is a jsFiddle of the above code: https://jsfiddle.net/z48thf9a/
Things to note:
You cannot use v-for on the template tag itself
You cannot use v-for on the top-level element just inside template. The template should contain one and only enclosing element, typically a <div>
There is no need to set id on input elements. You need to use v-model for your model-view bindings
If you still have issues, please provide a jsFiddle to debug further.
Edited after comment #1 and #2:
My above response is focused more on constructing the Vue component and rendering the list with proper binding to the checkboxes.
To get the checked items into a separate array, you can use a computed property in the same component to run through the original array this.yards and create a new array of selected items only.
Here is the jsFiddle for capturing the checked values: https://jsfiddle.net/z48thf9a/1/
You may modify the above to capture only the id part, and rename selectedYards to newSchedule or whatever your app requires.
I am not sure if I understood your question correctly, and if this solves your issue. Can you please provide more code samples?

Categories

Resources