सामने की तरफ डेटा को छानने की घोषणा। जेएस / टीएस


क्या आपको अक्सर अपने डेटा के लिए फ़िल्टर हैंडलर लिखना पड़ता है? यह ड्रॉइंग टेबल, कार्ड, सूचियों - कुछ भी के लिए एरेज़ हो सकता है।


जब फ़िल्टरिंग स्थिर होती है, तो सब कुछ सरल होता है। मानक सुविधाएँ map, filterऔर reduceकाफी पर्याप्त हैं। लेकिन क्या होगा यदि डेटा में एक जटिल संरचना या घोंसले का शिकार है, और फिल्टर के लिए काफी नियम हो सकते हैं। नियमों को दोहराया जा सकता है, डेटा बदला जा सकता है, और जितना अधिक फिल्टर नियंत्रण दिखाई देगा, उतना ही जटिल और अस्थिर हैंडलर कोड होगा।


बढ़ती जटिलता की समस्या को कैसे हल करें?


मैंने स्वयं एक बड़ी मात्रा में डेटा के साथ काम करने वाले एप्लिकेशन को विकसित करते समय इस समस्या का सामना किया। धीरे-धीरे अधिक से अधिक नए फिल्टर जोड़े।


, . . , . , . - .


, .
, :


  1. ng-table — . .
  2. List.js — ng-table, .
  3. filter.js — , , .
  4. Isotope — DOM . .

, :


  1. .
  2. .
  3. .
  4. , and or .
  5. . .
  6. ( , , , , , )

awesome-data-filter.


, , .



.


npm install awesome-data-filter

.
, :


const users = [
  {
    age: 31,
    name: "Marina Gilmore",
  },
  {
    age: 34,
    name: "Joyner Mccray",
  },
  {
    age: 23,
    name: "Inez Copeland",
  },
  {
    age: 23,
    name: "Marina Mitchell",
  },
  {
    age: 25,
    name: "Prince Spears",
  },
];

:


const filterValue = {
  age: 23,
  searchText: "mari",
};

, .


:


  • matchText — ;
  • equalProp — ;
    • betweenDates — ;
    • equalOneOf — ;
    • someInArray — ;
    • isEmptyArray — ;
    • lessThen — , ;
    • moreThen — , ;
    • not — .

matchText equalProp.


:


  • filterField — ;
  • elementField — .

import { 
  buildFilter, 
  elementField, 
  filterField, 
} from "awsome-data-filter";
import { matchText, equalProp } from "awsome-data-filter/rules";
import { and } from "awsome-data-filter/conditions";

const filter = buildFilter({
    rules: {
      elementFilter: and([
        matchText(filterField("searchText"), elementField("name")),
        equalProp(filterField("age"), elementField("age")),
      ]),
    },
  });

const { elements } = filter(
    filterValue,
    {
      groups: [],
      elements: users,
    },
);

console.log(elements);
// elements: [{ age: 23, name: "Marina Mitchell" }]

filter groups elements.


, . .



, , elements.


and or, 2 .


import { 
  buildFilter, 
  elementField, 
  filterField, 
} from "awsome-data-filter";
import { matchText, equalProp } from "awsome-data-filter/rules";
import { or } from "awsome-data-filter/conditions";

const filter = buildFilter({
    rules: {
      elementFilter: or([
        matchText(filterField("searchText"), elementField("name")),
        equalProp(filterField("age"), elementField("age")),
      ]),
    },
  });

const { elements } = filter(
    filterValue,
    {
      groups: [],
      elements: users,
    },
);

console.log(elements);
// elements: 
// [
//   {
//     age: 31,
//     name: "Marina Gilmore",
//   },
//   {
//     age: 23,
//     name: "Inez Copeland",
//   },
//   {
//     age: 23,
//     name: "Marina Mitchell",
//   }
// ]

filterField, elementField .


constValue .
or(..., matchText, [and([..., matchText, ...]), or([..., ...])])


. :


const dataList = [
  {
    groupName: "first group",
    list: [
      { age: 31, name: "Marina" },
      { age: 23, name: "Fabio" },
    ],
  },
  {
    groupName: "second group",
    groups: [
      {
        groupName: "third group",
        list: [],
        groups: [
          {
            groupName: "fourth group",
            list: [{ age: 42, name: "Li" }],
          },
        ],
      },
    ],
    list: [
      { age: 41, name: "Marina" },
      { age: 29, name: "Inez" },
      { age: 33, name: "Marina" },
    ],
  },
  {
    groupName: "fifth group",
    list: [
      { age: 21, name: "Dmitriy" },
      { age: 22, name: "Li" },
      { age: 45, name: "Mitchell" },
    ],
  },
];

traversal:


import { 
  buildFilter, 
  elementField, 
  filterField, 
} from "awsome-data-filter";
import { matchText } from "awsome-data-filter/rules";

const filter = buildFilter({
    traversal: {
      getChildrenFunc: group => group.list, //    
      setChildrenFunc: (group, list) => ({ ...group, list }), //      
      getGroupsFunc: group => group.groups, //    
      setGroupsFunc: (group, groups) => ({ ...group, groups }), //    
    },
    rules: {
      elementFilter: matchText(filterField("searchText"), elementField("name")),
    },
  });

const filterValue = {
  searchText: "li",
};

const { groups } = filter(filterValue, {
  groups: dataList, //      
  elements: [], //       
});

console.log(groups);
// groups: 
//[
//  {
//    groupName: "second group",
//    groups: [
//      {
//        groupName: "third group",
//        list: [],
//        groups: [
//          {
//            groupName: "fourth group",
//            list: [{ age: 42, name: "Li" }],
//          },
//        ],
//      },
//    ],
//    list: [],
//  },
//  {
//    groupName: "fifth group",
//    list: [
//      { age: 22, name: "Li" },
//    ],
//  },
//]

elementFilter , . groupFilter .


import { 
  buildFilter, 
  elementField, 
  filterField, 
} from "awsome-data-filter";
import { matchText } from "awsome-data-filter/rules";

const filter = buildFilter({
    traversal: {
      getChildrenFunc: group => group.list, //    
      setChildrenFunc: (group, list) => ({ ...group, list }), //      
      getGroupsFunc: group => group.groups, //    
      setGroupsFunc: (group, groups) => ({ ...group, groups }), //    
    },
    rules: {
      elementFilter: matchText(filterField("searchText"), elementField("name")),
      groupFilter: matchText(filterField("groupName"), elementField("groupName")),
    },
  });

const filterValue = {
  searchText: "li",
  groupName: "fi",
};

const { groups } = filter(filterValue, {
  groups: dataList,
  elements: [],
});

console.log(groups);
// groups:
//[
//  {
//    groupName: "first group",
//    list: [
//      { age: 31, name: "Marina" },
//      { age: 23, name: "Fabio" },
//    ],
//  },
//  {
//    groupName: "second group",
//    groups: [
//      {
//        groupName: "third group",
//        list: [],
//        groups: [
//          {
//            groupName: "fourth group",
//            list: [{ age: 42, name: "Li" }],
//          },
//        ],
//      },
//    ],
//    list: [],
//  },
//  {
//    groupName: "fifth group",
//    list: [
//      { age: 22, name: "Li" },
//    ],
//  },
//]

first group , , , .
fifth group , , .


. :


const standardStrategy: StrategiesFilterInterface = {
  elementHandler: ({ //     
    element,
    tools: { 
        isGroupFilterIsActive, //     
        applyElementFilter //   
    },
  }) => {
    if (isGroupFilterIsActive) return null;
    if (!applyElementFilter) return element;
    return applyElementFilter(element, true) ? element : null;
  },
  groupHandler: ({
    element: group,
    originalElement: originalGroup,
    tools: {
      isGroupFilterIsActive,
      applyElementFilter,
      getIsGroupFilterHaveMatch,
      getGroupsFunc,
      getChildrenFunc,
      setChildrenFunc,
    },
  }) => {
    let newChildren = [];
    let originalChildren = [];
    const children = getChildrenFunc(group);
    const childrenExists = !!children;
    //     
    if (children) {
      originalChildren = [...children];
      newChildren = originalChildren.filter(element =>
        applyElementFilter
          ? applyElementFilter(element, !isGroupFilterIsActive)
          : !isGroupFilterIsActive,
      );
    }
    //     ,    ,   
    if (!newChildren.length && getIsGroupFilterHaveMatch(group)) {
      return originalGroup;
    }
    //     ,    
    if (childrenExists) {
      group = setChildrenFunc(group, newChildren);
    }

    //   
    const newGroups = getGroupsFunc(group);
    const isGroupsExists = !!(newGroups && newGroups.length);
    const isElementExists = !!(newChildren && newChildren.length);
    //      ,   
    return isElementExists || isGroupsExists ? group : null;
  },
};

, filterStrategy.



awesome-data-filter . .



, . .


, .


All Articles