在Vuejs中创建的新对象更新为最后一个值

时间:2017-10-31 20:43:22

标签: vue.js

我是Vuejs的新手,但我遇到了一些代码问题。

我试图将一系列line_items的订单“压扁”成一个项目列表,然后为每个对象创建元信息。第一部分工作正常,但似乎Vuejs的反应性质导致这些新创建的对象的最后一个值延伸到以前所有的化身。

我在这里创造了一个小提琴。 http://jsfiddle.net/trestles/ruj7hzcf/3/

我认为问题在于创建我的项目(〜小提琴中的第70行)。

  // here's the problem - why is quantity being updated to the last value? 
  var item = {item_id: line_item.menu_item_id, header: line_item.menu_item_header, quantity: line_item.quantity, locations: locations }
  this.items.push(item);

为什么在这种情况下项目会更新为最后一个值?

在表格中,结果如下:

test item  3 5 8 
spiced shrimp with horseradish cocktail sauce (per dozen) 9 5 8 
dates with bacon & parmesan (per dozen) 5 5 8 
marcona almonds (serves 8) 6 5 8 
marinated olives (serves 8) 8 5 8 

应该是

test item  3 3 0 
spiced shrimp with horseradish cocktail sauce (per dozen) 9 2 7 
dates with bacon & parmesan (per dozen) 5 5 0 
marcona almonds (serves 8) 6 0 6 
marinated olives (serves 8) 8 0 8 

我做错了什么?

1 个答案:

答案 0 :(得分:3)

现有代码中的大多数问题的根源是重复使用相同的对象 - this.locationsthis.orderPickupTimes数组的元素 - 一次又一次地通过createNewItem传递它们。在代码中添加这些行:

// instead of var location = this.locations[j];
var location = Object.assign({}, this.locations[j]);

// and within the internal loop
// instead of var order_pickup_time = this.orderPickupTimes[k];
var order_pickup_time = Object.assign({}, this.orderPickupTimes[k]);

......看看它的不同之处。

尽管如此,这只是问题的一部分。您的代码的关键思想是存储 - 每个“项目”对象 - 整个位置列表和取件时间,让某些订单设置其“数量”属性更改。

但要做到这一点,你需要区分已经处理过的物品(已经填充了它们的结构)和新鲜物品。这很麻烦,是的,但可能会有这样的事情:

 var locations = [];
 var item = this.items.find(it => it.item_id === line_item.menu_item_id);
 if (item) {
     locations = item.locations;
 }
 else {
     item = {item_id: line_item.menu_item_id, header: line_item.menu_item_header, quantity: 0, locations: locations };
     this.items.push(item);
 }

...并且需要在创建新位置或orderPickupTime之间进行选择,或重复使用现有位置。

以下the demo说明了这种方法。

不过,我在这里改变了两个主要部分。

首先,我创建一个专用的私人功能,按订单项目的位置和订单取货时间对订单项目进行分组。像这样:

function _groupItemsByOrders(orders) {
  return orders.reduce(function(groupedItems, order) {
    var locationId = order.location_id;
    var orderPickupTimeKey = order.order_pickup_time_short;
    order.line_items.forEach(function(lineItem) {
      if (!groupedItems.hasOwnProperty(lineItem.menu_item_id)) {
        groupedItems[lineItem.menu_item_id] = {
          header: lineItem.menu_item_header,
          quantity: 0,
          locations: {}
        };
      }
      var groupedItem = groupedItems[lineItem.menu_item_id];

      if (!groupedItem.locations.hasOwnProperty(locationId)) {
        groupedItem.locations[locationId] = {};
      }
      var groupedItemLocation = groupedItem.locations[locationId];

      if (!groupedItemLocation.hasOwnProperty(orderPickupTimeKey)) {
        groupedItemLocation[orderPickupTimeKey] = 0;
      }

      groupedItemLocation[orderPickupTimeKey] += lineItem.quantity;
      groupedItem.quantity += lineItem.quantity;
    });

    return groupedItems;
  }, {});
}

其次,我重新安排了该模板,使其从头数组中获取位置和orderPickupTimes的顺序,然后将其映射到groupedData。像这样:

  <tr v-for="(item, item_id) in groupedItems">
      <td>{{item_id}}</td>
      <td>{{item.header}}</td>
      <td>{{item.quantity}}</td>
      <template v-for="location in locations">
        <td v-for="opt in orderPickupTimes">
          {{item.locations[location.id][opt.short]}}
        </td>
      </template>
  </tr>

现在,你的“挂载”钩子看起来像这样:

mounted(){
  axios.get('http://www.mocky.io/v2/59f8ceb52d00004d1dad41ec')
    .then(response => {
      this.locations = response.data.locations;
      this.orderPickupTimes = response.data.order_pickup_times;
      this.groupedItems = _groupItemsByOrders(response.data.orders);
    });
}

这是the demo