Как удалить элемент из массива в объекте возврата нового объекта? - PullRequest
0 голосов
/ 08 января 2020

У меня есть этот объект

let x = {
      "name": "Ola",
      "dates": [
        {
          "7.01.2020": [1, 2, 3]
        },
        {
          "8.01.2020": [3 ,4]
        }
      ],
      "id": 7
    }

, и мне нужно иметь возможность удалять по нажатию кнопки выбранный элемент из массива. Ex. после нажатия кнопки мой объект выглядит следующим образом:

   let x = {
          "name": "Ola",
          "dates": [
            {
              "7.01.2020": [1, 2]
            },
           {
              "8.01.2020": [3 ,4]
            }
          ],
          "id": 7
        }

Обычно мне удается отфильтровать этот arr, проблема в том, что я пытаюсь вернуть новый x.dates arr. Обратите внимание, что есть объекты с разными ключами.

Есть идеи? Спасибо!

РЕДАКТИРОВАТЬ - все веселье c

    try {
      fetch(`http://localhost:3003/users/${userObject.id}`)
        .then(res => res.json())
        .then(user => {
          const map = new Map(
            user.dates.map((entry, i, arr) => {
              const [key] = Object.keys(entry);
              console.log(entry);
              return [key, entry[key]];
            })
          );
          result = map.get(date.toLocaleDateString());
          console.log(user.dates);
          return user;
        })
        .then(user => {
          // Create array without deleted task
          userDatesArr = result.filter(el => {
            if (el !== itemText) {
              return el;
            }
          });
          result = userDatesArr;
          // Update json-server - doesn't work, cause user.dates looks the same
          patchFunc(user.dates);
        });
    } catch (err) {
      console.error(err);
    }
;

Ответы [ 2 ]

3 голосов
/ 08 января 2020

Есть несколько проблем с этим кодом:

  1. Вы присваиваете переменную, которая нигде не объявлена ​​(result). Это означает, что код становится жертвой того, что я называю Ужас неявных глобалов . Вы должны объявить свои переменные. Я настоятельно рекомендую включить строгий режим, чтобы механизм JavaScript сообщал вам, когда вы это сделаете.

  2. Теперь вы используете filter, обратный вызов должен вернуть флаг, указывающий, следует ли сохранить запись.

  3. Вы не проверяете на успешность HTTP. Это пулемет в fetch API, о котором я пишу здесь . Вам нужно проверить ok в ответе перед вызовом json.

  4. itemText - строка, но ваш массив содержит числа. Ни одна строка не является === числом.

  5. Нет причин отделять код в вашем первом обработчике then от второго, промежуточного обещания нет.

  6. Нет причин создавать карту, если вы не собираетесь использовать ее повторно. Вы можете просто найти объект один раз.

  7. Ничто в коде не обрабатывает ошибки вызова ajax или обработчиков выполнения. (try / catch, который вы обернули вокруг него, будет ловить только ошибки, вызывающие fetch, а не ошибки в операции выборки последующих обработчиков then.)

Вот обновленная версия с некоторыми примечаниями:

  fetch(`http://localhost:3003/users/${userObject.id}`)
    .then(res => {
      // *** Check for HTTP success
      if (!res.ok) {
        throw new Error("HTTP error " + res.status);
      }
      return res.json();
    })
    .then(user => {
      const targetValue = +itemText; // *** Convert to number
      for (const entry of user.dates) {
        const targetKey = Object.keys(entry)[0];
        if (targetKey === key) {
          // *** Remove the entry if present
          entry[targetKey] = entry[targetKey].filter(value => value !== targetValue);
          break;
        }
      }
      // Update json-server
      patchFunc(user.dates);
    });

Обратите внимание, что это не помечает это, если объект для целевой даты не найден. Если вы хотите сделать это, вы можете добавить флаг:

  fetch(`http://localhost:3003/users/${userObject.id}`)
    .then(res => {
      // *** Check for HTTP success
      if (!res.ok) {
        throw new Error("HTTP error " + res.status);
      }
      return res.json();
    })
    .then(user => {
      const targetValue = +itemText; // *** Convert to number
      let found = false;
      for (const entry of user.dates) {
        const targetKey = Object.keys(entry)[0];
        if (targetKey === key) {
          // *** Remove the entry if present
          entry[targetKey] = entry[targetKey].filter(value => value !== targetValue);
          found = true;
          break;
        }
      }
      if (!found) {
        // *** Handle the fact it wasn't found
      }
      // Update json-server
      patchFunc(user.dates);
    });

Вы также захотите добавить обработчик отклонения (.catch) для обработки ошибок.

0 голосов
/ 08 января 2020

Я думаю, что приведенный ниже фрагмент кода поможет лучше понять проблему.

Проверьте консоль, вы получите желаемый результат. Вам необходимо выполнить глубокое клонирование, чтобы избежать изменения существующего объекта ( Глубокое клонирование - благодаря @nemisj)

let x = {
  "name": "Ola",
  "dates": [{
      "7.01.2020": [1, 2, 3]
    },
    {
      "8.01.2020": [3, 4]
    }
  ],
  "id": 7
}

function clone(item) {
    if (!item) { return item; } // null, undefined values check

    var types = [ Number, String, Boolean ], 
        result;

    // normalizing primitives if someone did new String('aaa'), or new Number('444');
    types.forEach(function(type) {
        if (item instanceof type) {
            result = type( item );
        }
    });

    if (typeof result == "undefined") {
        if (Object.prototype.toString.call( item ) === "[object Array]") {
            result = [];
            item.forEach(function(child, index, array) { 
                result[index] = clone( child );
            });
        } else if (typeof item == "object") {
            // testing that this is DOM
            if (item.nodeType && typeof item.cloneNode == "function") {
                result = item.cloneNode( true );    
            } else if (!item.prototype) { // check that this is a literal
                if (item instanceof Date) {
                    result = new Date(item);
                } else {
                    // it is an object literal
                    result = {};
                    for (var i in item) {
                        result[i] = clone( item[i] );
                    }
                }
            } else {
                // depending what you would like here,
                // just keep the reference, or create new object
                if (false && item.constructor) {
                    // would not advice to do that, reason? Read below
                    result = new item.constructor();
                } else {
                    result = item;
                }
            }
        } else {
            result = item;
        }
    }

    return result;
}


function deleteData (date, elementToBeDel) {
  let newObj = clone(x) // spreading to avoid mutating the object
  newObj.dates.map(dt => {
    if(Object.keys(dt)[0] === date){
      if(dt[date].indexOf(elementToBeDel) > -1){
        dt[date].splice(dt[date].indexOf(elementToBeDel), 1);
      }
    }
  })
  console.log("old Object", x)
  console.log("new Object",newObj)
}
<button onclick="deleteData('7.01.2020', 3)">Click Me to delete</button>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...