Customizing the appearance of a date input field by passing an object with Vue.js

I created a dynamic table using Vuejs, where each cell contains an input element set as readOnly initially. The table also includes an 'edit' button for each row, which, when clicked, changes to 'save' and allows editing of the input elements in that specific row. I am trying to capture both the new and previous values entered after clicking save. One particular challenge I'm facing is with formatting dates - the date field is originally in this format 2019-10-10T07:00:00Z, but I want it displayed as mm/dd/yy. Although Moment.js helps me format the date successfully, the value doesn't seem to stay consistent after alerting it. Any suggestions on what I might be doing wrong? Perhaps I need to rethink my approach due to the necessity of extracting the new and previous values for each field.

<div id="app">
<table border=1 width=100%>
  <tr>
    <td>EDIT</td>
    <td v-for="editableKey in editableKeys" :key="editableKey" class="label">{{ editableKey }}</td>
  </tr>
  <tr v-for="(program, index) in programs">
    <td><button v-if="program.isReadOnly" v-on:click="editItem(program)">edit</button>&nbsp;<button @click="saveItem(program)" v-else>save</button></td>    
    <td><input type="text" v-bind:data-id="program.id" :readonly="program.isReadOnly" v-model="formatDate(program)"></td>  
    <td><input type="text" v-bind:data-id="program.id" :readonly="program.isReadOnly" v-model="program.company"></td>
    <td><input type="text" v-bind:data-id="program.id" :readonly="program.isReadOnly" v-model="program.funding"></td>
    <td><input type="text" v-bind:data-id="program.id" :readonly="program.isReadOnly" v-model="program.funded"></td>
    <td><select :class="bgColor(program)" type="text" v-bind:data-id="program.id" :disabled="program.isReadOnly" v-model="program.Recruit">
            <option>Internal</option>
            <option>Recruiting</option>
        </select>
      <!--<input  :class="bgColor(program)" type="text" v-bind:data-id="program.id" :readonly="program.isReadOnly" v-model="program.Recruit">--></td>
    <td><input type="text" v-on:change="" v-bind:data-id="program.id" :readonly="program.isReadOnly" v-model="program.program"></td>    
  </tr>
</table>

</div>



new Vue({
  el:"#app",
  data:() => ({
    programs:[],
    editableKeys: ['date', 'company', 'funding', 'funded', 'recruit', 'program'],
  }),
  created () {
    this.getPrograms();
  },
  methods: {
    getPrograms() {
     axios.get("https://my-json-server.typicode.com/isogunro/jsondb/Programs").then(response => {
       this.programs = response.data.map(program => ({
           ...program,
           isReadOnly: true
       }));
      }).catch(error => {
       console.log(error);
      });
    },
    editItem (program) {
      program.isReadOnly = false
    },
    saveItem (program) {
      program.isReadOnly = true
      console.log(program)
      alert("New Value: "+program.Date)
      alert("Previous Value: "+program.Date)
    },
    bgColor (program) {
      return program.funded === program.funding ? 'yellow' : 'white'
    },
    formatDate(program){
      var formatL = moment.localeData().longDateFormat('L');
      var format2digitYear = formatL.replace(/YYYY/g,'YY');
      return moment(program.Date).format(format2digitYear);
    },
    updateField(program){
      console.log(program)
      alert(program)
    }
  }
})

For more clarity, here's a link to the CodePen demo. Any help or insights provided would be greatly appreciated.

Answer №1

If you desire the input data to be different from what is displayed, you must separate the input from the data.

v-model requires a variable assignment for the input to update its value. Your current usage of v-model="formatDate(program)" will not work as passing a static function result is non-reactive.

There are various ways to achieve this. Here's an example that efficiently accomplishes the task with room for enhancements and alternative implementations...

Replace v-model with value and event listeners

This specifies where the value originates from - a function generating a formatted date. (Note: using functions in templates for rendering is discouraged. It's better to calculate once and use a cached value to avoid unnecessary recalculations.)

<input
  type="text"
  v-bind:data-id="program.id"
  :readonly="program.isReadOnly"
  :value="formatDate(program)"
  @input="updateDate($event, program)"
>

Update Methods

    editItem (program) {
      program.isReadOnly = false
      program.tempDate = null; // added tempDate set to null initially
    },
    saveItem (program) {
      program.isReadOnly = true
      if(program.tempDate !== null) {
        // If tempDate is set, update Date
        program.Date = program.tempDate;
        // Clear tempDate
        program.tempDate = null;
      }
      console.log({...program})
    },
    // New method to convert input value from string to Date (if valid date passed)
    updateDate(e, program ) {
      if(new Date(e.target.value).toString() !== 'Invalid Date'){
        program.tempDate = new Date(e.target.value)
      } else {
        program.tempDate = null
      }
    },

Update

As mentioned, utilizing functions for formatting values in templates is not recommended. Instead, reformat the data before usage (refer to the map function). Once the data is correctly formatted, utilize v-model, noting that this example does not validate the date format.

function toDDMMYY(date) {
  const [y, m, d] = (new Date(date)).toISOString().slice(0, 10).split('-')
  return `${d}/${m}/${y%100}`
}
new Vue({
  el: "#app",
  data() {
    return {
      test: "hello",
      programs: "",
      hide: true,
      editable: [],
    }
  },
  created: function() {
    this.getPrograms();
  },
  methods: {
    getPrograms: function() {
      axios.get("https://my-json-server.typicode.com/isogunro/jsondb/Programs").then((response) => {
          this.programs = response.data.map(row => ({
            ...row,
            dateFormatted: toDDMMYY(row.Date),
            editable: false
          }));
        })
        .catch(function(error) {
          console.log(error);
        });
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>

<div id="app">
  <table border=1 width=100%>
    <tr>
      <td width=10px>EDIT</td>
      <td>Date</td>
      <td>Program</td>
      <td>Company</td>
      <td>Funding</td>
      <td>Funded</td>
      <td>Recruit</td>
    </tr>
    <tr v-for="program in programs">
      <td>
        <button v-if="program.editable == false" @click="program.editable = true">edit</button>
        <button v-else @click="program.editable = false">save</button>
      </td>
      <td><input type="text" v-bind:data-id="program.id" :readonly="!program.editable" v-model="program.dateFormatted"></td>
      <td><input type="text" v-bind:data-id="program.id" :readonly="!program.editable" v-model="program.program"></td>
      <td><input type="text" v-bind:data-id="program.id" :readonly="!program.editable" v-model="program.company"></td>
      <td><input type="text" v-bind:data-id="program.id" :readonly="!program.editable" v-model="program.funding"></td>
      <td><input type="text" v-bind:data-id="program.id" :readonly="!program.editable" v-model="program.funded"></td>
      <td><input type="text" v-bind:data-id="program.id" :readonly="!program.editable" v-model="program.Recruit"></td>
    </tr>
  </table>

</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I display base64 image data in a new window without triggering a block?

Currently experiencing challenges with Javascript. Utilizing html2canvas to convert a div to a canvas and then using .toDataURL to convert the canvas to a base64 data stream. Attempting to open base64 image data in a new window, but facing blocks from va ...

Managing server JSON objects in Adobe AIR

I am facing an issue with a script that fetches objects from a remote server using an Ajax call. The server sends back objects in JSON format. However, while working on Adobe AIR, I encountered a restriction on utilizing eval() due to security concerns. As ...

Unable to retrieve data from the database within PHP code

I have successfully built a shopping cart website utilizing SQL, HTML, and PHP. Below is the code snippet for the 'Add to Cart' button: <form method="post" action="cart.php" class="form-inline"> <input type="hidden" value="&apos ...

Using Vue.js 3 to fetch data from a REST API using the Axios

How do I properly retrieve and display an array using axios.get in Vue? The data is not showing up in my table cells when I use the v-for directive. Could the issue be related to the v-for statement? <tr v-for="params in form" :key=" ...

Dealing with duplicate entries in a dropdown menu when receiving a JavaScript AJAX response

I am attempting to display multiple selected values in a dropdown list that are coming from a database. The contents of my dropdown list are dependent on another dropdown list. Here is the JS code I am using: var cityName = <?= json_encode($cityName); ...

The CSRF token in Laravel Blade seems to be unreachable by Vue

Having a blade with the following code snippet. <meta name="csrf-token" content="{{ csrf_token() }}"> <covid-form> </covid-form> Inside the covid-form component, there is a form structure like this: <form @submit.prevent="send"&g ...

Is it possible to alter the HTML structure using JavaScript?

Looking to shift the positions of 2 divs using JavaScript DOM manipulation, all without altering the HTML. <div class="div1"> this should move downwards</div> <div class="div2"> while this should move upwards</div&g ...

Personalized configurations from the environment in the config.json file

I need to dynamically populate a setting object in my config.json file based on environment variables. The settings should vary depending on the environment. "somesetting": { "setting1": "%S1%", "setting2": "%S2%" } I am currently working on Wind ...

Pattern for either one or two digits with an optional decimal point in regular expressions

Currently, I'm utilizing for input masking. I am specifically focusing on the "patterns" option and encountering difficulties while trying to create a regex expression for capturing 1 or 2 digits with an optional decimal place. Acceptable inputs: ...

Implementing a function to save a file to a nested directory in node.js

Currently, I'm utilizing node and express with the following directory structure: public img css js server.js Within server.js, I have the code snippet below for writing to a png file: fs.writeFile('testfile.png', imageData, func ...

Error message: "Unassigned value in knockout.js"

Here is my code snippet for binding to a textbox: var CategoryViewModel = { categoryModel: ko.observable({ categoryId: ko.observable(), categoryName: ko.observable(), active: ko.observable() }), GetCategoryById: functio ...

In the event of a 404 error on Nuxt, users should be automatically redirected

I need a solution for always redirecting to the homepage in Nuxt.Js when a non-existent page is accessed. Recently, our sitemap generation had some issues and incorrect URLs were submitted, resulting in numerous 404 errors according to Google Search Consol ...

"Step-by-step guide on adding and deleting a div element with a double click

$(".sd").dblclick(function() { $(this).parent().remove(); }); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <table width="750" border="0" cellpadding="0" cellspacing="0"> <tr> <t ...

The script in Vue.js Build.js keeps running indefinitely

'use strict' require('./check-versions')() process.env.NODE_ENV = 'production' const ora = require('ora') const rm = require('rimraf') const path = require('path') const chalk = require('ch ...

jQuery .click() only triggering upon page load

I've been searching all over the place and I just can't seem to find a solution to my specific situation. But here's what I'm dealing with: Instead of using inline HTML onclick, I'm trying to use jQuery click() like this $(docume ...

What steps do I need to follow to utilize LiveReload with an AngularJS templateURL?

Is there a way to trigger the reload of templateURL when using LiveReload and Grunt? angular.module('meshApp', [ 'ngSanitize', 'ngRoute' ]) .config(function ($routeProvider) { $routeProvider .when('/&apos ...

Similar to the reference of $(this) in jQuery, there is a similar concept in Vue.js

When working with jQuery, the use of $(this) allows for accessing elements without relying on classes or ids. How can we achieve a similar outcome in Vue.js? ...

Unable to perform surveillance on the htpp.get method

Example snippet: if (!this.scope.popupHtmlTemplate) { this.$http.get("widgets/pinpointcomponent/browseLibraries/resources/browseLibrariesDialogModal.html") .success((data: any) => { console.log("Processing success"+data) if (dat ...

Verify if a specific key is present in associative arrays

Can you please explain the correct way to check for the existence of a key in associative arrays? For instance: var mydata = { key1: '', key2: { subkey1: { subkey1_1: { value1: '' ...

Vanilla JavaScript code that utilizes regex to transform JSON data into an array of blocks, while disregarding any

As I searched through various resources on converting JSON into arrays using JavaScript, none of the results matched my specific requirements (outlined below). I am in need of a RegEx that can transform JSON into an array containing all characters such as ...