Vue: How to get rid of duplicate content - javascript

I have an array of names using v-for I get the names, as you can see I have two v-fors where the content is duplicated in this example my content is small and doesn't look so scary in real life it can be much bigger and all the problem is that the content is repeated, I tried to apply slots but could not cope
Template
<template>
<div>
<div v-for="(item, index) in array" :key="index" class="names">
<div class="show-names">
<p>{{ item.name }}</p>
</div>
<div
v-for="(girlNames, index) in item.girlNames"
:key="index"
class="names"
>
<div class="show-names">
<p>{{ girlNames.name }}</p>
</div>
</div>
</div>
</div>
</template>
Script
<script>
export default {
data() {
return {
array: [
{ name: "Alex" },
{ name: "Jacob" },
{ name: "Robert" },
{
girlNames: [
{
name: "Anna",
},
{
name: "Kiwi",
},
{
name: "Ava",
},
],
},
],
};
},
};
</script>
Yes, this picture shows where the content is repeated
You can also see code example in codesandbox

The only problem I see here is bad data structure. In my opinion it should be an object with two fields, which seperate in your case boys and girls, and in this object should be actual data:
<script>
export default {
data() {
return {
names: {
boys: [
{ name: "Alex" },
{ name: "Jacob" },
{ name: "Robert" },
],
girls: [
{ name: "Anna" },
{ name: "Kiwi" },
{ name: "Ava" },
]
}
},
],
};
},
};
</script>
They your code in template will be like:
<template>
<div>
<div class="names">
<div v-for="(item, index) in name.boys" :key="index" class="show-names">
<p>{{ item.name }}</p>
</div>
<div v-for="(item, index) in name.girls" :key="index" class="show-names">
<p>{{ item.name }}</p>
</div>
</div>
</div>
</template>

Related

How to iterate array value by comparing it with another array in Vuejs?

HelloWorld.vue
<template>
<div>
<div v-for="box in boxes" :key="box.sname">
<BaseAccordian>
<template v-slot:title>{{ box.sname }}</template>
<template v-slot:content>
<div v-for="paint in paints" :key="paint.tname" class="line">
<List :content="matchingdata" :sname="box.sname" />
</div>
</template>
</BaseAccordian>
</div>
</div>
</template>
<script>
import BaseAccordian from "./BaseAccordian.vue";
import List from "./List.vue";
export default {
name: "HelloWorld",
components: {
BaseAccordian,
List,
},
data() {
return {
boxes: [
{
sname: "apple",
},
{
sname: "bananna",
},
{
sname: "grapes",
},
{
sname: "choc",
},
],
paints: [
{
tname: "a",
},
{
tname: "b",
},
{
tname: "c",
},
{
tname: "d",
},
{
tname: "e",
},
],
matchingdata: [
{
matchid: "1",
OverallStatus: "ok",
sname: "choc",
},
{
matchid: "2",
OverallStatus: "notok",
sname: "grapes",
},
],
};
},
};
</script>
BaseAccordion.vue
<template>
<div class="wrapper">
<div class="accordion">
<input type="checkbox" #click="toggleItem" />
<h2 class="title">
<slot name="title"></slot>
</h2>
</div>
<div v-show="show" class="content">
<slot name="content"></slot>
</div>
</div>
</template>
<script>
export default {
components: {},
data: function () {
return {
show: false,
};
},
methods: {
toggleItem: function () {
this.show = !this.show;
},
},
};
</script>
List.vue
<template>
<div class="">
<div
v-for="match in matchingData"
:key="match.matchid"
:class="{
green: match.OverallStatus === 'ok',
red: match.OverallStatus === 'notok',
}"
>
{{ match.OverallStatus }}
</div>
</div>
</template>
<script>
export default {
components: {},
props: {
content: {
type: Array,
required: true,
},
sname: {
type: String,
required: true,
},
},
data: function () {
return {};
},
methods: {},
computed: {
matchingData() {
return this.content.filter((a) => {
if (a.sname === this.sname) {
return true;
} else {
return false;
}
});
},
},
};
</script>
<style scoped>
</style>
I three arrays called matchingdata,boxes,paints array based on this three arrays, i am trying to filter the array.(nested v-for)
Now, I want to iterate the matchingdata array by comparing it with sname in boxes array. and Common value between matchingdata and boxes array is ""sname""
I tried above logic, and struck with computed property.
Expected Output:-
In List.vue component , i have
{{ match.OverallStatus }} where that field , i want to show,(from the matchingdata array) when user clicked on checkbox.
Taking the ""sname"" the common value from the matchingdata array and the boxes array
code:- https://codesandbox.io/s/damp-pine-27s2kn?file=/src/components/List.vue
As you're passing the sname property as a string via a prop to your List.vue component, you'll just need to use that string in your filter function.
matchingData() {
return this.content.filter((a) => a.sname === this.sname)
},
I've tried this in your codesandbox link and it is giving some output - but I'm not clear enough on what you're trying to achieve to know if this is the intended outcome.
Just incase you're not aware the 'filter' function returns a new array. It's not going to return a 'true/false' which I feel you may be trying to do.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

How to filter an array by another array in vue

I have two arrays of object which one of them is called submodules which has a children array in it and I need to filter these childrens arrays by accessed array of objects
new Vue({
data: {
submodules: [
{
type: "something1",
children: [
{
name: "new_sth1",
value: "new_sth1"
},
{
name: "new_sth2",
value: "new_sth2"
}
]
},
{
type: "something2",
children: [
{
name: "new_sth3",
value: "new_sth3"
},
]
},
{
type: "something3",
children: [
{
name: "new_sth4",
value: "new_sth4"
},
{
name: "new_sth5",
value: "new_sth5"
},
{
name: "new_sth6",
value: "new_sth6"
},
]
},
],
accessed: [
{value: 'new_sth1'},
{value: 'new_sth2'},
{value: 'new_sth3'},
{value: 'new_sth4'},
]
}
})
<div class="row">
<div class="col-6 mt-3" v-for="item in submodules">
<div class="card" style="min-height: 260px">
<div class="card-header" style="background: #757575;color: white">
{{item.type}}
</div>
<div class="card-body">
<ul class="nav nav-pills nav-stacked mb-0 pb-0">
<li style="width: 100%;cursor: pointer" class="navbar my-0 py-0" v-for="child in item.children">
<a style="color: black" :href="'/'+child.value">
<span class="text-right navbar-text">{{child.name}}</span>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
I need to filter submodules array by accessed array values.
I tried many ways but I couldn't solve the problem.
If anyone has any idea please share it with me.
You can use computed property to filter the submodules array according to accessed.
computed properties in vue js
codesandbox: Code is not styled as I've not installed the bootstrap.
computed: {
getFilteredResult() {
return this.submodules.reduce((acc, curr) => {
const children = curr.children.filter(({ value }) => {
return this.accessed.find((x) => x.value === value);
});
acc.push({ ...curr, children });
return acc;
}, []);
},
},

Vue js props no data

I cant pass data to props in VueJS.
Here is my code:
const projects = [{ id: 1, name: 'First', img: "https://randomwordgenerator.com/img/picture-generator/53e0d7414855ac14f1dc8460962e33791c3ad6e04e5074417d2e72d2964cc6_640.jpg" },
{ id: 2, name: 'Second', img: "https://randomwordgenerator.com/img/picture-generator/paper-1100254_640.jpg" },
{ id: 3, name: 'Third', img: "https://randomwordgenerator.com/img/picture-generator/5fe2d4414352b10ff3d8992cc12c30771037dbf85254794075287cd69145_640.jpg" },
{ id: 4, name: 'Forth', img: "https://randomwordgenerator.com/img/picture-generator/5fe1d3414256b10ff3d8992cc12c30771037dbf8525478487c2f79d5924e_640.jpg" }
]
const Project = {
props: ['img', 'name'],
template: `
<div class="container projectbox">
<div class="textandimage"> Name: {{ projects.name }} </div>
</div>
`,
data() {
return {
projects
}
}
}
img:undefined
name:undefined
Please help.
Projects is a list (Array) of Objects. if you want to access an Object in the list, you need to reference its position. for example:
<div class="textandimage"> Name: {{ projects[0].name }} </div>
This will access the first Object in your list, and return the value of the key name
EDIT: for-loop
If you want to loop through the data to the template, do something like this:
<div v-for="(item, index) in projects" class="container projectbox" :key="index">
<div class="textandimage"> Name: {{ item.name }} </div>
</div>
Hope that makes more sense.

Live filter in custom select with input

I am trying to make a custom list filter on input using computed property. In one file I create a widget, in another I use it. Here is the code from the widget creation file:
<template>
<input value="Гарантийный случай"
v-model="searchText"
:class="{'w-autocomplete__input_completed': completed}"
ref="input"
#click="areOptionsVisible = !areOptionsVisible"/>
<div v-if="areOptionsVisible"
:style="{maxHeight: maxHeight, overflow: 'auto', zIndex: zIndex}"
class="w-autocomplete__items">
<div v-for="option in options" class="w-autocomplete__item_first" >
{{ option.name }}
<div v-for="item in option.children" class="w-autocomplete__item"
:class="{'w-autocomplete__item_active': currentIndex === item}"
#mouseenter="setActive(item)"
#keyup.up="changeCurrent('up', item)"
#keyup.down="changeCurrent('down', item)"
#click="doChoose(item)">
{{ item.name }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'dropdown',
props: {
placeholder: {
type: String,
required: false,
default: '',
},
options: {
type: Array,
default(){
return []
}
},
},
data: function () {
return {
counter: 0,
currentIndex: null,
completed: false,
chosenItem: null,
areOptionsVisible: false,
searchText: '',
data: [],
}
},
computed: {
options(){
return this.props.options.filter(elem => {
return elem.name.toLowerCase().includes(this.searchText.toLowerCase());
});
},
},
.......
}
</script>
This is how I pass the array to this list in another file:
<template>
........
<div class="complaint-form__line-item">
<div class="form-group">
<label>Гарантийный случай</label>
<dropdown :options="options" />
</div>
</div>
........
</template>
<script>
........
export default {
name: 'complaint-form',
components: {LockedImport, UploadFiles, CarNumberInput, Autocomplete, Dropdown},
props: {
......
}
},
data() {
const complaint = new Complaint();
return {
........
options: [
{name: 'Выход детали из строя в процессе эксплуатации', value: null,
children: [{name: 'Увеличение зазора, люфт (дробь/стуки)', value: 53},
{name: 'Обрыв детали', value: 54}]},
{name: 'Поломка при установке', value: null},
{name: 'Брак до установки', value: null,
children: [{name: 'Недокомплект', value: 55},
{name: 'Заводской брак (замятия, отсутствие резьбы, пробой пыльника и т.д.)',
value: 56}]},
],
}
},
Tell me please why computed doesn't work? Only I add computed and the list is not displayed at all when clicking on the field, but should. That is, it breaks down completely. I want to be filtered when entering text in input
Vue.js cannot have more than one element inside a <template> tag, so I would suggest that you enclose the whole code of the dropdown component within a <div> tag or something of the sort.
Also, and this is just a comment, I would suggest that you use the focus event for the input because with click it will still be showing even if you aren't focusing on the input.

vue v-for with filter gives error

I'm trying to use a local filter with v-for but I'm getting an error
Property or method "filterByTitle" is not defined on the instance but
referenced during render. Make sure that this property is reactive,
either in the data option, or for class-based components, by
initializing the property.
Code below
<template>
<div class="row">
<div class="col pt-5">
<ul class="blog-list-single" v-for="(post, index) in posts | filterByTitle" :key="index">
<li class="title">{{ post.title }}</li>
<li class="author">{{ post.author }}</li>
</ul>
</div>
</div>
</template>
<style lang="scss">
</style>
<script>
export default {
data() {
return {
posts: [
{ title: 'a', author: 'nd' },
{ title: 'b', author: 'nd' },
{ title: 'c', author: 'nd' },
],
selectedValue: 'a',
}
},
filters: {
filterByTitle(value) {
return value.filter(el => el.title == this.selectedValue)
}
},
}
</script>
Filters are limited in Vue 2 primarily to formatting string interpolations. You can also now use them in v-bind expressions.
In Vue 2, you would filter a list like this using a computed property.
console.clear()
new Vue({
el: ".row",
data() {
return {
posts: [{
title: 'a',
author: 'nd'
},
{
title: 'b',
author: 'nd'
},
{
title: 'c',
author: 'nd'
},
],
selectedValue: 'a',
}
},
computed: {
filterByTitle() {
// return the whole list if there is no filter value
if (!this.selectedValue) return this.posts
// otherwise return the list filtered by title
return this.posts.filter(el => el.title == this.selectedValue)
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<div class="row">
<div class="col pt-5">
<ul class="blog-list-single" v-for="(post, index) in filterByTitle" :key="index">
<li class="title">{{ post.title }}</li>
<li class="author">{{ post.author }}</li>
</ul>
</div>
</div>

Categories