简体   繁体   English

如何在 SearchKit 中强制更改查询?

[英]How to change the query imperatively in SearchKit?

We are trying to make a RefinementListFilter with checkboxes that has all items checked by default, and when all the items are unchecked by the user, all the items become checked automatically.我们正在尝试使用复选框创建一个默认选中所有项目的 RefinementListFilter,当用户取消选中所有项目时,所有项目都会自动选中。 We accomplished something similar but it has issues (sorry if the code feels ugly, it is WIP):我们完成了类似的事情,但它有问题(对不起,如果代码感觉难看,它是 WIP):

In the render code在渲染代码中

<RefinementListFilter
  id="type"
  title="By Type"
  field="_type"
  size={10}
  operator="OR"
  itemComponent={RefinementOption}
  listComponent={RefinementList}
/>

Other code其他代码

/**
 * Returns the label associated to a data type
 * @param {string} val
 */
const valueToLabel = (val) => {
  const data = [
    { label: 'Documents', value: 'document' },
    { label: 'Links', value: 'link' },
    { label: 'Web Pages', value: 'article' },
    { label: 'Species Info', value: 'species' },
    { label: 'Habitat Types Info', value: 'habitat' },
    { label: 'Sites Info', value: 'site' },
    { label: 'Protected Area', value: 'protected_area' }, // hidden
  ];
  return data.filter((x) => x.value === val)[0].label;
};

/**
 * Displays a checkbox w/ a label that replaces the default data type string.
 * @param {object} props
 */
const RefinementOption = (props) => {
  return (
    <div
      role="checkbox"
      onKeyPress={() => {}}
      className={props.bemBlocks
        .option()
        .state({ selected: props.active })
        .mix(props.bemBlocks.container('item'))}
      tabIndex={0}
      aria-checked={props.active}
    >
      <label style={{ flexGrow: 1 }}>
        <input
          type="checkbox"
          onClick={(...args) => {
            return props.onClick(...args);
          }}
          checked={props.active}
          className="sk-item-list-option__checkbox"
        />
        <span className={props.bemBlocks.option('text')}>
          {valueToLabel(props.label)}
        </span>
      </label>
      {/* <div className={props.bemBlocks.option('count')}>{props.count}</div> */}
    </div>
  );
};

/**
 * Before showing the data types' filter sort its options well and the default
 * behavior is to all be checked (this is the same as when all are unchecked,
 * because the implicit operator is OR).
 * @param {object} props
 */
const RefinementList = (props) => {
  const data = [
    { order: 1, key: 'document' },
    { order: 2, key: 'link' },
    { order: 3, key: 'article' },
    { order: 4, key: 'species' },
    { order: 5, key: 'habitat' },
    { order: 6, key: 'site' },
    { order: 7, key: 'protected_area' }, // hidden
  ];

  let arr = [...props.items];
  arr = arr.filter((x) => x.key !== 'protected_area');
  arr = arr.sort((a, b) => {
    console.log('A', a.key, 'B', b.key);

    const ai = data.findIndex((x) => x.key === a.key);
    const bi = data.findIndex((x) => x.key === b.key);
    if (ai < 0 || isNaN(ai) || bi < 0 || isNaN(bi)) {
      return 0;
    }

    return data[ai].order - data[bi].order;
  });

  const allKeys = arr.map((x) => x.key);
  const activeCount = props.selectedItems.length;
  let selectedItems = props.selectedItems.map((x) => x.key);
  if (activeCount === 0) {
    selectedItems = allKeys;
  } else {
    selectedItems = props.selectedItems;
    if (selectedItems.length === allKeys.length) {
      selectedItems = [];

      // TODO: do this in the selected filters view w/o reloading the page
      const newLoc = window.location.href
        .replace(/type\[\d+\]=[a-zA-Z0-9_]+/g, '')
        .replace(/&&/g, '&')
        .replace(/\?&/g, '?')
        .replace(/[&?]$/, '');
      if (newLoc !== window.location.href) {
        window.location.href = newLoc;
      }
    }
  }

  return (
    <CheckboxItemList {...props} items={arr} selectedItems={selectedItems} />
  );
};

What we are trying to avoid is in the TODO comment in the code above.我们试图避免的是上面代码中的TODO注释。

The documentation of SearchKit is not complete in my opinion.我认为SearchKit文档并不完整。 I could not find how to do this.我找不到如何做到这一点。

What I tried and works is to change the query by changing the URL of the browser (setting location.href ) but the reload of the page is really ugly and does not match the behavior of the rest of the page.我尝试和工作的是通过更改浏览器的 URL(设置location.href )来更改查询,但是页面的重新加载非常难看,并且与页面其余部分的行为不匹配。

The only thing left for me to try, if I do not get any answer, is to read the three demos' source code and then read the source code of SearchKit.如果我没有得到任何答案,我唯一可以尝试的就是阅读三个演示的源代码,然后阅读 SearchKit 的源代码。

The Git repo with the relevant file is OSS.带有相关文件的 Git 存储库是 OSS。

There are no error messages.没有错误消息。

Thank you.谢谢你。

Working solution, after taking a look at the SearchKit source code (yes, the first line is a global variable, I might change that into something else in future):可行的解决方案,在查看 SearchKit 源代码后(是的,第一行是一个全局变量,我将来可能会将其更改为其他内容):

let globalSearchKitManagers = [];

... ...

for (const sk of globalSearchKitManagers) {
  if (typeof sk !== 'undefined') {
    const filters = sk.accessors.accessors.filter(
      (x) => x.field === '_type',
    );
    for (const x of filters) {
      sk.removeAccessor(x);
    }
    sk.performSearch(true, true);
  }
}

... ...

React.useEffect(() => {
  globalSearchKitManagers.push(searchkit);
  return () => {
    globalSearchKitManagers.splice(
      globalSearchKitManagers.indexOf(searchkit),
      1,
    );
  };
}, [searchkit]);

Update: We are now using SearchkitComponent instead of the global variable in the above code snippet.更新:我们现在使用SearchkitComponent而不是上面代码片段中的全局变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM