Combine Search and checkbox filters in Vue js - search

I have to filter a list using a Search input field and als some Checkboxes (filter on a category).
I have both functionalities working independently.
The Search field
computed: {
getfilteredData() {
return this.experiences.filter(experience =>
experience.name.toLowerCase().includes(this.search.toLowerCase()) ||
experience.category.toLowerCase().includes(this.search.toLowerCase()
)
)
}
},
The Checkboxes
computed: {
getfilteredData() {
if (!this.checkedCategories.length)
return this.experiences
return this.experiences.filter(experience =>
this.checkedCategories.includes(experience.category))
}
},
How do I combine those filters? So they are working simultaneously?

combining both filters in succession will filter both as an AND statement
getfilteredData() {
return this.experiences.filter(experience =>
experience.name.toLowerCase().includes(this.search.toLowerCase()) ||
experience.category.toLowerCase().includes(this.search.toLowerCase()
)
).filter(experience =>
// if there are no checkboxes checked. all values will pass otherwise the category must be included
!this.checkedCategories.length || this.checkedCategories.includes(experience.category)
)
}
otherwise, you could combine them in one filter with (firstCondition || secondCondition) with the same logic you use above.
I saw your other question that got closed Write my Javascript more cleaner in my Vue js search functionality
where I think you could rewrite your function like this
experience => {
let reg = new RegExp(this.search, 'gi')
return reg.test(`${experience.name} ${experience.category}`)
}
using g means that your string can be in any position, but you must reconstruct your regex on each test otherwise you can end up with issues found here
Why am I seeing inconsistent JavaScript logic behavior looping with an alert() vs. without it?
using i means it will ignore casing so you don't need to worry about using toLowerCase()
thus your filter can be written like this in one statement
experience => {
let reg = new RegExp(this.search, 'gi')
// search input matches AND the checkbox matches
return reg.test(`${experience.name} ${experience.category}`) && (!this.checkedCategories.length || this.checkedCategories.includes(experience.category))
// search input matches OR the checkbox matches
//return reg.test(`${experience.name} ${experience.category}`) || (!this.checkedCategories.length || this.checkedCategories.includes(experience.category))
}

Related

nodejs map return nothing when if statement true

so i have the following code
data.push(commands.map(
command => {
if (!command.devOnly) { return command.name; } // first condition
if (command.devOnly && message.author.id != '3251268789058714880') {} // second condition
},
).join('\n'));
if the second condition is true it returns null but then when I run console.log(data) it has a blank line for all the commands where the second condition is true.
Is there a way to stop the second condition from returning anything, and not leaving the blank line
.map() is a 1-for-1 transformation so the output array will have EXACTLY the same number of elements in it as the input array. If you don't return anything, that element in the array will have an undefined value (which is the return value when you don't actively return something).
To transform the array and eliminate some elements, you cannot use .map(). You can either do .filter().map() where you first filter out the items you don't want and then map the others or you can use a regular for loop and just push the items into output array that you want to keep using either a regular for loop iteration or a .reduce() or .forEach() iteration.
One example:
const results = commands.filter(command => !command.devOnly).map(command => command.name);
console.log(results);
const results = [];
for (let command of commands) {
if (!command.devOnly) results.push(command.name);
}
console.log(results);
Note, your second condition doesn't do anything at all in your code example so I wasn't sure how to account for that in these examples.
P.S. I've often wished Javascript had a .filterMap() feature that let you return undefined to leave that value out of the result - otherwise work like .map(). But, it doesn't have that feature built in. You could build your own.
Per your comments, you can filter on two conditions like this:
const results = commands
.filter(command => !command.devOnly || message.author.id === '3251268789058714880')
.map(command => command.name);
console.log(results);
you could use Array.reduce
commands.reduce((prev,command)=>{
if (!command.devOnly)
return [...prev,command.name]
// this if, is useless but shows that you can use more conditions.
if (command.devOnly && message.author.id != '3251268789058714880')
return prev
// add more conditions as you need here
return prev
},[])
another options could be by doing map then filter the undefined values, or use for-loop
like jfriend00 explained in his answer. the filterMap() he wished could be implemented with Array.reduce

If statements not working with JSON array

I have a JSON file of 2 discord client IDs `{
{
"premium": [
"a random string of numbers that is a client id",
"a random string of numbers that is a client id"
]
}
I have tried to access these client IDs to do things in the program using a for loop + if statement:
for(i in premium.premium){
if(premium.premium[i] === msg.author.id){
//do some stuff
}else{
//do some stuff
When the program is ran, it runs the for loop and goes to the else first and runs the code in there (not supposed to happen), then runs the code in the if twice. But there are only 2 client IDs and the for loop has ran 3 times, and the first time it runs it goes instantly to the else even though the person who sent the message has their client ID in the JSON file.
How can I fix this? Any help is greatly appreciated.
You may want to add a return statement within your for loop. Otherwise, the loop will continue running until a condition has been met, or it has nothing else to loop over. See the documentation on for loops here.
For example, here it is without return statements:
const json = {
"premium": [
"aaa-1",
"bbb-1"
]
}
for (i in json.premium) {
if (json.premium[i] === "aaa-1") {
console.log("this is aaa-1!!!!")
} else {
console.log("this is not what you're looking for-1...")
}
}
And here it is with return statements:
const json = {
"premium": [
"aaa-2",
"bbb-2"
]
}
function loopOverJson() {
for (i in json.premium) {
if (json.premium[i] === "aaa-2") {
console.log("this is aaa-2!!!!")
return
} else {
console.log("this is not what you're looking for-2...")
return
}
}
}
loopOverJson()
Note: without wrapping the above in a function, the console will show: "Syntax Error: Illegal return statement."
for(i in premium.premium){
if(premium.premium[i] === msg.author.id){
//do some stuff
} else{
//do some stuff
}
}
1) It will loop through all your premium.premium entries. If there are 3 entries it will execute three times. You could use a break statement if you want to exit the loop once a match is found.
2) You should check the type of your msg.author.id. Since you are using the strict comparison operator === it will evaluate to false if your msg.author.id is an integer since you are comparing to a string (based on your provided json).
Use implicit casting: if (premium.premium[i] == msg.author.id)
Use explicit casting: if (premium.premium[i] === String(msg.author.id))
The really fun and easy way to solve problems like this is to use the built-in Array methods like map, reduce or filter. Then you don't have to worry about your iterator values.
eg.
const doSomethingAuthorRelated = (el) => console.log(el, 'whoohoo!');
const authors = premiums
.filter((el) => el === msg.author.id)
.map(doSomethingAuthorRelated);
As John Lonowski points out in the comment link, using for ... in for JavaScript arrays is not reliable, because its designed to iterate over Object properties, so you can't be really sure what its iterating on, unless you've clearly defined the data and are working in an environment where you know no other library has mucked with the Array object.

how to test effects with filter of ngrx in Angular 4 5 with Jasmine and Marble

I am now facing a problem. not sure how to test if the action$ with filter operator.
I am also trying to follow the rules of https://github.com/vsavkin/testing_ngrx_effects/tree/309b84883c2709a34ab98b696398332d33c2104f
make it simple, I just set the filter if the length of array is 0 return true.
for example:
loadDatas$: Observable<Action> = this.actions$.ofType(LOAD_DATAS_ACTION).pipe(
withLatestFrom(this.store.select(getDatas), (action, datas) =>datas),
filter(data => !data.length),
switchMap(() => {
console.log(‘run api’);
return this.dataApi.find().pipe(
map((datas: Data[]) => new DatasLoadedAction(datas))
………
…..
so I try to write two test cases, one is
expect(effects.loadDatas$).toBeObservable(expected);
when filter return true.
but I don’t know how to test if the filter return false.
Do you have any suggestion for this ? thank a lot
You expect the effect to not return a new action, so you can compare it with an 'empty' observable:
const expected = cold('----');
expect(effects.loadDatas$).toBeObservable(expected);

protractor: filter until finding first valid element

I am doing e2e testing on a site that contains a table which I need to iterate "until" finding one that doesn't fail when I click on it.
I tried it using filter and it is working:
this.selectValidRow = function () {
return Rows.filter(function (row, idx) {
row.click();
showRowPage.click();
return errorMessage.isDisplayed().then(function (displayed) {
if (!displayed) {
rowsPage.click(); // go back to rows Page, all the rows
return true;
}
});
}).first().click();
};
The problem here is that it is iterating all available rows, and I only need the first one that is valid (that doesn't show an errorMessage).
The problem with my current approach is that it is taking too long, as my current table could contain hundreds of rows.
Is it possible to filter (or a different method) and stop iterating when first valid occurrence appears?, or could someone come up with a better approach?
If you prefer a non-protractor approach of handling this situation, I would suggest async.whilst. async is a very popular module and its highly likely that your application is using it. I wrote below code here in the editor, but it should work, you can customize it based on your needs. Hopefully you get an idea of what I'm doing here.
var found = false, count = 0;
async.whilst(function iterator() {
return !found && count < Rows.length;
}, function search(callback) {
Rows[count].click();
showRowPage.click();
errorMessage.isDisplayed().then(function (displayed) {
if (!displayed) {
rowsPage.click(); // go back to rows Page, all the rows
found = true; //break the loop
callback(null, Rows[count]); //all good, lets get out of here
} else {
count = count + 1;
callback(null); //continue looking
}
});
}, function aboutToExit(err, rowIwant) {
if(err) {
//if search sent an error here;
}
if(!found) {
//row was not found;
}
//otherwise as you were doing
rowIwant.click();
});
You are right, filter() and other built-in Protractor "functional programming" methods would not solve the "stop iterating when first valid occurrence appears" case. You need the "take some elements while some condition evaluates to true" (like the itertools.takewhile() in Python world).
Fortunately, you can extend ElementArrayFinder (preferably in onPrepare()) and add the takewhile() method:
Take elements while a condition evaluates to true (extending ElementArrayFinder)
Note that I've proposed it to be built-in, but the feature request is still open:
Add takewhile() method to ElementArrayFinder

Drupal 6: Working with Hidden Fields

I am working on an issue i'm having with hooking a field, setting the default value, and making it hidden. The problem is that it is taking the default value, but only submitting the first character of the value to the database.
//Here is how I'm doing it
$form['field_sr_account'] = array( '#type' => 'hidden', '#value' => '45');
I suppose there is something wrong with the way that I have structured my array, but I can't seem to get it. I found a post, http://drupal.org/node/59660 , where someone found a solution to only the first character being submitted
//Here is the format of the solution to the post - but it's not hidden
$form['field_sr_account'][0]['#default_value']['value'] = '45';
How can I add the hidden attribute to this?
Have you tried using #default_value insted of #value?
Also if you're trying to pass some data to the submit that will not be changed in the form you should use http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html#value .
The answer was actually to set the value and the hidden attribute separately, then set the value again in the submit handler using the following format.
I'm not sure if it's all necessary, I suppose I probably don't need to assign it in the form alter, but it works, so I'm going to leave it alone...
$form['#field_sr_account'] = $club;
$form['field_sr_account'] = array( '#type' => 'hidden','#value' => $club);
}
}
/*in submit handler, restore the value in the proper format*/
$form_state['values']['field_sr_account'] = array('0' => array('value' => $form['#field_sr_account']));
An interesting solution from http://drupal.org/node/257431#comment-2057358
CCK Hidden Fields
/**
* Implementation of hook_form_alter().
*/
function YourModuleName_form_alter(&$form, $form_state, $form_id) {
if (isset($form['type']) && isset($form['#node'])) {
### Make a CCK field becoming a hidden type field.
// ### Use this check to match node edit form for a particular content type.
if ($form_id === 'YourContentTypeName_node_form') {
$form['#after_build'] = array('_test_set_cck_field_to_hidden');
}
}
}
function _test_set_cck_field_to_hidden($form, &$form_state) {
$form['field_NameToBeHidden'][0]['value']['#type'] = 'hidden';
$form['field_NameToBeHidden'][0]['#value']['value'] = 'testValue';
return $form;
}

Resources