تصفية البيانات التعريفية في المقدمة. شبيبة / ts


هل تحتاج غالبًا إلى كتابة معالجات التصفية لبياناتك؟ يمكن أن تكون صفائف لرسم الجداول والبطاقات والقوائم - أي شيء.


عندما يكون الترشيح ثابتًا ، يكون كل شيء بسيطًا. يتميز معيار 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