I have data in this form:
itemlist : {
"dates": [
"2019-03-15",
"2019-04-01",
"2019-05-15"
],
"id": [
"arn21",
"3sa4a",
"wqa99"
],
"price": [
22,
10,
31
]
}
I want to use v-for in my created component that loops through this object treating every index in those 3 nested arrays as one observation. So dates[0], id[0] and price[0]correspond to same item, dates[1] id[1] price[1] is second and so on.
So In other words I think I need to transform this into, but not sure:
0 : {
dates: "2019-03-15",
id: "arn21",
price: 22,}
1:{
dates: "2019-04-01",
id: "3sa4a",
price: 10}
}
2:...
Thats how I pass the data to the component:
<tempc v-for="i in itemlist" :key="i.id" :price="i.price" :dates="i.dates"></temp>
But this does not work for the original data
You can create a computed property for this:
Vue.component('my-component', {
template: '#my-component',
data() {
return {
itemlist: {
"dates": [
"2019-03-15",
"2019-04-01",
"2019-05-15"
],
"id": [
"arn21",
"3sa4a",
"wqa99"
],
"price": [
22,
10,
31
]
}
};
},
computed: {
// Note: here I assume these arrays will always have the same length
mergedList() {
return this.itemlist.dates.map((dates, i) => {
return {
dates,
id: this.itemlist.id[i],
price: this.itemlist.price[i]
};
});
}
}
});
var vm = new Vue({
el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.min.js"></script>
<div id="app">
<my-component></my-component>
</div>
<template id="my-component">
<ul>
<li v-for="i in mergedList" :key="i.id" :price="i.price" :dates="i.dates">
{{i.id}} - ${{i.price}} ({{i.dates}})
</li>
</ul>
</template>
Related
Please can someone teach me the method to swap two different data on click
For example, we have a data
data() {
return {
data_one: [
{
name: "Simo",
age: "32"
}
],
data_two: [
{
name: "Lisa",
age: "25"
}
],
}
},
then I want to put this data on v-for, and I want to add two buttons to swap from data_one and data_two and display data_one as default.
<button #click="change_to_data_one">Data 1<button>
<button #click="change_to_data_two">Data 2<button>
<li v-for="item in data_one">{{item.name}} - {{item.age}}<li>
🙏🙏🙏🙏🙏
Try to use computed property:
new Vue({
el: "#demo",
data() {
return {
data_one: [{name: "Simo", age: "32"}],
data_two: [{name: "Lisa", age: "25"}],
selected: "data_one"
}
},
computed: {
showData(){
return this[this.selected]
}
},
methods: {
swap(val) {
this.selected = val
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<button #click="swap('data_one')">Data 1</button>
<button #click="swap('data_two')">Data 2</button>
<ul>
<li v-for="(item, i) in showData" :key="i">{{item.name}} - {{item.age}}</li>
</ul>
</div>
In my third exercise, I have a json file that contains info about cars and their models.
I am trying to populate 2 dropdowns from that file:1 for cars and the corresponding models in the other dropdown but not able to do that.
In the models dropdown that I did below, i see some null elements! (maybe corresponding of a place occupied in previos selection).
I would like to have the models dropdown always have the first item by default.
Thanks for help.
json file data:
[
{"name": "Abarth",
"models": [
{"name": "124 Spider", "series": null},
{"name": "500", "series": null},
]
},
{"name": "Acura",
"models": [
{"name": "MDX", "series": null},
{"name": "NSX", "series": null},
{"name": "RL", "series": null},
{"name": "RSX", "series": null},
]
},
]
My Code:
<template>
<div>
Make:<select #change="switchView($event, $event.target.selectedIndex)">
<option
v-for="(item, index) in logitems"
:key="index"
v-bind:value="this.selected"
>
{{ item.name }}
</option>
</select>
Model:<select>
<option
v-for="(item, index1) in logitems"
:key="item"
>
{{ logitems[selectedIndex].models[index1]}} //not able to get the name !
</option>
</select>
</div>
</template>
<script>
import logs from "../assets/car-makes.json";
export default {
data() {
return {
logitems: logs,
selectedIndex: "0",
selected: {
name: "Abarth",
models: [
{
name: "124 Spider",
series: null,
},
{
name: "500",
series: null,
},
],
},
};
},
methods: {
switchView: function (event, selectedIndex) {
console.log(event, selectedIndex);
this.selectedIndex = selectedIndex;
},
},
};
</script>
Try like following snippet:
new Vue({
el: '#demo',
data() {
return {
logitems: [
{ name: "Abarth",
models: [{name: "124 Spider", series: null}, {name: "500", series: null},]
},
{ name: "Acura",
models: [{name: "MDX", series: null}, {name: "NSX", series: null},
{name: "RL", series: null }, {name: "RSX", series: null },]
},
],
selected: {
name: 'Abarth',
model: ''
}
};
},
computed: {
models(){
return this.logitems.filter(l => l.name === this.selected.name)
}
},
methods: {
clearModel() {
this.selected.model = this.logitems.find(l => l.name === this.selected.name).models[0].name
}
}
})
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div>
Make:<select v-model="selected.name" #change="clearModel">
<option
v-for="(item, index) in logitems"
:key="index"
:value="item.name"
>
{{ item.name }}
</option>
</select>
Model:<select v-model="selected.model">
<option
v-for="(item, i) in models[0].models" :key="i">
{{ item.name }}
</option>
</select>
<p>{{ selected }}</p>
</div>
</div>
I have an array of objectsand I want to show only 3 at a time with a button that when clicked,show 3 more, making 6 in total and so on.
This is what I have currently:
// vue template
<ul>
<li v-for="(order, index) in orders" :key="index">
{{order.item_description}}
</li>
</ul>
<button #click="loadMore">load more </button>
For the script, I have the data and some computed properties:
data() {
return {
orders: [
{
id: 1,
item_description: "One",
created_at: "23, Dec 2019",
delivery_address: "Location",
cost: "2500"
},
{
id: 2,
item_description: "Two",
created_at: "23, Dec 2019",
delivery_address: "Location",
cost: "2500"
},
{
id: 3,
item_description: "Three",
created_at: "23, Dec 2019",
delivery_address: "Location",
cost: "2500"
}
// .... upto 12 items
],
currentPage: 1,
maxPerPage: 3
}
},
computed: {
totalResults() {
return Object.keys(this.orders).length
},
pageCount() {
return Math.ceil(this.totalResults / this.maxPerPage)
},
pageOffest() {
return this.maxPerPage * this.currentPage
}
},
methods: {
loadMore() {
this.currentPage += 1
}
}
}
My confusion is how to get the orders to be paginated using the maxPerPage and then add more using the loadMore
Here is a codesandbox for demo
You can add computed property like:
paginatedOrders() {
return this.orders.slice(0, this.currentPage * this.maxPerPage);
}
And then make your loop with this property:
<li v-for="(order, index) in paginatedOrders" :key="index">{{order.item_description}}</li>
additonnaly you can hide read more button if you already display all items
<button #click="loadMore" v-if="currentPage * maxPerPage < orders.length">load more</button>
Check it on codesandbox
Note: Keep in mind that the most common use of the "load more" button is to load other items with an api call or ajax request. This only works if you load all your orders beforehand.
I'm using a slot to display a button in Vue Tables 2. How can I pass the id of the warehouse i.e. 123 or 456 to the edit() event handler?
I've tried adding props (as this is what the docs show). But I haven't had any luck. I'm using Vue Tables 2 in a component.
<template>
<div>
<h1>How to pass warehouse id to edit() method?</h1>
<v-client-table :columns="columns" :data="warehouses" :options="options">
<span slot="actions" slot-scope="{ WarehousesMin }">
<button v-on:click="edit">Edit</button>
</span>
</v-client-table>
</div>
export default {
name: 'WarehousesMin',
data() {
return {
warehouses: [
{"id": 123, "name": "El Dorado", "loc": "EDO"},
{"id": 456, "name": "Tartarus", "loc": "TAR"}
],
options: {
headings: {name: 'Name', code: 'Loc', actions: 'Actions'}
},
columns: ['name', 'loc', 'actions'],
}
},
methods: {
edit (warehouseId) {
// How to get id of warehouse here? i.e. 123 or 456
}
}
}
I haven't used this library before, but as far as I know about Vue slots, you can change your code into this and try again:
<template>
<div>
<h1>How to pass warehouse id to edit() method?</h1>
<v-client-table :columns="columns" :data="warehouses" :options="options">
<span slot="actions" slot-scope="{row}">
<button v-on:click="edit(row.id)">Edit</button>
</span>
</v-client-table>
</div>
and in script part, change to:
export default {
name: 'WarehousesMin',
data() {
return {
warehouses: [
{"id": 123, "name": "El Dorado", "loc": "EDO"},
{"id": 456, "name": "Tartarus", "loc": "TAR"}
],
options: {
headings: {name: 'Name', code: 'Loc', actions: 'Actions'}
},
columns: ['id', 'name', 'loc', 'actions'],
}
},
methods: {
edit (warehouseId) {
// The id can be fetched from the slot-scope row object when id is in columns
}
}
}
I think this ought to work, but if not please let me know.
I am finding it very difficult to re-define the return information so that it is suitable for ng-repeat to iterate over it in the view.
I have two views one for an index that i want the year-month to encompass the countries (might be 1+ or none) and then inside each country i want the name of each event (again could be 1+ or none). The second view i just want to pass the event details and will be calling these details by passing the event index number in order to return all the event details (name, mname, net).
The Data:
{
months: [
{
index: 201602,
year: "2016",
mon: "February",
country1: [
{
index: 12345678,
l: [
{
name: "Test1",
mname: "Test 1",
net: "February 10, 2016 11:39:00 UTC",
}
]
},
{
index: 23456789,
l: [
{
name: "Test2",
mname: "Test 2",
net: "February 10, 2016 11:39:00 UTC",
}
]
}
],
country2: [ ]
},
{
index: 201603,
year: "2016",
mon: "March",
country1: [
{
index: 546547657654,
l: [
{
name: "Test1",
mname: "Test 1",
net: "March 10, 2016 11:39:00 UTC",
}
]
}
],
country2: []
},
{
index: 201604,
year: "2016",
mon: "April",
country1: [ ],
country2: [
{
index: 78676756,
l: [
{
name: "Test1",
mname: "Test 1",
net: "April10, 2016 11:39:00 UTC",
}
]
}
]
}
]
}
In order for ng-repeat to work, you'll have to extract the country data in some another array (transform the initial data somehow).
If those country fields have consistent naming (like 'country' infix on each of them), you can extract them into their own array and use ng-repeat to iterate over it.
Here is working solution. It assumes that country arrays all have the word 'country' in their name:
function MyCtrl($scope) {
$scope.countriesData = prepData(sampleData);
function prepData(data) {
return data.months.map(function(yearMonth) {
var transformed = { yearMonth: yearMonth, countries: [] };
for (var key in yearMonth) {
if (key.indexOf('country') != -1) {
transformed.countries.push(yearMonth[key]);
}
}
return transformed;
});
}
}
var sampleData = {
months: {
//...
}
}
The solution takes the data you've provided and transforms it into an array of entries like this one: { yearMonth: yearMonth, countries: [] };
You'll just have to render them like this:
<div ng-controller="MyCtrl">
<ul>
<li ng-repeat="entry in countriesData">
ym-id: {{entry.yearMonth.index}}
<ul>
<li ng-repeat="country in entry.countries">
<ul>
<li ng-repeat="event in country">
event-id: {{event.index}}
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
You can check the fiddle here: http://jsfiddle.net/tvy4jbvs/