I am making a simple filter and In this filter I am pushing query parameters to URL and appending them. If user choose a particular option, I want to modify the query string and I need the help here.
My URL is like this : http://app.test/home?preference=onsite&place=Aus&place=Mus
and if user choose wfh instead of onsite for preference I want to remove place from URL and want this URL: http://app.test/home?preference=wfh
my code:
<template>
<div>
<div class="mt-2">
</div>
<div class="mt-2" v-if=" this.$route.query.preference == 'onsite'">
<label>Available for work</label>
<div class="form-control" >
<input type="text">
<div class="options" style="max-height:140px;overflow:scroll">
<ul class="" style="max-height:40px;">
<li v-for="place in places" :key="place.id">
<input type="checkbox" v-model="filter.place"
:value="place.name">{{ place.name }}
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
places: [
{
id: 1,
name: "Aus",
},
{
id: 2,
name: "Mus",
},
],
filter: {
preference: this.$route.query.preference,
place:[],
},
};
},
watch: {
filter: {
handler() {
const query = this.filter
this.$router.push({
query: query,
});
},
deep: true,
},
},
};
</script>
I wrote below code to check if preference is wfh and update URL but this is not working
if (this.$route.query.preference == 'wfh') {
this.$route.query.place='';
this.$router.replace({ query: query });
}
You can extract the rest of the queries and replace with them, it same like delete place query.
if (this.$route.query.preference == 'wfh') {
const { place, ...query} = this.$route.query;
this.$router.replace({ query: query });
}
Related
this is the DIV where I am including the component responsible to fetch the data from API:
The component has params for filtering through the data and identifying the user but it doesn't return the specific user even when I use params and I am adding in the params of each div the user_id. The picture of this user isn't loading somehow.
<div class="gold_container_below">
<h4 class="gold_subtitle" v-html="$t('awards_gold_type')"></h4>
<div class="special_container">
<img src="/img/event/cheersupports/2022/appreciation/awards/gold_left.svg" class="gold_left"/> <div class="userdata_icon">
<LiverListArea1
ref="liver_list"
page_records="1"
:params="params0"/>
<!-- <img src="/img/event/cheersupports/2022/appreciation/awards/gengoro.png"/> --> </div>
export default {
props: ["lang", "params"],
i18n,
components: {
LiverListArea1,
},
data() {
return {
params0: {
user_id: 1616,
},
params1: {
user_id: 5754,
},
params2: {
user_id: 298,
},
params3: {
user_id: 4655,
},
params4: {
user_id: 524,
},
params5: {
liver_id: 1807,
},
<template>
<div class="loadercontainer1 default_font">
<ul class="account_list">
<li
class="account_list_item finger"
v-for="(liver, key) in livers"
:key="key"
v-on:click="click_item(liver)"
>
<div class="account">
<img :src="liver.icon_path" alt="まごころプロジェクト" />
</div>
</li>
</ul>
<LiverSearchFunction
ref="liver_search_function"
:header="header"
:params="params"
:page_records="page_records"
/>
</div>
</template>
The code above is the component in charge of filtering though the data from the component LiverSearchFunction.
I am only getting the user icon image from the loop not from the user_id from params. I am not sure how get that specific information....
I'm looking solution for how to auto fill input in vue js. I have a form which include of input type text, select dropdown, quantity, etc. I want when the select dropdown is selected, then the quantity of vCPU, vRAM, and Storage Capacity will be automatically filled with the value according to the selected Server Flavor.
I tried to choose Flavor Server with Flavor 1 options, vCPU should immediately be filled with a value 4, vRAM should be filled with a value 2, and storage capacity should be filled with a value 10. But the quantity does not appear.
But in the price estimation the numbers are correct, namely vCPU (4), vRAM (2), Storage Capacity (10)
I'm confused, to put the if conditional in the <base-quantity> at the #updateQuantity custom event or in v-if attribute. Is there anyone here that can help me solve this problem?
The full source code is in this codesandbox => https://codesandbox.io/s/suspicious-almeida-rjyy9
Lite.vue
<template>
<div class="container">
<h2 class="font-size-26 txt-secondary">Deka Flexi</h2>
<div class="row">
<div class="col-12">
<form #submit.prevent="submitFormLite">
<div class="form-group form-group--border">
<label class="font-size-22 txt-secondary txt-semibold">Commitment Type</label>
<select name="commitment" id="" class="select-custom" v-model="selectedCommitTypeLite">
<option v-for="ctl in commitTypeLite" :key="ctl.name" :value="ctl.value">{{ ctl.name }}</option>
</select>
</div>
<div class="form-group form-group--border">
<label class="font-size-22 txt-secondary txt-semibold">Server Name</label>
<input type="text" name="name" class="custom-input" v-model="serverNameLite" />
</div>
<div class="form-group form-group--border">
<label class="font-size-22 txt-secondary txt-semibold">Server Flavor</label>
<select name="storage-type" id="" class="select-custom" v-model="selectedServerFlavorLite">
<option v-for="sfl in serverFlavorLite" :key="sfl.name" :value="sfl.value">{{ sfl.name }}</option>
</select>
</div>
<h6 class="font-size-22 txt-secondary txt-semibold">
Components
</h6>
<div class="row form-group--border">
<div class="col-md-6">
<div class="form-group text-center">
<div class="font-size-18 txt-secondary">vCPU (GHz)</div>
<base-quantity #updateQuantity="updateCpuLite"></base-quantity>
</div>
</div>
<div class="col-md-6">
<div class="form-group text-center">
<div class="font-size-18 txt-secondary">vRAM (GB)</div>
<base-quantity #updateQuantity="updateRamLite"></base-quantity>
</div>
</div>
<div class="col-md-6">
<div class="form-group text-center">
<label class="font-size-18 txt-secondary">Storage Type</label>
<select name="storage-type" id="" class="select-custom" v-model="selectedStorageTypeLite">
<option v-for="stl in storageTypeLite" :key="stl.name" :value="stl.value">{{ stl.name }}</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group text-center">
<div class="font-size-18 txt-secondary">Storage Capacity (GB)</div>
<base-quantity #updateQuantity="updateCapacityLite" v-model="updateCapacityLite"></base-quantity>
</div>
</div>
</div>
<div class="row pt-4">
<div class="col-md-6">
<div class="form-group text-center">
<label class="font-size-18 txt-secondary">Public IP</label>
<select name="public-ip" id="" class="select-custom" v-model="selectedPublicIpLite">
<option v-for="pil in publicIpLite" :key="pil.name" :value="pil.value">{{ pil.name }}</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group text-center">
<label class="font-size-18 txt-secondary">OS Type</label>
<select name="os-lite" id="" class="select-custom" v-model="selectedOsLite">
<option v-for="ol in osLite" :key="ol.name" :value="ol.value">{{ ol.name }}</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group text-center">
<div class="font-size-18 txt-secondary">Quantity</div>
<base-quantity #updateQuantity="updateQuantityLite"></base-quantity>
</div>
</div>
</div>
<div class="form-group mt-4 text-center">
<button class="button button__add" #click="addToCart">Submit</button>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
import BaseQuantity from "../base/BaseQuantity.vue";
export default {
components: {
BaseQuantity,
},
data() {
return {
serverNameLite: '',
storageTypeLite: [
{
name: "Storage Type 1",
value: 100
},
{
name: "Storage Type 2",
value: 120
}
],
publicIpLite: [
{
name: "Yes",
value: 120
},
{
name: "No",
value: 20
}
],
osLite: [
{
name: "OS 1",
value: 80
},
{
name: "OS 2",
value: 100
},
{
name: "OS 3",
value: 120
}
],
serverFlavorLite: [
{
name: "Flavor 1",
value: "flavor-1"
},
{
name: "Flavor 2",
value: "flavor-2"
},
{
name: "Flavor 3",
value: "flavor-3"
}
],
commitTypeLite: [
{
name: "Commitment Type 1",
value: 80
},
{
name: "Commitment Type 2",
value: 100
},
{
name: "Commitment Type 3",
value: 120
}
],
selectedStorageTypeLite: "",
selectedPublicIpLite: "",
selectedOsLite: "",
selectedCommitTypeLite: "",
selectedServerFlavorLite:""
};
},
watch: {
serverNameLite: function() {
this.$store.commit('setServerNameLite', this.serverNameLite);
},
selectedStorageTypeLite: function() {
let storageTypeLite = this.storageTypeLite.find((storageTypeLite) => storageTypeLite.value == this.selectedStorageTypeLite);
this.$store.commit('setStorageTypeLite', storageTypeLite);
},
selectedPublicIpLite: function() {
let publicIpLite = this.publicIpLite.find((publicIpLite) => publicIpLite.value == this.selectedPublicIpLite);
this.$store.commit('setPublicIpLite', publicIpLite);
console.log(publicIpLite);
},
selectedOsLite: function() {
let osLite = this.osLite.find((osLite) => osLite.value == this.selectedOsLite);
this.$store.commit('setOsLite', osLite);
},
selectedCommitTypeLite: function() {
let commitTypeLite = this.commitTypeLite.find((commitTypeLite) => commitTypeLite.value == this.selectedCommitTypeLite);
this.$store.commit('setCommitTypeLite', commitTypeLite);
},
selectedServerFlavorLite: function() {
let serverFlavorLite = this.serverFlavorLite.find((serverFlavorLite) => serverFlavorLite.value == this.selectedServerFlavorLite);
this.$store.commit('setServerFlavorLite', serverFlavorLite);
if(this.selectedServerFlavorLite == "flavor-1"){
this.updateCpuLite(4);
this.updateRamLite(2);
this.updateCapacityLite(10);
}
},
},
methods: {
async addToCart() {
let isLiteEmpty = await this.$store.dispatch('isLiteEmpty');
if(!isLiteEmpty) {
this.$store.commit('calculateLiteCost');
this.$store.commit('setLite', this.$store.getters.getLiteState);
this.$store.commit('calculatePrice');
}
},
updateCpuLite(val) {
this.$store.commit('setCpuLite', {qty: val, value: 100});
console.log(val);
},
updateRamLite(val) {
this.$store.commit('setRamLite', {qty: val, value: 100});
console.log(val);
},
updateCapacityLite(val) {
this.$store.commit('setCapacityLite', {qty: val, value: 100});
console.log(val);
},
updateQuantityLite(val) {
this.$store.commit('setQuantityLite', {qty: val, value: 100});
console.log(val);
},
},
};
</script>
selectedServerFlavorLite: function() {
let serverFlavorLite = this.serverFlavorLite.find((serverFlavorLite) => serverFlavorLite.value == this.selectedServerFlavorLite);
this.$store.commit('setServerFlavorLite', serverFlavorLite);
if(this.selectedServerFlavorLite == "flavor-1"){
this.updateCpuLite(4);
this.updateRamLite(2);
this.updateCapacityLite(10);
}
},
BaseQuantity.vue
<template>
<div class="quantity" :class="disabled ? 'quantity__untoggle' : 'quantity__toggle'">
<button type="button" #click="decrement" class="btn quantity__decrement" :disabled="disabled">-</button>
<input type="text" class="quantity__value" :value="quantity" :disabled="disabled" readonly>
<button type="button" #click="increment" class="btn quantity__increment" :disabled="disabled">+</button>
</div>
</template>
<script>
export default {
props : ['disabled'],
data(){
return{
quantity: null
}
},
watch:{
quantity :function(val){
this.$emit('updateQuantity',val);
}
},
methods :{
increment () {
this.quantity++
},
decrement () {
if(this.quantity === 0) {
alert('Negative quantity not allowed')
} else {
this.quantity--
}
}
}
}
</script>
There are multiple ways, but it's all based on how your data is stored and connected through components.
Let's start from BaseQuantity.vue:
data() {
return {
quantity: 0 // you have a local saved state of the quantity
}
},
methods: {
increment() {
this.quantity++ // when user hits something, you increment the LOCAL state
},
}
watch: {
quantity: function(val) { // when the LOCAL value updates
this.$emit('updateQuantity', val); // you emit event it has been updated
}
}
Basically each of your Base Quantity components defines its state (starting from 0), and then tracks its own actions that update that state.
You use those components like
<base-quantity #updateQuantity="updateServer"
And the method calls Vuex to store the new value (gotten from the component, equals to it's internal state):
updateServer(val) {
this.$store.commit('setServer', {qty: val, value: 100});
}
Your first issue is that each of those Base Quantity components define their own initial state, which is internal and separate. Currently, there's no real way to tell any of those "your value is X", it's quite the opposite - they tell the parent "I've updated my value".
In order to do so, you must somehow set the initial value. The very basic approach would be to pass the initial value to the component:
props : ['disabled', 'initialValue'],
data(){
return {
quantity: this.initialValue
}
},
Problem two now is that you don't only need an initial value, you need to set the value from outside, whenever the user selects a dropdown option. But you would also like to keep track of manual updates on the component. So you need a two-directional binding of the values (set and update). That's where the v-model comes in handy. Here's a good article explaining how it worked before, and how it works now: https://v3-migration.vuejs.org/breaking-changes/v-model.html#overview Basically you'll use it like that:
<base-quantity v-model="serverQuantity" />
<!-- would be shorthand for: -->
<base-quantity
:modelValue="serverQuantity"
#update:modelValue="serverQuantity= $event"
/>
You don't store the data in your Calculator component - you store it in Vuex. Now this is the part where you have a lot of solutions and you need to be careful how you design your data flow. I would go with the simplest one:
Use store getters to instruct Base Quantity what its value is: <base-quantity :value="$store.getters.serverQuantity" />. This is a reactive property that would be updated when the store updates its value for server quantity. If you don't have getters you could use the state instead, but that's not suggested.
Remove local variable for quantity, and just use the passed property: <input :value="value" />
Upon update (clicking on a button), emit an event with the new value without updating it locally: increment() { this.$emit('updateQuantity', this.value + 1)
In your handler, commit the update as of now
In order to handle dropdown selection, if you use the approach described above, you just need to wait for the user input (dropdown selection) and populate the store with all the needed fields. Since they are passed to each component, the value would be automatically populated:
watch: {
selectedPackage: function() {
let pack = this.storagePackage.find((pack) => pack.value == this.selectedPackage);
this.$store.commit('setPackage', pack);
// here you should somehow map the pack to the values you'd like to populate
// let's say package "One" (value: 30) means you'd have 8 vRAM, then:
this.updateRam(package.ram);
// this would call this.$store.commit('setRam', { qty: 8, value: 100 });
this.updateCapacity(100);
this.updateCpu(5);
// all the other fields you'd like to update, with the specific values this PACK has (I haven't seen any map for plan -> values)
},
}
p.s. I'm not entirely sure why you store qty: val, value: 100 everywhere, but probably you have some reason about it.
With this approach you'll have a single source of truth about the data. And separate components that just say "I want this value (whatever it is) to be either incremented or decremented". So the component is completely isolated of any knowing of the real business logic of modification and storage, as well as the property name.
The parent is the one that handles data both ways - first it sends it to each component, and second - it handles the user actions, which are then commited to a Vuex store (single point of truth).
You can set values using the v-model but this is a different scenario where the values are based on the selected events. So I reached this solution where you can create a function that sets the values in custom mode
Try using this:
setValues: function () {
this.specifications === this.specifications[1]
? (this.os = this.os[0].name)
: (this.os = '');
You can pass in other Databases, StorageType, Firewall values as well.
I am attempting to do a SPA using Vue.js but unfortunately I know almost nothing about it, I followed a tutorial and got something up and running. This should hopefully be relatively simple!
I'm trying to create a simple page that:
Does a REST API call and pulls some JSON
A list with links of a particular field in the list of results is displayed on the left side of the screen
(I've managed until here)
Now I would like to be able to click on one of the links and see on the right side of the screen the value of another field for the same record.
For instance, suppose my JSON is:
{
"jokes":{
[
"setup":"setup1",
"punchline":"punchline1"
],
[
"setup":"setup2",
"punchline":"punchline2"
],
[
"setup":"setup3",
"punchline":"punchline3"
]
}
}
So in my screen I would see:
setup1
setup2
setup3
So if I click in setup1 I see punchline1, setup2 displays punchline2 and so on.
Here is my code - I'm basically trying to display the punchline in the moduleinfo div. I realise the current solution does not work. I've been searching but can't find any similar examples. Any pointers would be greatly appreciated.
<template>
<div class="home">
<div class="module-list">
<input type="text" v-model.trim="search" placeholder="Search"/>
<div>
<ul>
<li class="modules" v-for="value in modulesList" :key="value.id">
{{ value.setup }}
</li>
</ul>
</div>
</div>
<div class="moduleinfo">
<h2>Module info</h2>
<!-- <p>{{ value.punchline }}</p> -->
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Home',
data: function(){
return {
jokes: [],
search : ""
}
},
mounted() {
this.getModules();
},
methods: {
getModules() {
var self = this
const options = {
method: 'GET',
url: 'https://dad-jokes.p.rapidapi.com/joke/search',
params: {term: 'car'},
headers: {
'x-rapidapi-key': '...',
'x-rapidapi-host': 'dad-jokes.p.rapidapi.com'
}
};
axios.request(options)
.then(response => {
self.jokes = response.data;
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
}
},
computed: {
modulesList: function () {
var jokes = this.jokes.body;
var search = this.search;
if (search){
jokes = jokes.filter(function(value){
if(value.setup.toLowerCase().includes(search.toLowerCase())) {
return jokes;
}
})
}
return jokes;
}
},
};
</script>
Thanks!
I was building a sample Single File Component in my Vue 2 CLI app, and when I came back to post it, Ryoko had already answered the question with the same approach that I recommend, adding a new property to track showing the punchline.
Since I already built it, I figured that I might as well post my component, which does change the layout, using a table instead of a list, but the functionality works.
<template>
<div class="joke-list">
<div class="row">
<div class="col-md-6">
<table class="table table-bordered">
<thead>
<tr>
<th>SETUP</th>
<th>PUNCHLINE</th>
</tr>
</thead>
<tbody>
<tr v-for="(joke, index) in jokes" :key="index">
<td>
{{ joke.setup }}
</td>
<td>
<span v-if="joke.showPunchline">{{ joke.punchline }}</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
jokes: [
{
setup: "setup1",
punchline: "punchline1"
},
{
setup: "setup2",
punchline: "punchline2"
},
{
setup: "setup3",
punchline: "punchline3"
}
]
}
},
methods: {
getPunchline(index) {
this.jokes[index].showPunchline = true;
},
addPropertyToJokes() {
// New property must be reactive
this.jokes.forEach( joke => this.$set(joke, 'showPunchline', false) );
}
},
mounted() {
this.addPropertyToJokes();
}
}
</script>
You can add a new property inside the data object and then make a new method to set it accordingly when you click the <a> tag. Have a look at the code below, it was a copy of your current solution, edited & simplified to show the addition that I made to make it easier for you to find it.
The select method will insert the object of the clicked joke to the selectedJoke so you can render it below the Module Info.
Because it's defaults to null, and it might be null or undefined, you have to add v-if to the attribute to check wether there is a value or not so you don't get error on the console.
<template>
<div class="home">
<div class="module-list">
<input type="text" v-model.trim="search" placeholder="Search"/>
<div>
<ul>
<li class="modules" v-for="value in modulesList" :key="value.id">
{{ value.setup }}
</li>
</ul>
</div>
</div>
<div class="moduleinfo">
<h2>Module info</h2>
<p v-if="selectedJoke">{{ selectedJoke.punchline }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Home',
data: function(){
return {
jokes: [],
search : "",
selectedJoke: null,
}
},
methods: {
select(joke) {
this.selectedJoke = joke;
},
},
};
</script>
I am using VueJS to show a list of articles. Then I have some filters which use checkboxes and a computed property to filter the list of articles displayed, based on what tag is selected.
However, I would like to add a 'All' tag which would clear any applied filter tags that were selected previously (Sports/Schools). Is this possible? If so, what do I need to do? Any help welcome.
var app = new Vue({
el: '#app',
data: {
tags: ['all', 'sports', 'schools'],
articles: [
{tags: ['sports'], name: 'Why sports is fun'},
{tags: ['sports', 'schools'], name: 'How sports helps schools'},
{tags: ['schools'], name: 'Why students attend school'}
],
selectedTags: []
},
computed: {
activeArticles: function() {
if(this.selectedTags.length == 0) return this.articles;
var activeArticles = [];
var filters = this.selectedTags;
this.articles.forEach(function(article) {
function articleContainsFilter(filter) {
return article.tags.indexOf(filter) != -1;
}
if(filters.every(articleContainsFilter)) {
activeArticles.push(article);
}
});
return activeArticles;
}
}
});
Then my HTML is as follows;
<div id="app">
<label for="showAllArticles">All</label>
<input type="checkbox" value="showAllArticles">
<div v-for="tag in tags">
<input type="checkbox" value="{{ tag }}" v-model="selectedTags" id="tag-{{ tag }}">
<label for="tag-{{ tag }}">{{ tag }}</label>
</div>
<p v-show="selectedTags.length != 0">
Filters: <span v-for="tag in selectedTags" class="label">{{ tag }}</span>
</p>
<ul>
<li v-for="article in activeArticles">{{ article.name }}</li>
</ul>
</div>
Change activeArticles to return all articles if all tag selected
activeArticles: function() {
// if statement edited
if(this.selectedTags.length == 0 || this.selectedTags.includes('all') )return this.articles;
var activeArticles = [];
var filters = this.selectedTags;
this.articles.forEach(function(article) {
function articleContainsFilter(filter) {
return article.tags.indexOf(filter) != -1;
}
if(filters.every(articleContainsFilter)) {
activeArticles.push(article);
}
});
return activeArticles;
}
Just add
methods: {
resetFilters(e) {
if (e.target.checked) {
this.selectedTags = []
}
}
}
And apply onClick={resetFilters} listener to the 'All' checkbox
The computed activeArticles will update, because one of its dependents (selectedTags) updated.
When the user selects a machine, I get the id of the machine. From that id I need to get the make and model of the machine.
<ul class="list-unstyled">
<li>
<div v-for="dosimeter in dosimeters">
<label>
<input type="radio" name="optDosimeter" v-model="dosimeter_id" :value="dosimeter.id" v-on:click="dosimeter_select">{{dosimeter.nickname}}
</label>
</div>
</li>
</ul>
Vue.js
export default {
data: function() {
return {
dosimeters:[],
dosimeter_id:''
}
},
mounted(){
axios.get('/dosimeters').then((response) => {
this.dosimeters=response.data;
});
},
methods: {
dosimeter_select(){
not sure what to put here
}
}
}
i think you should do something like :
dosimeter_select(){
let found= this.dosimeters.find(d=>{
return d.id==this.dosimeter_id
});
console.log(found.make);
console.log(found.model);
}
try this
dosimeter_select()
{
let machine = this.dosimeters.find(dosimeter => dosimeters.id===this.dosimeter_id);
// now you have the machine object
}
it should work:
new Vue({
el: "#app",
data: {
dosimeters:[
{ id: 1, name: 'foo' },
{ id: 2, name: 'bar' }
]
},
methods: {
dosimeterSelected (selectedDosimeter) {
console.log(`i doing something with dosimeter.id: ${selectedDosimeter.id}`)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul class="list-unstyled">
<li v-for="dosimeter in dosimeters">
<div>
<label>
<input type="radio" name="optDosimeter" :value="dosimeter.name" v-on:click="dosimeterSelected(dosimeter)">{{dosimeter.name}}
</label>
</div>
</li>
</ul>
</div>
I made some changes now it works.
I used the suggestion from Boussadjra Brahim:
dosimeter_select(){
let found= this.dosimeters.find(d=>{
return d.id==this.dosimeter_id
});
console.log(found.make);
console.log(found.model);
}
and rather than using radio buttons I made it a select drop down. Also, rather than triggering the method with #click, I used #change.