Loop Object with Objects in Vue2 template - vue.js

Hi I use VueJs with TypeScript and I want to loop response result with type Section that have Array of Articles the response looks like:`
{
{
id: 1,
name: "Test",
articles: [
{
id: 1,
name: "Test",
price: 1.0,
quantity: 1
}
]
},
{
id: 1,
name: "Test",
articles: [
{
id: 1,
name: "Test",
price: 1.0,
quantity: 1
}
]
}
}
I tried with v-for but does not recognize id prop and the type is not section but
const section: string | number | boolean | Date | Article[] | undefined

First, your object is not JSON valid as #neha mentioned also.
It should be like this:
{
"obj1":{
id: 1,
name: "Test",
articles: [
{
id: 1,
name: "Test",
price: 1.0,
quantity: 1
}
]
},
"obj2":{
id: 1,
name: "Test",
articles: [
{
id: 1,
name: "Test",
price: 1.0,
quantity: 1
}
]
}
}
Then you will be able to "loop" like this:
<div id="app">
<ul>
<li v-for="(item, key, index) in objectItems">
{{ item.id }} - {{ key }} - {{ index }}
</li>
</ul>
</div>
The example is from DigitalOcean:
https://www.digitalocean.com/community/tutorials/vuejs-iterating-v-for
But I strongly suggest you redo the object from the backend so that the main object will be in an array.

Related

Group transition with dynamic list as a whole

I have a data_sets. I need to take out a certain dataset (data_source in the snipped), filter it (itemList in the snippet) and display it, with any simple group transition, preferably list transition in Vue's official guide
This is a snippet that I created on https://sfc.vuejs.org/ to play around.
<template>
<div>
<ul>
<transition-group name="list" mode="out-in">
<li v-for="item in itemList" :key="item.id">
{{item.content}}
</li>
</transition-group>
</ul>
</div>
<button #click="changeDatasource(0)">
Dataset 1
</button>
<button #click="changeDatasource(1)">
Dataset 2
</button>
<button #click="changeDatasource(2)">
Dataset 3
</button>
</template>
<script>
export default {
data() {
return {
data_sets: [
[{
id: 1,
content: "Frog",
active: 1,
},
{
id: 2,
content: "Elephant",
active: 0,
},
{
id: 3,
content: "Racoon",
active: 1,
},
{
id: 8,
content: "Cheetah",
active: 1,
},
],
[{
id: 4,
content: "Rooster",
active: 1,
},
{
id: 5,
content: "Cow",
active: 1,
},
{
id: 6,
content: "Cat",
active: 1,
},
{
id: 7,
content: "Dog",
active: 0,
},
],
[{
id: 10,
content: "Lion",
active: 1,
},
{
id: 11,
content: "Shark",
active: 1,
},
{
id: 12,
content: "Bee",
active: 0,
},
{
id: 13,
content: "Cockroaches",
active: 0,
},
],
],
data_source: [],
}
},
computed: {
itemList: {
get() {
return this.data_source.filter((item) => item.active)
},
set(newValue) {
//this.itemList = newValue; <--
}
}
},
methods: {
changeDatasource: function(id) {
//this.itemList = [] <--
this.data_source = this.data_sets[id];
}
}
}
</script>
<style scoped>
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>
When clicking on buttons to choose a data set, you can see the transition is not okay: old items still present when the new ones come in. The expected order should be: old items disappears, then new items come in.
It's very likely because itemList is replaced as a whole at a time. So I've tried to:
Empty itemList = [],
Continue to make the changes. (the commented part in the snippet)
RangeError: Maximum call stack size exceeded
Guess it bounds to some kind of infinite loop, at this point I'm completely pointless.
I've also messed around with transition mode, it isn't better.
My question is there any way to apply transition to list as a whole like this?
Solved it by working around with setTimeout and setInterval and changed from computed propery to watch.
Content shifting is there but a little CSS and JavaScript manipulation will fix it. Not the best solution but by now that's what I can think of.
Result snippet
<template>
<div>
<ul>
<transition-group name="list">
<li v-for="item in itemList" :key="item.id">
{{item.content}}
</li>
</transition-group>
</ul>
</div>
<button #click="changeDatasource(0)">
Dataset 1
</button>
<button #click="changeDatasource(1)">
Dataset 2
</button>
<button #click="changeDatasource(2)">
Dataset 3
</button>
</template>
<script>
export default {
data() {
return {
data_sets: [
[{
id: 1,
content: "Frog",
active: 1,
},
{
id: 2,
content: "Elephant",
active: 0,
},
{
id: 3,
content: "Racoon",
active: 1,
},
{
id: 8,
content: "Cheetah",
active: 1,
},
],
[{
id: 4,
content: "Rooster",
active: 1,
},
{
id: 5,
content: "Cow",
active: 1,
},
{
id: 6,
content: "Cat",
active: 1,
},
{
id: 7,
content: "Dog",
active: 0,
},
],
[{
id: 10,
content: "Lion",
active: 1,
},
{
id: 11,
content: "Shark",
active: 1,
},
{
id: 12,
content: "Bee",
active: 0,
},
{
id: 13,
content: "Cockroaches",
active: 0,
},
],
],
data_source: [],
itemList: [],
}
},
methods: {
changeDatasource: function(id) {
//this.itemList = [] <--
this.data_source = this.data_sets[id];
}
},
watch: {
data_source: function(newValue, oldValue) {
let initialLength = this.itemList.length;
if (initialLength > 0) {
this.itemList = [];
}
let dataLength = newValue.length;
let interval = 200;
let i = 0;
let timer = setInterval(() => {
setTimeout(() => {
if (typeof newValue[i - 1] != 'undefined') {
this.itemList.push(newValue[i - 1])
}
}, interval)
if (i === dataLength - 1) {
clearInterval(timer);
}
i++;
}, interval)
}
}
}
</script>
<style scoped>
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>

how to multi filtering vue.js

just new in vue.js.
I have an array of objects which is my products, How to multi filter it?
HTML
<input type="checkbox" required v-model="selectedCategory" value="1"> // Category 1
<input type="checkbox" required v-model="selectedCategory" value="2"> // Category 2
<div>
<div v-for="product in filteredProducts">
<a href="#">
<div class="prdct-frame__img-holder">
<img :src="product.productImage">
</div>
<p>{{ product.productName }}</p>
</a>
</div>
</div>
SCRIPT
<script>
var vm = new Vue({
el: "#main",
data: {
products: [
{
productName: "Product 1",
productID: 1,
productImage: //via.placeholder.com/200x200,
categoryID: true,// 1
colorID: 1, //blue
sizeID: 1, //large
},
{
productName: "Product 2",
productID: 2,
productImage: //via.placeholder.com/200x200,
categoryID: true, // 1
colorID: 2, //red
sizeID: 2, //medium
},
{
productName: "Product 3",
productID: 3,
productImage: //via.placeholder.com/200x200,
categoryID: true, // 2
colorID: 3, //green
sizeID: 3, //small
},
{
productName: "Product 4",
productID: 4,
productImage: //via.placeholder.com/200x200,
categoryID: true, // 2
colorID: 4, //green
sizeID: 3, //small
},
],
selectedCategory: [],
},
computed: {
filteredProducts: function() {
var vm = this;
var category = vm.selectedCategory;
return vm.products.filter((product) => {
var keys = Object.keys(product);
var matchFilter = false;
category.forEach((key) => {
if(product[key] === true) {
matchFilter = true;
}
});
return matchFilter;
});
},
}
});
</script>
This Code works for filtering by category, if I filter by Category 1 it display all the products under Category 1 which is right. Now I want to filter it too by color and size.
For example if choose Category 1 and choose color is red and choose size is medium
The expected out put will be :
Product name : Product 2
Color : red
Size : medium
You should use an Array of filters:
data()
{
return {
filtration:
[
{
key: 'categoryID',
value: 2
},
{
key: 'colorID',
value: 2
},
{
key: 'sizeID',
value: 2
},
]
}
},
computed: {
filteredProducts: function() {
const arrFilters = this.filtration;
return this.products.filter((product) => {
return arrFilters.every((filter) => {
return product[filter.key] === filter.value;
});
});
},
}

how to get 1 row value from (onclick) selected row datatables vue js 2

hello i didnt have any example to try this method..
can any one give me some little example for take 1 row value from datatable (onclick) selected row on vue js.
this is my template table
<template>
<div class="table-responsive">
<datatable title="" :rows="tableData" :columns="columndata" :options="options"></datatable>
</div>
</template>
and this is my javascript
export default {
data(){
return {
columns: ['id', 'name', 'age'],
tableData: [
{ id: 1, name: "John", age: "20" },
{ id: 2, name: "Jane", age: "24" },
{ id: 3, name: "Susan", age: "16" },
{ id: 4, name: "Chris", age: "55" },
{ id: 5, name: "Dan", age: "40" }
],
options: {
// see the options API
}
}
}

Two-Way Binding in Component Scope

Suppose I'm trying to make a simple questionnaire, where the user answers a list of questions.
new Vue(
{
el: "#app",
data:
{
questions:
[
{
id: 1,
name: "What is your favorite color?",
selectedId: 2,
choices:
[
{ id: 1, name: "red" },
{ id: 2, name: "green" },
{ id: 3, name: "blue" },
]
},
...
]
}
});
How do I go about making a question component with two-way binding. That is, if the user swaps their favorite color from green to red, by clicking on the respective input, the selectedId will automatically update. I'm not very clear on how v-model works within a component. Does it only have access to the components data? Also, I don't understand the difference between props/data.
There are lots of ways you can approach this, here's my attempt:
let id = 0;
Vue.component('question', {
template: '#question',
props: ['question'],
data() {
return {
radioGroup: `question-${id++}`,
};
},
methods: {
onChange(choice) {
this.question.selectedId = choice.id;
},
isChoiceSelected(choice) {
return this.question.selectedId === choice.id;
},
},
});
new Vue({
el: '#app',
data: {
questions: [
{
title: 'What is your favorite color?',
selectedId: null,
choices: [
{ id: 1, text: 'Red' },
{ id: 2, text: 'Green' },
{ id: 3, text: 'Blue' },
],
},
{
title: 'What is your favorite food?',
selectedId: null,
choices: [
{ id: 1, text: 'Beans' },
{ id: 2, text: 'Pizza' },
{ id: 3, text: 'Something else' },
],
},
],
},
});
.question {
margin: 20px 0;
}
<script src="https://rawgit.com/yyx990803/vue/master/dist/vue.js"></script>
<div id="app">
<question v-for="question of questions" :question="question"></question>
</div>
<template id="question">
<div class="question">
<div>{{ question.title }}</div>
<div v-for="choice of question.choices">
<input type="radio" :name="radioGroup" :checked="isChoiceSelected(choice)" #change="onChange(choice)"> {{ choice.text }}
</div>
<div>selectedId: {{ question.selectedId }}</div>
</div>
</template>

VueJS filterBy with dynamic argument

I have a VueJS object with data that looks like the following:
phases: [
{ id: 1, ... },
{ id: 2, ... },
{ id: 3, ... },
],
roles: [
{ phaseId: 1, title: "Account Manager" },
{ phaseId: 1, title: "Creative Director" },
{ phaseId: 2, title: "Account Manager" },
{ phaseId: 2, title: "Creative Director" },
]
And my v-for loop looks like the following:
<article v-for="phase in phases" class="phase">
... Other content ...
<div v-for="role in roles | filterBy phase.id in 'phaseId' ">
<p>${role.title}</p>
</div>
</article>
I'm trying to filter the roles array to only show roles with the "parent" phase given by the ID. Since the roles for-loop will be running multiple times, each time it will only show the appropriate roles.
Is there any way to accomplish this?
+1 #gurghet, filters are deprecated.
Use a method
data: {
phases: [
{ id: 1, ... },
{ id: 2, ... },
{ id: 3, ... },
],
roles: [
{ phaseId: 1, title: "Account Manager" },
{ phaseId: 1, title: "Creative Director" },
{ phaseId: 2, title: "Account Manager" },
{ phaseId: 2, title: "Creative Director" },
]
},
methods: {
filtered(id){
return this.roles.filter(rol => rol.phaseId === id)
}
}
Template:
<article v-for="phase in phases" class="phase">
... Other content ...
<div v-for="role in filtered(phase.id) ">
<p>${role.title}</p>
</div>
</article>
Exmaple
One can use a mixin that calls the actual filter
1. First we need to register a filter globally
Vue.filter('normalizetext', function (value) {
if (!value) return '';
value = value.toString();
value = value.replace('_', ' ').toLowerCase();
return value.charAt(0).toUpperCase() + value.slice(1);
})
2.Create a mixin
import Vue from 'vue';
export default {
/**
* The methods that the mixin used for filer functions.
*/
methods: {
/**
* Method used to check if specific element is found in an filer
*
* #param {filer} filtername filer to find created filter
*
* #returns {any} filtered output
*/
dynamicFilter(filterName, value) {
return Vue.filter(filterName)(value);
}
}
};
3.Calling filter
<template>
{{
dynamicFilter(data.FilterName, value)
}}
</template>