Set Datagrid isRowSelectable property based on useListContext

huangapple go评论67阅读模式
英文:

Set Datagrid isRowSelectable property based on useListContext

问题

In a React-Admin Datagrid component, I want to set all of the list items to be individually selectable (isRowSelectable) based on all the rows in aggregate.

That is, all items should be selectable (if the status property is the same for all of them); OR all items should NOT be selectable (if the status property is NOT the same for all).

The code below does that, but has one problem. When I try to select all items using the checkbox at the top of the Datagrid, I get an error (Invalid hook call ... handleSelectAll DatagridHeader.tsx:65).

I don't get that error when I select the list items individually.

const checkAllStatuses = () => {
  const { data } = useListContext();
  const uniqueStatuses = [...new Set(data.map((item) => item.status))];
  return uniqueStatusStates.length === 1;
};

const EmployeeList = (props) => {
  return (
    <List title="Employees">
      <Datagrid isRowSelectable={checkAllStatuses}>
        ...
      </Datagrid>
    </List>
  );
};

How can I prevent the "Invalid hook call..." error when I select all the items collectively using the button at the top?

Alternatively, is there a way to disable or hide the "select all" checkbox in the Datagrid header - but only when the status property is not the same for all items?

英文:

In a React-Admin Datagrid component, I want to set all of the list items to be individually selectable (isRowSelectable) based on all the rows in aggregate.

That is, all items should be selectable (if the status property is the same for all of them); OR all items should NOT be selectable (if the status property is NOT the same for all).

The code below does that, but has one problem. When I try to select all items using the checkbox at the top of the Datagrid, I get an error (Invalid hook call ... handleSelectAll DatagridHeader.tsx:65).

I don't get that error when I select the list items individually.

const checkAllStatuses = () =&gt; {
  const { data } = useListContext();
  const uniqueStatuses = [...new Set(data.map((item) =&gt; item.status))];
  return uniqueStatusStates.length === 1;
};

const EmployeeList = (props) =&gt; {
  return (
    &lt;List title=&quot;Employees&quot;&gt;
      &lt;Datagrid isRowSelectable={checkAllStatuses}&gt;
        ...
      &lt;/Datagrid&gt;
    &lt;/List&gt;
  );
};

How can I prevent the "Invalid hook call..." error when I select all the items collectively using the button at the top?

Alternatively, is there a way to disable or hide the "select all" checkbox in the Datagrid header - but only when the status property is not the same for all items?

答案1

得分: 1

以下是翻译好的内容:

  1. 添加一个状态以获取当前选定的状态。
  2. 创建一个函数来覆盖Datagrid上的行选择(请参见 https://github.com/marmelab/react-admin/issues/2000#issuecomment-840594240 以覆盖选择)。
  3. 当用户勾选某项时,选择所有具有相同状态的其他内容。
  4. 当用户勾选某项时,同时设置当前选定的状态。
  5. 使用当前选定的状态还可以禁用其他行上的复选框。

以下是代码示例:

import { useRecordSelection } from 'react-admin';

// 步骤 2
const useSetSelectedRecords = (resource: string, ids: string[] | undefined) => {
  const [, { select }] = useRecordSelection(resource);
  useEffect(() => {
    ids && select(ids);
  }, [select, ids]);
}

const EmployeeList = (props) => {

  const { data } = useListContext();
  const [currentStatus, setCurrentStatus ] = useState(undefined);// 步骤 1

  return (
    <List title="Employees">
      <Datagrid isRowSelectable={(record) => {
        // 步骤 5
        currentStatus && record.status === currentStatus
      }}>
        ...
      </Datagrid>
    </List>
  );
};

然后在用户与复选框交互或所选 ID 更改时调用下面的代码(步骤 3)和 setCurrentStatus 函数(步骤 4)。

  useSetSelectedRecords(
    props.resource,
    data
      .filter(record => record.status === currentStatus)
      .map(record => record.id)
  )

不要忘记在移除所有选择时调用 setCurrentStatus(undefined),以重新启用所有行的行选择。

英文:

From what I understood, you want to

  1. Add a state to get your currently selected status
  2. Create a function to overwrite the rows selection on the Datagrid (see https://github.com/marmelab/react-admin/issues/2000#issuecomment-840594240 to overwrite the selection)
  3. Select everything else that has the same status when the user checks something
  4. Also set the currently selected status when the user checks something
  5. Use the currently selected status to also disable the checks on other rows

Which translates to:

import { useRecordSelection } from &#39;react-admin&#39; 

// step 2
const useSetSelectedRecords = (resource: string, ids: string[] | undefined) =&gt; {
  const [, { select }] = useRecordSelection(resource)
  useEffect(() =&gt; {
    ids &amp;&amp; select(ids)
  }, [select, ids])
}

const EmployeeList = (props) =&gt; {

  const { data } = useListContext();
  const [currentStatus, setCurrentStatus ] = useState(undefined);// step 1

  return (
    &lt;List title=&quot;Employees&quot;&gt;
      &lt;Datagrid isRowSelectable={(record) =&gt;
        // step 5
        currentStatus &amp;&amp; record.status === currentStatus
      }&gt;
        ...
      &lt;/Datagrid&gt;
    &lt;/List&gt;
  );
};

And then call the code below (step 3) and the setCurrentStatus function (step 4) when the user interacts with the checkbox or as an effect for when the selected ids change.

  useSetSelectedRecords(
    props.resource,
    data
      .filter(record =&gt; record.status === currentStatus)
      .map(record =&gt; record.id)
  )

And don't forget to call setCurrentStatus(undefined) when you remove all selections too to re-enable the row selection for all rows.

答案2

得分: 1

可能的实现

    const DatagridCheck = () => {
      let checkAll = false
      const { data } = useListContext()
    
      if (data) {
        const uniqueStatuses = new Set(data.map((item) => item.status)) 
        checkAll = uniqueStatuses.size === 1
      }
    
      return (
        <Datagrid isRowSelectable={() => checkAll}>
          ...
        </Datagrid>
      )
    }
    
    const EmployeeList = (props) => {
      return (
        <List title="Employees">
          <DatagridCheck />
        </List>
      )
    }
英文:

Possible implementation:

const DatagridCheck = () =&gt; {
  let checkAll = false
  const { data } = useListContext()

  if (data) {
    const uniqueStatuses = new Set(data.map((item) =&gt; item.status)) 
    checkAll = uniqueStatuses.size === 1
  }

  return (
    &lt;Datagrid isRowSelectable={() =&gt; checkAll}&gt;
      ...
    &lt;/Datagrid&gt;
  )
}

const EmployeeList = (props) =&gt; {
  return (
    &lt;List title=&quot;Employees&quot;&gt;
      &lt;DatagridCheck /&gt;
    &lt;/List&gt;
  )
}

huangapple
  • 本文由 发表于 2023年4月11日 04:10:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980359.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定