官术网_书友最值得收藏!

  • Vue.js 2.x by Example
  • Mike Street
  • 915字
  • 2021-07-02 20:00:28

Filtering our content

Now we have control over our people rows and some filter controls in our view, we need to make our filters work. We are already filtering by our isActive key, so the radio buttons will be the first to be wired up. We already have the value in a Boolean form for both the radio buttons values and the key we will be filtering by. For this filter to work, we need to compare the isActive key with the radio button's value.

  • If the filterUserState value is true, show users where isActive is true
  • If the filterUserState value is false, however, only show users where their isActive value is false as well

This can be written in one line by comparing the two variables:

      filterRow(person) {
return (this.filterUserState === person.isActive);
}

On page load, no users will be shown as the filterUserState key is set to neither true nor false. Clicking one of the radio buttons will reveal the corresponding users. 

Let's make the filter work only if the active user option is selected in the dropdown:

      filterRow(person) {
let result = true;

if(this.filterField === 'isActive') {
result = this.filterUserState === person.isActive;
}

return result;
}

This code sets a variable to true as a default. We can then return the variable immediately and our row will show. Before returning, however, it checks the value of the select box and if is the desired value, will then filter by our radio buttons. As our select box is bound to the filterField value, as with the filterUserState variable, it updates while we interact with the app. Try selecting the Active user option in the select box and changing the radio buttons.

The next step is to use the input query box when the active user option is not selected. We also want our query to be a fuzzy search — for example, to match words containing the search query rather than matching exactly. We also want it to be case insensitive:

      filterRow(person) {
let result = true;

if(this.filterField) {

if(this.filterField === 'isActive') {
result = this.filterUserState === person.isActive;
} else {
let query = this.filterQuery.toLowerCase(),
field = person[this.filterField].toString().toLowerCase();
result = field.includes(query);

}

}

return result;
}

There are a few things we had to add to this method in order to work. The first step is to check that our select field has a value to begin the filtering. As the first option in our select field has a value="", this equates to false. If this is the case, the method returns the default of true.

If it does have a value, it then goes to our original if statement. This checks on the specific value to see whether it matches isActive – if it does, it runs the code we wrote previously. If not, we start our alternate filtering. A new variable of query is established, which takes the value of the input and converts it to lowercase.

The second variable is the data we are going to be filtering against. This uses the value of the select box, which is the field key on the person, to extract the value to filter with. This value is converted to a string (in the case of the date or balance), converted to lowercase and stored as the field variable. Lastly, we then use the includes function to check whether the field includes the query entered. If it does, we return true and the row is shown if; not, the row is hidden.

The next issue we can address is when filtering with numbers. It is not intuitive for the user to enter the exact balance of the user they are after — a much more natural way of searching is to find users with a balance under or over a certain amount, for example, < 2000.

The first step in doing this is to only apply this type of filtering when it is the balance field. We can approach this two ways – we can either check that the field name is balance, similar to how we check the isActive field, or we can check the type of data we are filtering on.

Checking against the field name is simpler. We can do an else if()  in our method or even migrate to a switch statement for easier reading and expansion. The alternative of checking the field type, however, is more scalable. It means we can expand our dataset with more numeric fields without having to extend or change our code. It does mean, however, that there will be further if statements in our code.

What we will do first is alter our storing method, as we don't want to necessarily lowercase the field or query:

      if(this.filterField === 'isActive') {
result = this.filterUserState === person.isActive;
} else {
let query = this.filterQuery,
field = person[this.filterField];
}

The next step is to establish the type of data in the field variable. This can be established by, once again, using the typeof operator. This can be used in an if statement, to check whether the type of field is a number:

      if(this.filterField === 'isActive') {
result = this.filterUserState === person.isActive;
} else {
let query = this.filterQuery,
field = person[this.filterField];
if(typeof field === 'number') {
// Is a number
} else {
// Is not a number field = field.toLowerCase(); result = field.includes(query.toLowerCase());
}
}

Once our check is complete, we can default back to our original query code. It will use this if the select option is not isActive and the data were are filtering on is not a number. If this is the case, then it will lowercase the field and see if it includes what has been written in the query box when converted to lowercase as before.

The next stage is to actually compare our numbered data against what has been written in the query box. To do this, we are going to use the native JavaScript eval function.

The eval function can be a potentially dangerous function and should not be used in production code without some serious input sanitizing checks, plus, it is less performant than lengthier alternatives. It runs everything inside as native JavaScript and so can be open to abuse. However, as we are using this for a dummy application, with the focus being on Vue itself rather than creating a fully web-safe application, it is fine in this instance. You can read more about eval in 24 ways:

      if(this.filterField === 'isActive') {
result = this.filterUserState === person.isActive;
} else {

let query = this.filterQuery,
field = person[this.filterField];

if(typeof field === 'number') {
result = eval(field + query);
} else {
field = field.toLowerCase();
result = field.includes(query.toLowerCase());
}

}

This passes both the field and the query to the eval() function and passes the result (either true or false) to our result variable to determine the visibility of the row. The eval function literally evaluates the expression and determines if it is true or false. Here's an example:

      eval(500 > 300); // true
eval(500 < 400); // false
eval(500 - 500); // false

In this example, the number 500 is our field, or in this specific example, balance. Anything that is after that is what is written by our user. Your filtering code is now ready to go. Try selecting the balance from the dropdown and filtering for users with a balance higher than 2000

Before we move on, we need to add some error checking. If you have your JavaScript console open, you may have noticed an error when you typed the first greater or less than. This was because the eval function is unable to evaluate X > (where X is the balance). You may have also been tempted to type $2000 with the currency and realized this doesn't work. This is because the currency is applied while rendering the view, whereas we are filtering the data before this is rendered.

In order to combat these two errors, we must remove any currency symbols typed in the query and test our eval function before relying on it to return the results. Remove the currency symbol with the native JavaScript replace() function. If it changes, uses the currency symbol stored in the app, rather than hardcoding the currently used one. 

      if(typeof field == 'number') {
query = query.replace(this.currency, '');
result = eval(field + query);
}

We now need to test the eval function so it does not throw an error with every key pressed. To do this, we use a try...catch statement:

      if(typeof field == 'number') {
query = query.replace(this.currency, '');

try {
result = eval(field + query);
} catch(e) {}
}

As we don't want to output anything when an error is entered, we can leave the catch statement empty. We could put the field.includes(query) statement in here, so it falls back to the default functionality. Our full filterRow() method now looks like this:

      filterRow(person) {
let result = true;

if(this.filterField) {

if(this.filterField === 'isActive') {

result = this.filterUserState === person.isActive;

} else {

let query = this.filterQuery,
field = person[this.filterField];

if(typeof field === 'number') {

query = query.replace(this.currency, '');
try {
result = eval(field + query);
} catch (e) {}

} else {

field = field.toLowerCase();
result = field.includes(query.toLowerCase());

}
}
}

return result;

}
主站蜘蛛池模板: 射洪县| 雷山县| 大新县| 个旧市| 江源县| 合水县| 金溪县| 湛江市| 罗甸县| 北辰区| 纳雍县| 许昌市| 郴州市| 寻乌县| 崇信县| 龙山县| 房产| 郸城县| 尼勒克县| 南川市| 桐乡市| 聂荣县| 陈巴尔虎旗| 扎兰屯市| 剑川县| 景谷| 宝清县| 临颍县| 石门县| 察雅县| 山阴县| 城步| 醴陵市| 天等县| 五指山市| 高阳县| 大城县| 吉安市| 沙河市| 宝山区| 瑞安市|