简体   繁体   English

如何从对象中的数组中删除元素并返回新对象?

[英]How to delete element from array in object an return new object?

I have this object我有这个对象

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

and I need to be able to delete on button click chosen element from array.并且我需要能够在单击按钮时从数组中删除所选元素。 Ex.前任。 after button click, my object looks like this:单击按钮后,我的对象如下所示:

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

Acrtually I've managed to filter this arr, the problem is when I try to return new x.dates arr.实际上我已经设法过滤了这个 arr,问题是当我尝试返回新的 x.dates arr 时。 Please, notice that there are objects with different keys.请注意,有些对象具有不同的键。

Any ideas?有任何想法吗? Thanks!谢谢!

EDIT - whole func编辑 - 整个功能

    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);
    }
;

There are a few issues with that code:该代码有几个问题:

  1. You're assigning to a variable that isn't declared anywhere ( result ).您正在分配一个未在任何地方声明的变量( result )。 That means the code is falling prey to what I call The Horror of Implicit Globals .这意味着代码正在成为我所说的隐式全局的恐怖的牺牲品。 You need to declare your variables.你需要声明你的变量。 I strongly recommend turning on strict mode so the JavaScript engine will tell you when you do this.强烈建议打开严格模式,以便 JavaScript 引擎会在您执行此操作时告诉您。

  2. That's now how you use filter , the callback should return a flag saying whether to keep the entry.这就是你现在如何使用filter ,回调应该返回一个标志,说明是否保留条目。

  3. You're not checking for HTTP success.您没有检查 HTTP 是否成功。 This is a footgun in the fetch API I write about here .这是我在 此处写的fetch API 中的一把枪。 You need to check ok on the response before calling json .在调用json之前,您需要检查响应是否ok

  4. itemText is a string, but your array contains numbers. itemText是一个字符串,但您的数组包含数字。 No string is ever === a number.没有字符串永远是===数字。

  5. There is no reason for separating the code in your first then handler from the second, there's no intervening promise.没有理由将第一个then处理程序中的代码与第二个处理程序分开,没有中间承诺。

  6. There's no reason to create the Map if you're not going to reuse it.如果您不打算重用它,就没有理由创建 Map。 You can just find the object once.您只能找到该对象一次。

  7. Nothing in the code handles errors the ajax call or the fulfillment handlers.代码中没有任何内容处理 ajax 调用或履行处理程序的错误。 (The try / catch you have wrapped around it will only catch errors calling fetch , not errors in the fetch operation of subsequent then handlers.) (围绕它的try / catch只会捕获调用fetch错误,而不是后续then处理程序的 fetch 操作中的错误。)

Here's an updated version with some notes:这是一个带有一些注释的更新版本:

  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);
    });

Note that that doesn't flag it up if the object for the target date isn't found.请注意,如果未找到目标日期的对象,则不会对其进行标记。 If you want to do that, you can add a flag:如果你想这样做,你可以添加一个标志:

  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);
    });

You'll also want to add a rejection handler ( .catch ) to handle errors.您还需要添加一个拒绝处理程序 ( .catch ) 来处理错误。

I think the below code snippet will give a better understanding of the problem.我认为下面的代码片段可以更好地理解这个问题。

Check the console, you will get the desired output.检查控制台,您将获得所需的输出。 You need to do a deep cloning to avoid mutating the existing object ( Deep Cloning - thanks to @nemisj)您需要进行深度克隆以避免改变现有对象( 深度克隆- 感谢 @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>

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

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