Vue: Switch between result arrays with checkbox - vue.js

I have a computed property that brings back the data "V" into a select dropdown and splits it at the commas and sorts it. All is well.
I also have a check box that allows the user to display records where the date has passed. This info is shown by selecting a checkbox. That works okay too.
So what I'm trying to do is switch between two different functions depending on whether the checkbox is checked.
So what I'd like to say (although the syntax is incorrect) is this:
if (checkboxX === true) const metaVFees = this.resultfilteredResults
else (checkboxX === false) const metaVFees = this.results
and work it into this computed property. Can anyone help with this please?
uniqueSubjects() {
const metaVFees = this.resultfilteredResults // <--- This should switch
.filter((result) => result.metaData && result.metaData.V)
.map((item) => item.metaData.V)
.filter((subject, i, arr) => arr.indexOf(subject) === i);
// Split multiple subjects in strings and store in an array
let subjects = [];
metaVFees.forEach((item) => {
const splitArr = item.split(", ");
subjects = subjects.concat(splitArr);
});
return subjects
.sort()
.filter((subjects, i, arr) => arr.indexOf(subjects) === i);
},

There's several ways to address this, but the easiest is probably JavaScript's Conditional (Ternary) Operator:
[conditional] ? [expression if true] : [expression if false]
It would look like this in your case:
this.metaVFees ? this.resultfilteredResults : this.results
This statement says that if this.metaVFees is true, "execute" this.resultfilteredResults, and if false, then this.results (I say execute because you can use full statements/ expressions with this operator, but we only need single values here).
We can drop the ternary expression straight into your computed property
(I like the parenthesis for clarity, but they aren't actually required since there's a line break after it here):
...
const metaVFees = (this.metaVFees ? this.resultfilteredResults : this.results)
.filter((result) => result.metaData && result.metaData.V)
.map((item) => item.metaData.V)
.filter((subject, i, arr) => arr.indexOf(subject) === i);
...
And here's a short snippet showing this kind of expression in action:
new Vue({
el: '#app',
data() { return {
flag: false,
values1: [1, 2, 3, 4, 5],
values2: [6, 7, 8, 9, 10],
}},
computed: {
ternaryComputed() {
return this.flag ? this.values1 : this.values2
.filter(num => num % 2 == 0); // Filter out odd numbers
},
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<div>{{ `Computed: ${ternaryComputed}` }}</div><br>
<button #click="flag = !flag">Swap Array</button><br><br>
<div>{{`(this.flag ? this.values1 : this.values2) = [${(this.flag ? this.values1 : this.values2)}]`}}</div>
</div>

Related

Vue: Add items to computed property results which do not exist my Array of Objects

I have a computed property that filters the results on the date:
resultfilteredResults() {
const filteredResults = this.results.filter((result) => {
return Date.now() < new Date(result.metaData.E);
});
return filteredResults;
},
That works fine.
Now I have realized that my filteredResults need to contain data that does not necessarily exist in the specific Object.
For example. One bit of data within the object in the Array looks like this:
"C": "Pakistan, Vietnam, Wales, Western Sahara, Yemen, Zambia"
Sometimes "C" will not exist (when this is the case it means it should bring back all available data in all "C" objects within the whole Array. This is because it is not only for specific counties but all countries. I hope that makes sense.
I tried this but it does not work.
resultfilteredResults() {
const undefinedResults = result.metaData;
{
const filteredResults = this.results.filter((result) => {
return Date.now() < new Date(result.metaData.E);
});
if (undefinedResults == "undefined") {
return undefinedResults;
} else {
return filteredResults;
}
}
},
Can anyone help?
There is nothing wrong with the code.
What is not clear is if (undefinedResults == "undefined") {
undefinedResult is a string "undefined"? or just undefined?
Can you try this?
if (undefinedResults == undefined) {

vue js converting a map filter to a variable

const managers = new Map([
['CA1111#domain.com', 'myuser#domain.com'],
['SA5363#domain.com', 'auser#domain.com'],
['EA6373#domain.com', 'theuser#domain.com']
])
Vue.filter('managers', function(value) {
return (value != null ? managers.get(value.substring(0, 10)) : "") || 'Unknown'
})
I am using vue 2.5 and I have a .map filter I am using to point to a specific email address of a user. The issue is- I want to be able to point this in a variable format and I am trying to figure out the best way to achieve this. So the correct email address displays on the screen due to a "filter", but I need this to be pushed to a variable?
{{sillystring | manager}}
You don't need a filter to get that result. And you don't need a filter, if you want your code to be future-proof (Vue3 drops the filters: https://dev.to/chenxeed/awesome-breaking-changes-in-vue-3-if-you-migrate-from-vue-2-3b98)
const managers = new Map([
['CA1111#domain.com', 'myuser#domain.com'],
['SA5363#domain.com', 'auser#domain.com'],
['EA6373#domain.com', 'theuser#domain.com']
])
Vue.filter('managers', function(value) {
return (value != null ? managers.get(value.substring(0, 17)) : "") || 'Unknown'
})
new Vue({
el: "#app",
data: {
managerList: []
},
methods: {
managers(value) {
// putting the values into a list
if (!this.managerList.includes(value)) {
this.managerList = [...new Set([...this.managerList, value])]
}
// returning value like a filter
return (value != null ? managers.get(value.substring(0, 17)) : "") || 'Unknown'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
"managers" filter: {{ "SA5363#domain.com" | managers }}<br />
"managers" method: {{ managers("SA5363#domain.com") }}<br />
"managers" method: {{ managers("EA6373#domain.com") }}<br />
"managerList" attribute: {{ managerList }}
</div>
Actually your example code wouldn't work, as you want a value in a Map with substring of length 10, but the Map's keys are 17 chars long. Maybe this is just because of the example, but I had to correct that to make the snippet work.

Always first filtered selected on Quasar Select

I am using Quasar Framework and using the Q-Select with filter.
I would like to the first filtered option always be already marked, because then if I hit enter, the first will selected.
After some research I found out how to achieve this in a generic way.
The second parameter on the function update received at filterFn is the instance of QSelect itself.
Hence, we can use
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
To keep the focus on the first filtered element, regardless of multiselect or not.
The final code is something like
filterFn(val, update) {
update(
() => {
const needle = val.toLocaleLowerCase();
this.selectOptions = this.qSelectOptions.filter(v => v.toLocaleLowerCase().indexOf(needle) > -1);
},
ref => {
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
});
}
There is one option to achieve this is set model value in the filter method if filtered options length is >0.
filterFn (val, update, abort) {
update(() => {
const needle = val.toLowerCase()
this.options = stringOptions.filter(v => v.toLowerCase().indexOf(needle) > -1)
if(this.options.length>0 && this.model!=''){
this.model = this.options[0];
}
})
}
Codepen - https://codepen.io/Pratik__007/pen/QWjYoNo

How to loop through an array containing objects and do comparison

I am using ionic 4. I get the result from the API then get the result show like this
[
{"name":John,"age":20},
{"name":Peter,"age":35},
{"name":Alex,"age":15}
]
But I want to get the name only to check whether have same name with my condition or not. But I cannot straight a way get the result from the API, I need to hard code to do comparison. Here is my code:
this.http.get(SERVER_URL).subscribe((res) => {
const data = [
{ name: John, age: 21 },
{ name: Thomas, age: 25 },
];
const ppl= data.find(people=> people.name === 'alex');
console.log(ppl);
});
So, My first question is How to get the name from the API directly, not like now I hard code the result from API. My Second Question is when I do comparison I want to show the result 'already exist' or 'can use this name'. Because if I write my code like this I will get the error Type 'void' is not assignable to type 'boolean':
const ppl= data.find((people)=> {
if(people.name === 'alex') {
this.text = 'already exist'
} else {
this.text = 'can use this name'
}});
console.log(ppl);
Anyone can help me? Thank you very much
Instead of defining data, use the contents of the response; res will have the exact same contents that you are declaring in data.
this.http.get(SERVER_URL).subscribe(res => {
// If successful, res is an array with user data like the following
// [
// {name: "John", age: 21},
// {name: "Thomas", age: 25},
// ...
// ]
if (res.find(user => user.name === 'alex')) {
console.log ('Username has been taken');
} else {
console.log('Username is available');
}
});
Taken from the MDN docs on Array.prototype.find():
The find() method returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
In that case
res.find(user => user.name === 'alex')
will return a user object if any of the usernames match alex, or undefined if none of the user.name attributes match alex.
undefined evaluates to false and a user object evaluates to true in the conditional.
Keep in mind that you are comparing strings with ===, so, for example, Alex will not match alex, if you want to look into other ways to compare strings, have a look at this question.
You also might want to handle errors, how you handle them is up to you, and it will depend on the response, but you can access the error inside your subscribe like this:
this.http.get(SERVER_URL).subscribe(res => {
if (res.find(user => user.name === 'alex')) {
console.log ('Username has been taken');
} else {
console.log('Username is available');
}
}, error => {
console.log(error);
}, () => {
// There is also a 'complete' handler that triggers in both cases
});
Edit. API returns Object not array
If your API returns an Object instead of an array like in your question, you can still iterate over the properties
this.http.get(SERVER_URL).subscribe(res => {
// If successful, res is an array with user data like the following
// {
// key1: {name: "John", age: 21},
// key2: {name: "Thomas", age: 25},
// ...
// }
let match = false;
Object.keys(res).forEach(key => {
if (res[key].name === 'alex') {
match = true;
}
});
if (match) {
console.log ('Username has been taken');
} else {
console.log('Username is available');
}
});
Instead of Object.keys() you could use Object.values() to get an array with user objects, then use find() as before, but that seems less efficient, something like this:
if (Object.values(res).find(user => user.name === 'alex')) {
console.log ('Username has been taken');
} else {
console.log('Username is available');
}

Lodash differenceBy alternative

I am trying to find a way to differentiate between 2 object literals by a property from each.
I can get this working by using 2 ._forEach()
_.forEach(forms, form => {
_.forEach(this.sections, section => {
if(form.section === section.name){
section.inProgress = true;
}
});
});
However this does not seem ideal. I have tried with the _.differenceBy
_.differenceBy(forms, this.sections, 'x');
But I cant differentiate by the property name as the "name" that i want to check by is name in one of the arrays and section in the other.
I want to use something like
_.differenceBy(forms, this.sections, 'section' === 'name');
It there something in lodash for this?
You can use _.differenceWith() with a comparator that refers to a specified object property in each array:
var forms = [{ 'name': 'somethingA' }, { 'name': 'somethingB' }];
var sections = [{ section: 'somethingB' }];
var result = _.differenceWith(forms, sections, function(arrValue, othValue) {
return arrValue.name === othValue.section;
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>