$cache[$key] = empty($arr) ? NULL : $arr; return $cache[$key]; } // 门户 获取需要在频道显示的栏目主题数据 function portal_channel_thread($fid) { global $forumlist; if (empty($fid)) return NULL; $orderby = array('tid' => 1); $page = 1; // 遍历所有在频道显示内容的栏目 $category_forumlist = channel_category($fid); $arrlist = array(); $forum_tids = array(); $tidlist = array(); if ($category_forumlist) { foreach ($category_forumlist as &$_forum) { // 频道显示数据 $arrlist['list'][$_forum['fid']] = array( 'fid' => $_forum['fid'], 'name' => $_forum['name'], 'rank' => $_forum['rank'], 'type' => $_forum['type'], 'url' => $_forum['url'], 'channel_new' => $_forum['channel_new'], ); $forum_thread = thread_tid__find(array('fid' => $_forum['fid']), $orderby, $page, $_forum['channel_new'], 'tid', array('tid')); // 最新信息按栏目分组 foreach ($forum_thread as $key => $_thread) { $forum_tids[$key] = $_thread; } unset($forum_thread); } $tidlist += $forum_tids; } unset($category_forumlist); // 获取属性对应的tid集合 list($flaglist, $flagtids) = flag_thread_by_fid($fid); empty($flagtids) || $tidlist += $flagtids; unset($flagtids); // 频道置顶 $stickylist = sticky_list_thread($fid); empty($stickylist) || $tidlist += $stickylist; // 在这之前合并所有二维数组 tid值为键/array('tid值' => tid值) $tidarr = arrlist_values($tidlist, 'tid'); // 在这之前使用$tidarr = array_merge($tidarr, $arr)前合并所有一维数组 tid/array(1,2,3) if (empty($tidarr)) { $arrlist['list'] = isset($arrlist['list']) ? array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid') : array(); return $arrlist; } $tidarr = array_unique($tidarr); $pagesize = count($tidarr); // 遍历获取的所有tid主题 $threadlist = well_thread_find_asc($tidarr, $pagesize); // 遍历时为升序,翻转为降序 $threadlist = array_reverse($threadlist); foreach ($threadlist as &$_thread) { // 各栏目最新内容 isset($forum_tids[$_thread['tid']]) AND $arrlist['list'][$_thread['fid']]['news'][$_thread['tid']] = $_thread; // 全站置顶内容 isset($stickylist[$_thread['tid']]) AND $arrlist['sticky'][$_thread['tid']] = $_thread; // 首页属性主题 if (!empty($flaglist)) { foreach ($flaglist as $key => $val) { if (isset($val['tids']) && in_array($_thread['tid'], $val['tids'])) { $arrlist['flaglist'][$key][array_search($_thread['tid'], $val['tids'])] = $_thread; ksort($arrlist['flaglist'][$key]); $arrlist['flag'][$_thread['tid']] = $_thread; } } } } unset($threadlist); if (isset($arrlist['sticky'])) { $i = 0; foreach ($arrlist['sticky'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flag'])) { $i = 0; foreach ($arrlist['flag'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flaglist'])) { foreach ($arrlist['flaglist'] as &$val) { $i = 0; foreach ($val as &$v) { ++$i; $v['i'] = $i; } } } isset($arrlist['list']) AND $arrlist['list'] = array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid'); return $arrlist; } ?>javascript - Only send values that have changed in formik onSubmit - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Only send values that have changed in formik onSubmit - Stack Overflow

programmeradmin1浏览0评论

I have a small table of data that is pre-filled by an api call on page load. Each row in the table has a facility name and an Enabled value which comes from the api call. If Enabled == true the checkbox is shown as checked.

I have a couple checkboxes that are grayed out because of a condition in which it cannot be changed at all so there's a readOnly attribute on the field.

Onto my question, for brevity I condensed the list of facilities shown in the table, but in reality there could be X amount of facilities. In my onSubmit function I only want to send the facility name and enabled value if they have been selected/deselected instead of sending the entire list every time submit is pressed.

Ideally I want the shape of the data sent to look like so:

{
    facilityName: "Backup Restore",
    enabled: true
}

Now, I have been able to isolate JUST the facilityName and enabled value but I cannot figure out to only include the values that have been changed in the form. Like I said above, not every single facility name and enabled key/value should be sent every time submit is pressed just the ones that have been changed.

This is what I currently have(and can be seen in the sandbox below) in my onSubmit function

         <Formik
          enableReinitialize
          initialValues={{
            facilities: loggingFacilities
          }}
          onSubmit={async (values, { setSubmitting }) => {

            alert(JSON.stringify(values, null, 2));
            try {

              setLoggingFacilities(values.facilities);
              const valuesToSend = values.facilities.map(facility => {
                return {
                  key: facility.facilityName,
                  value: facility.enabled
                };
              });
              .....

I have a codesandbox here

I have a small table of data that is pre-filled by an api call on page load. Each row in the table has a facility name and an Enabled value which comes from the api call. If Enabled == true the checkbox is shown as checked.

I have a couple checkboxes that are grayed out because of a condition in which it cannot be changed at all so there's a readOnly attribute on the field.

Onto my question, for brevity I condensed the list of facilities shown in the table, but in reality there could be X amount of facilities. In my onSubmit function I only want to send the facility name and enabled value if they have been selected/deselected instead of sending the entire list every time submit is pressed.

Ideally I want the shape of the data sent to look like so:

{
    facilityName: "Backup Restore",
    enabled: true
}

Now, I have been able to isolate JUST the facilityName and enabled value but I cannot figure out to only include the values that have been changed in the form. Like I said above, not every single facility name and enabled key/value should be sent every time submit is pressed just the ones that have been changed.

This is what I currently have(and can be seen in the sandbox below) in my onSubmit function

         <Formik
          enableReinitialize
          initialValues={{
            facilities: loggingFacilities
          }}
          onSubmit={async (values, { setSubmitting }) => {

            alert(JSON.stringify(values, null, 2));
            try {

              setLoggingFacilities(values.facilities);
              const valuesToSend = values.facilities.map(facility => {
                return {
                  key: facility.facilityName,
                  value: facility.enabled
                };
              });
              .....

I have a codesandbox here

Share Improve this question edited Jan 10, 2020 at 0:19 DJ2 asked Jan 6, 2020 at 22:35 DJ2DJ2 1,7513 gold badges37 silver badges76 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 7

From the second param of your onSubmit callback, you can access props, so you could diff values against props.initialValues or however you have called the prop you use to initialize the form.

Actually, that's the suggestion from Jared Palmer:

You can compare initialValues and values within handleSubmit / onSubmit.

Using Array.prototype.filter() it would look something like this:

onSubmit={async (values, { props, setSubmitting }) => {

  // Let's assume this has the same format as `values.facilities`:
  const { initialValues } = props;

  try {
    setLoggingFacilities(values.facilities);

    const valuesToSend = values.facilities.filter((facility, i) => {
      // Let's send only those that have just been disabled or enabled:
      return facility.enabled !== initialValues[i].enabled;
    }).map((facility) => ({
      key: facility.facilityName,
      value: facility.enabled
    }));

    // ...

  } catch(err) { ... }

}

Try this:

const getChangedValues = (values, initialValues) => {
  return Object
    .entries(values)
    .reduce((acc, [key, value]) => {
      const hasChanged = initialValues[key] !== value

      if (hasChanged) {
        acc[key] = value
      }

      return acc
    }, {})
}

addition to the answer of randomKek (https://stackoverflow.com/a/66729194/878055)

Here is the typescript version of his function

const getChangedValues = <T extends Record<string, any>>(values: T, initialValues: T) => {
  return Object.entries(values).reduce((acc: Partial<T>, [key, value]) => {
    const hasChanged = initialValues[key as keyof T] !== value;

    if (hasChanged) {
      acc[key as keyof T] = value;
    }

    return acc;
  }, {});
};

I'm arriving later to this issue but I think you can use dirty flag. It appears to do the deep comparing with initial values for you. And will complement nicely with @Dazinger approach.

dirty: boolean Returns true if values are not deeply equal from initial values, false otherwise. dirty is a readonly computed property and should not be mutated directly.

发布评论

评论列表(0)

  1. 暂无评论