Checkbox form array data Vue 2 - javascript

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?

Related

ais-refinement-list in VueInstantSearch(Algolia) doesn't renders list

I have stucked with an issue using refinement list widget of algolia.
First of all my resulting data structure is like that:
[
{
objectID: 999,
title: 'some title',
categories: [
{
id: 444,
name: 'some name',
},
{...},
]
}
]
I have that type of structure on my page:
<ais-instant-search
:search-client="searchClient"
:initial-ui-state="{
index_Name: { query: searchedValue },
}"
index-name="index_Name"
>
<ais-index index-name="index_Name">
<ais-configure
:filters="facetsFilters"
:facets="['categories.id']"
:hits-per-page.camel="items"
/>
<ais-refinement-list attribute="categories.id" />
<div> ...Some other widgets nested in divs as ais-search-box, ais-sort-by, etc </div>
</ais-index>
</ais-instant-search>
Within ais-configure I have passed to filters a facetsFilters variable which contains string with such content:
"categories.id:1 OR categories.id:5"
and it works ok, I'm getting results within selected categories,
problems starts, when i try to get refinement-list here:
<ais-refinement-list attribute="categories.id" />
I have an empty list despite that on dashboard this attribute is added as an attributesForFacetings and in ais-configure filters parameters with categories.id in it also works well.
Any suggestions is highly appreciated !
Problem was in Dashboard of Algolia.
When we clicked on 'searchable' instead of 'filter only' radiobutton for chosen attributeForFaceting - everything starts working good.

Using Vue components - setattr - invalid attribute name

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"/>

passing array of objects to a component in vue.js

I am having problem to pass an array of objects to component in Vue.js 2.2.
Here is my component
<vue-grid :fields = "[
{name: 'Person Name', isSortable: true},
{name: 'Country', isSortable: true}]"
></vue-grid>
It doesn't work as it renders the curly braces in the browser.
I've tried without the quotation " in the object and without the colon : in front of fields property. None of these work either.
However, if I just pass a simple string that works. I don't know why object is not working.
I have found a similar question but answer was given for php. I need the solution just for JavaScript. I want to hard code the object array in the component.
You are passing it correctly. You must have something else happening behind the scenes. Ensure your template has a wrapping element. See this fiddle
<div id="vue-app">
<h2>
Vue App
</h2>
<vue-grid :fields = "[
{name: 'Person Name', isSortable: true},
{name: 'Country', isSortable: true}]"
></vue-grid>
</div>
<script id="vue-grid-template" type="text/x-template">
<div>
<h3>Grid</h3>
<div class="grid">
Fields are:
<ul>
<li v-for="field in fields">
{{field.name}} - {{field.isSortable}}
</li>
</ul>
</div>
</div>
</script>
<script>
Vue.component('vue-grid', {
props: ['fields'],
template: '#vue-grid-template'
});
new Vue({
el: '#vue-app'
});
</script>

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/

How to make angular empty filters match undefined and null values?

I've found a problem while typing a filter and then remove it, the collection keeps being filtered and not showing the items with undefined or null values in the filtered term.
An example code:
<div ng-app="App" ng-controller="AppController as app">
<p>
Filters
</p>
Name: <input ng-model="listFilters.name" type="text"/>
<br/>
Short Description: <input ng-model="listFilters.shortDescription" type="text"/>
<ul>
<li ng-repeat="person in app.persons | filter:{name: listFilters.name, shortDescription: listFilters.shortDescription}">
<p>{{person.name}}</p>
</li>
</ul>
</div>
The angular code:
angular.module('App', []);
angular.module('App').controller('AppController', AppController);
function AppController() {
var ctrl = this;
ctrl.persons = [
{
name: 'Bill',
shortDescription: null
},
{
name: 'Sally',
shortDescription: 'A girl'
},
{
name: 'Jhon',
},
];
}
A working fiddle: https://jsfiddle.net/89pkcww2/
Steps to see the problem I'm talking about:
Filter by name, the list is filtered.
Erase the filter, see how the list is again displayed (Bill, Sally, Jhon).
Filter by description, the list is filtered.
Erase the filter, only the second value of the collection is displayed (Sally) the ones with undefined or nulls aren't. It's filtering by "empty string".
I guess this is a default behavior in Angular filters but... is there a way to change it? Do I have to make my own filter?
I want to filter by both properties separately, the collection | filter: filter.var does not serve this purpose.
Nor this is the same as filtering to show only not null values, it's closer to the opposite...
shortDescription: null , it doesnt mean '' , null != '' , so when you delete the text from the 'short description' it doesnt show 'Bill' item.
on third item there is not shortDescription at all so the ng-model="listFilters.shortDescription" cant bind to the property.
only 'Sally' item works ok because the ng-model can bind to the property.
Update your li html to something like this:
<li ng-repeat="person in app.persons | filter:listFilters.name">
Here is the updated fiddle: https://jsfiddle.net/89pkcww2/1/

Categories

Resources