【问题标题】:Upserting data from table to database?将数据从表更新到数据库?
【发布时间】:2018-11-30 13:10:03
【问题描述】:

我有一个时间跟踪表网络应用程序,其中每一行代表数据库中的一个用户,每一列都有一个输入字段,用户将在其中输入他们在特定日期工作的小时数。 向您展示它的外观的小提琴:https://jsfiddle.net/L5u1fc0a/138/

基本上,我如何确保只向数据库发送新数据。我希望(显然)在表中显示当前值,并且我正在获取该数据并将其存储在 Vue v-model 中(参见小提琴中的worklogs) - worklogs 中的这些数据是填充表的内容.我的问题是我不知道如何处理额外的时间。如果用户在特定日期再增加一小时并点击“更新”(在小提琴中,“保存”),它将发送包含所有当前值 + 新值的整个 worklogs 数据值,所以如果有人要仅添加一个输入,它仍会发送worklogsobject 中的所有内容。在小提琴中,如果您在某处输入一个新值并点击“保存”按钮,您可以看到我的数组updateData也在填充所有现有值 - 我怎样才能只将新更新的值发送到数据库?

【问题讨论】:

  • 在您的数据中包含一个“脏”标志,这样您就知道发生了什么变化。保存所有项目时将其设置为 false。每次进行更新时将其设置为 true。
  • 你能举个例子吗?不知道这是什么意思

标签: javascript http post vue.js put


【解决方案1】:

如果您随时更改数据,您将无法真正弄清楚更新了什么。您需要在工作时将它们分开,然后只需保存 updateData。所以我将你的worklogs 重命名为saved,并使updateData 成为一个对象,该对象将包含与saved 完全相同类型的条目。

我做了一个合并savedupdateData 的计算,并将其用于绑定value。你不能在这里真正使用v-model,因为你不能将单个元素写回计算字典。但你不需要。在更改时,您更新 updateData 并且 value 保持一致。

(旁注:如果您将每个输入都设为一个组件,则可以使用v-model,但仍然需要在父级中处理所有管道。)

save 函数执行后端调用的任何操作,更新saved,并清空updateData

/* app instance */
new Vue({
  el: '#app',
    data() {
    	const currentDate = new Date();
    	return {
      saved: {
        "1,2018-11-01": "8", 
        "1,2018-11-02": "8",
        "2,2018-11-03": "10",
        "2,2018-11-04": "10"
				},
      updateData: {},
      users: [
          {id: 1, firstName: 'Jay', lastName: 'Carter', email: 'jayz@rocafella.com'},
          {id: 2, firstName: 'Day', lastName: 'Darter', email: 'dayz@rocafella.com'}
        ],
        secondHalf: false,
        selectedYear: currentDate.getFullYear(),
        selectedMonth: currentDate.getMonth() + 1,
        
    };
  },
  methods: {
    prevPeriod() {
      if (!this.secondHalf) {
        this.selectedMonth -= 1;
        this.secondHalf = !this.secondHalf;
      } else {
        this.secondHalf = !this.secondHalf;
      }
      if (this.selectedMonth < 1) {
        this.selectedYear -= 1;
        this.selectedMonth = 12;
      }
    },
    nextPeriod() {
      if (this.secondHalf) {
        this.selectedMonth += 1;
        this.secondHalf = !this.secondHalf;
      } else {
        this.secondHalf = !this.secondHalf;
      }
      if (this.selectedMonth > 12) {
        this.selectYear += 1;
        this.selectedMonth = 1;
      }
    },
    getMonth(date) {
      const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
      return months[date.getMonth()];
    },
    getWeekDay(date) {
      const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    	return days[date.getDay()];
    },
    setUpdateData(userId, day, event) {
      const key = this.dataKey(userId, day);
      const value = event.target.value;
      
      if (this.saved[key] !== value) {
      	this.$set(this.updateData, key, value);
      } else {
      	this.$delete(this.updateData, key);
      }
    },
    save() {
			// Presumably, this would go somewhere that would refresh saved, but
      // the ultimate effect is just to copy the updateData into saved and
      // empty updateData
			Object.assign(this.saved, this.updateData);
      this.updateData = {};
		},
    dataKey(userId, day) {
    	return `${userId},${this.convertDateString(day)}`;
    },
    convertDateString(date) {
      let isoWithTimezone = new Date(
        date.getTime() - date.getTimezoneOffset() * 60000
      ).toISOString();
      return isoWithTimezone.split("T")[0];
    }
  },
  
  computed: {
  	allData() {
    	return Object.assign({}, this.saved, this.updateData);
    },
    getDates() {
      const year = this.selectedYear;
      const month = this.selectedMonth;
      
      let currentDate = new Date(year, month - 1, 1);
      const dates = [];
      
      while (currentDate.getMonth() == month - 1) {
        dates.push(currentDate);
        currentDate = new Date(
        	currentDate.getFullYear(),
          currentDate.getMonth(),
        	currentDate.getDate() + 1
        );
      }
      
      if (this.secondHalf) {
        return dates.slice(15);
      } else {
        return dates.slice(0, 15);
			}
    },
  }
})
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  -moz-appearance: none;
  margin: 0;
}
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <div>
    <p>{{this.selectedYear}} - {{this.selectedMonth}}</p>
    <div>
      <button @click="prevPeriod"> ‹‹ </button>
      <button @click="nextPeriod"> ›› </button>
    </div>
    <div>
      <table id="conTab">
        <tr>
          <td></td>
          <td v-for="(date, key) in getDates" :key="key" style="font-size: 80%;"> {{getWeekDay(date)}}</td>
        </tr>
        <tr>
          <td style="border-top-width: 0px; border-left-width: 0px"></td>
          <td v-for="(date, key) in getDates" :key="key" style="font-size: 80%;"> {{getMonth(date)}} {{date.getDate()}}</td>
        </tr>
        <tbody>
          <tr v-for="(user, i) in users" :key="user.id">
            <td>
              {{user.firstName}}
            </td>
            <td v-for="(day, key) in getDates" :key="key">
              <input type="number" style="width: 35px;" :value="allData[dataKey(user.id, day)]" @change="setUpdateData(user.id, day, $event)">
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <div><button @click="save">SAVE</button></div>
  </div>
  <pre>{{$data}}</pre>
</div>

【讨论】:

  • 感谢您的详尽评论,非常感谢。看看我这样做的方式,你会说我可以做一些更容易的事情吗?我的最终目标是拥有一个看起来非常像 Excel 网格的时间表..
  • 很多工作都与日期有关。我不知道像 moment.js 这样的库是否会简化它。除此之外,没有太多的空间可以变得更容易。
  • 为了清楚起见,在您的代码中,您是否建议我将数据从updateData 发送到我的后端?因为如果我要保存从updateDatasaved 的所有内容,然后将saved 对象发布到后端,那么什么都没有真正改变——saved 仍将保留所有值,从之前和新更新一个
  • 您将updateData 发送到您的后端。将其放入saved 只是为了反映它现在已保存数据的事实。
  • 嘿,罗伊,我能问你关于 :value@change 的整个逻辑吗 - 不完全确定我掌握了这一切是如何运作的。 @change 值存储输入值和 user.id + 日期,但我不确定 if (this.saved[key] !== value) 做了什么。
猜你喜欢
  • 1970-01-01
  • 2018-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-21
  • 1970-01-01
  • 2018-06-01
  • 2015-08-26
相关资源
最近更新 更多