In vue.js how can I filter products by size, color, category & by selecting each of these categories in step wise slider - vue.js

In vue.js how can I filter products by size, color, category & by selecting each of these categories in step-wise slider where I have to select each filter one by one step-wise & at last I need to display the products which pass through the filter.

Please share code examples and ask specific questions about where you are stuck. This question is very broad and is difficult to answer.
I'll try to provide an answer as best as I can.
You might have a ProductList component that may look something like this:
<template>
<!-- your template -->
</template>
<script>
import RangeSlider from "./RangeSlider";
export default {
name: "ProductList",
components: {
RangeSlider
},
data() {
return {
products: [],
filters: {
color: null,
size: null,
category: null
},
options: {
color: ["Red", "Yellow", "Green"],
size: ["Small", "Medium", "Large"],
category: ["Men", "Women", "Boy", "Girl"]
}
};
}
};
</script>
The RangeSlider can use the native <input type="range" /> control to build the functionality you want.
In this example, it takes a label and an array of options to build the control, and will emit a change event when the user changes the value of the control by sliding, which is captured in ProductList to set the filters. You can then use the filters object and make an API call to fetch your products.
<template>
<div class="range-slider">
<label>
<strong>{{ label }}</strong>
</label>
<div>
<input type="range" min="0" :max="max" step="1" #change="onInputChange" :value="rangeValue">
</div>
<div>{{ options[rangeValue] }}</div>
</div>
</template>
<script>
export default {
name: "RangeSlider",
props: ["label", "options"],
data() {
return {
rangeValue: 0
};
},
mounted() {
this.onChange(0);
},
methods: {
onInputChange(e) {
this.onChange(e.target.value);
},
onChange(rangeValue) {
this.rangeValue = rangeValue;
let selectedOption = this.options[this.rangeValue];
this.$emit("change", selectedOption);
}
},
computed: {
max() {
return this.options.length - 1;
}
}
};
</script>
<style>
.range-slider {
padding: 1rem;
border-bottom: 1px solid;
}
</style>
Here is the working example on CodeSandbox: https://codesandbox.io/s/rangesliderwithoptionsexample-6pe10

Related

How do have unique variables for each dynamically created buttons/text fields?

I'm trying to create buttons and vue element inputs for each item on the page. I'm iterating through the items and rendering them with v-for and so I decided to expand on that and do it for both the rest as well. The problem i'm having is that I need to to bind textInput as well as displayTextbox to each one and i'm not sure how to achieve that.
currently all the input text in the el-inputs are bound to the same variable, and clicking to display the inputs will display them all at once.
<template>
<div class="container">
<div v-for="(item, index) in items" :key="index">
<icon #click="showTextbox"/>
<el-input v-if="displayTextbox" v-model="textInput" />
<el-button v-if="displayTextbox" type="primary" #click="confirm" />
<ItemDisplay :data-id="item.id" />
</div>
</div>
</template>
<script>
import ItemDisplay from '#/components/ItemDisplay';
export default {
name: 'ItemList',
components: {
ItemDisplay,
},
props: {
items: {
type: Array,
required: true,
},
}
data() {
displayTextbox = false,
textInput = '',
},
methods: {
confirm() {
// todo send request here
this.displayTextbox = false;
},
showTextbox() {
this.displayTextbox = true;
}
}
}
</script>
EDIT: with the help of #kissu here's the updated and working version
<template>
<div class="container">
<div v-for="(item, index) in itemDataList" :key="itemDataList.id">
<icon #click="showTextbox(item.id)"/>
<El-Input v-if="item.displayTextbox" v-model="item.textInput" />
<El-Button v-if="item.displayTextbox" type="primary" #click="confirm(item.id)" />
<ItemDisplay :data-id="item.item.uuid" />
</div>
</div>
</template>
<script>
import ItemDisplay from '#/components/ItemDisplay';
export default {
name: 'ItemList',
components: {
ItemDisplay,
},
props: {
items: {
type: Array,
required: true,
},
}
data() {
itemDataList = [],
},
methods: {
confirm(id) {
const selected = this.itemDataList.find(
(item) => item.id === id,
)
selected.displayTextbox = false;
console.log(selected.textInput);
// todo send request here
},
showTextbox(id) {
this.itemDataList.find(
(item) => item.id === id,
).displayTextbox = true;
},
populateItemData() {
this.items.forEach((item, index) => {
this.itemDataList.push({
id: item.uuid + index,
displayTextbox: false,
textInput: '',
item: item,
});
});
}
},
created() {
// items prop is obtained from parent component vuex
// generate itemDataList before DOM is rendered so we can render it correctly
this.populateItemData();
},
}
</script>
[assuming you're using Vue2]
If you want to interact with multiple displayTextbox + textInput state, you will need to have an array of objects with a specific key tied to each one of them like in this example.
As of right now, you do have only 1 state for them all, meaning that as you can see: you can toggle it for all or none only.
You'll need to refactor it with an object as in my above example to allow a case-per-case iteration on each state individually.
PS: :key="index" is not a valid solution, you should never use the index of a v-for as explained here.
PS2: please follow the conventions in terms of component naming in your template.
Also, I'm not sure how deep you were planning to go with your components since we don't know the internals of <ItemDisplay :data-id="item.id" />.
But if you also want to manage the labels for each of your inputs, you can do that with nanoid, that way you will be able to have unique UUIDs for each one of your inputs, quite useful.
Use an array to store the values, like this:
<template>
<div v-for="(item, index) in items" :key="index">
<el-input v-model="textInputs[index]" />
</div>
<template>
<script>
export default {
props: {
items: {
type: Array,
required: true,
},
},
data() {
textInputs: []
}
}
</script>

How can I change the backgroundColor of a row in a beufy datatable with a given color for each row?

I'm new to web technologies and I'm stuck this this problem: I would like to be able to change the color of a row dynamically.
I tried different things with my knowledge and none worked well. I have a json with information for the table with the color code inside (ex: #D465F2). I wasn't able to find a way to color the entire row in one time dynamically. I can do it with predetermined css but it's not what I need.
The only way it worked is this one:
Template:
<template>
<div>
<p class="title">logs</p>
<b-table
:data="loginfo"
:sticky-header="stickyHeaders"
height="1200px"
:row-class="() => 'relative'"
>
<b-table-column v-slot="props" field="log_id" label="color">
<div class="colored-cell" :style="{ backgroundColor: props.row.color }">
<p>{{ props.row.color }}</p>
</div>
</b-table-column>
</b-table>
</div>
</template>
Script:
<script>
import axios from 'axios'
export default {
props: {
id: Number,
state: Number,
},
data() {
return {
loginfo: [],
stickyHeaders: true,
dateSearchable: false,
}
},
watch: {
id(newId) {
this.newLog()
},
},
methods: {
async newLog() {
await axios
.get('http://127.0.0.2:5001/api/log?sequence=' + this.id)
.then((response) => (this.loginfo = response.data.data))
},
},
}
Exemple of json send to the script:
"data": [
{
"color": "#15986E",
"log_id": 25,
"logged_at": "2022-05-17 16:27:00.015",
},
and this is my css:
.relative {
position: relative;
}
.colored-cell {
position: absolute;
top: 0;
left: 0;
padding: 8px 12px;
}
With this code I color each cell one by one but it makes the table unreadable and all broken. Everything is on top of each other. TableBroken Screen
If anyone have the solution to make the table looks great again/color row dynamically or anything that can help me, another lib which allows me to change the row color dynamically.
Just use a td-attrs prop as documented
<b-table>
:data="loginfo"
:sticky-header="stickyHeaders"
height="1200px"
>
<b-table-column v-slot="props" field="log_id" label="color" :td-attrs="columnTdAttrs">
{{ props.row.color }}
</b-table-column>
</b-table>
</div>
export default {
methods: {
columnTdAttrs(row, column) {
return {
style: {
backgroundColor: row.color
}
}
}
},
}

Have trouble edit my to do list content via Vuex

I have made a to do list and wrote a code to edit my to do list title via VUEX but it doesn't work properly.
I would really apreaciate if someone can help me with it.
SandBox code example
Actually i want to filter the tasks in my view to select the one is clicked and then change its content to hat user types
VUEX state
tasks: [],
VUEX mutations
EDIT_TODO(state, task) {
state.tasks.filter((o) => {
o.id = task.id;
});
}
component
<template>
<div style="background-color: white; color: black; padding: 20px">
<input type="text" v-model="inputText" />
<br />
<button #click="editToDo">update value</button>
{{ task.title }}
</div>
<script>
export default {
props: ["task"],
data() {
return {
inputText: this.task.title,
};
},
methods: {
editToDo() {
console.log("hhh");
this.$store.commit("EDIT_TODO", this.inputText);
},
}
};
</script>
link to github project

Vue Survey Slideshow

I'm working on a survey like this: https://takecareof.com/survey/new using vue. So far I have this:
<template>
<div>
<div class="col-md-4 col-centered">
<div v-on:click="click()" class="survey-button"><slot></slot></div>
</div>
</div>
</template>
<script>
export default {
props: {
answer: {
type: String,
default: null,
}
},
data() {
return {
name: 'taest',
show: true,
}
},
methods: {
click() {
this.$parent.show = false;
//console.log('Question: ' + this.$parent.quesiton);
console.log('Quesiton: ' + this.$parent.getQuestion());
console.log('Answer: ' + this.answer);
console.log('Index: ' + this.$parent.getIndex());
}
}
}
</script>
<template>
<div class="row survey-question" v-show="show">
<h1><slot></slot></h1>
</div>
</template>
<script>
export default {
props: {
question: {
type: String,
default: null,
},
index: {
default: null,
}
},
data() {
return {
name: 'parent',
show: true,
}
},
methods: {
getQuestion() {
return this.question;
},
getIndex() {
return this.index;
}
},
}
</script>
<style>
.survey-question {
padding-top: 8em;
text-align: center;
}
</style>
<div id="app">
<surveyquestion question="how_often" index="0">
Which one best describes you?
<div class="col-md-offset-3">
<surveybutton answer="every_week">I train every week</surveybutton>
<surveybutton answer="some_weeks">I train some weeks</surveybutton>
</div>
</surveyquestion>
<surveyquestion question="where_train" index="1">
Which best describes you?
<surveybutton answer="one_location">I train in one location</surveybutton>
<surveybutton answer="mult_locations">I train in multiple locations</surveybutton>
<surveybutton answer="want_mult_locations">I would like to be able to train in more than one location.</surveybutton>
</surveyquestion>
<surveyquestion question="how_travel" index="2">
Which one best describes you?
<surveybutton answer="between_cities">I travel between cities for work</surveybutton>
<surveybutton answer="interstate">I travel interstate for work</surveybutton>
<surveybutton answer="suburbs">I travel between suburbs for work</surveybutton>
</surveyquestion>
</div>
</div>
I'm not sure how to hide one surveyquestion and show the next one? I wanted to do it like this to make it easy to insert new questions I'm just having trouble hiding and show new ones. In the code, there are two components. The first is the surveybutton and the next is the survey question. I just smashed them together. I'm new to StackOverflow. Any suggestions?
You can act like a wizard in the root element by defining the steps from this.$children and a current_index. Then display only the child component (show = true) at the current_index.
On click, the surveybutton emit a next event which increments the current_index
Fiddle here

VueJS: #click.native.stop = "" possible?

I have several nested components on the page with parents component having #click.native implementation. Therefore when I click on the area occupied by a child component (living inside parent), both click actions executed (parent and all nested children) for example
<products>
<product-details>
<slide-show>
<media-manager>
<modal-dialog>
<product-details>
<slide-show>
<media-manager>
<modal-dialog>
</products>
So I have a list of multiple products, and when I click on "canvas" belonging to modal dialog - I also get #click.native fired on product-details to which modal-dialog belongs. Would be nice to have something like #click.native.stop="code", is this possible?
Right now I have to do this:
#click.native="clickHandler"
and then
methods: {
clickHandler(e) {
e.stopPropagation();
console.log(e);
}
code
<template>
<div class="media-manager">
<div v-if="!getMedia">
<h1>When you're ready please upload a new image</h1>
<a href="#"
class="btn btn--diagonal btn--orange"
#click="upload=true">Upload Here</a>
</div>
<img :src="getMedia.media_url"
#click="upload=true"
v-if="getMedia">
<br>
<a class="arrow-btn"
#click="upload=true"
v-if="getMedia">Add more images</a>
<!-- use the modal component, pass in the prop -->
<ModalDialog
v-if="upload"
#click.native="clickHandler"
#close="upload=false">
<h3 slot="header">Upload Images</h3>
<p slot="body">Hello World</p>
</ModalDialog>
</div>
</template>
<script>
import ModalDialog from '#/components/common/ModalDialog';
export default {
components: {
ModalDialog,
},
props: {
files: {
default: () => [],
type: Array,
},
},
data() {
return {
upload: false,
}
},
computed: {
/**
* Obtain single image from the media array
*/
getMedia() {
const [
media,
] = this.files;
return media;
},
},
methods: {
clickHandler(e) {
e.stopPropagation();
console.log(e);
}
}
};
</script>
<style lang="scss" scoped>
.media-manager img {
max-width: 100%;
height: auto;
}
a {
cursor: pointer;
}
</style>
Did you check the manual? https://v2.vuejs.org/v2/guide/events.html
There is #click.stop="" or #click.stop.prevent=""
So you don't need to use this
methods: {
clickHandler(e) {
e.stopPropagation();
console.log(e);
}
}
In the Vue, modifiers can be chained. So, you are free to use modifiers like this:
#click.native.prevent or #click.stop.prevent
<my-component #click.native.prevent="doSomething"></my-component>
Check events
I had the same problem. I fixed the issue by using following:
<MyComponent #click.native.prevent="myFunction(params)" />