Vue.js versatile form for both adding and editing

As a newcomer to the world of vue.js, I am currently working on expanding some tutorials that I have completed. After struggling with this for three hours now, I must admit that I am feeling quite frustrated. Just to give you a heads up, I am using firebase, although I am not entirely sure if that information is relevant in this context.

So, here's what I have: a basic CRUD app for listing movies. There is a form at the top of the page where users can add movies, and below it, there is a table displaying the newly added entries. So far, everything seems to be functioning smoothly.

I recently introduced Edit and Delete buttons to each row on the table. While the delete function is working as expected, I am encountering an issue with the Edit function.

The main challenge lies in my attempt to use v-if on the initial form in order to trigger different methods (such as save and edit) and display different buttons (Add, Save, Cancel).

I've been experimenting with various approaches to access the objects required for this operation, but unfortunately, I keep running into errors where the object is deemed undefined by v-if.

Thank you for taking the time to read this. Please feel free to ask any questions if you require further clarification or details.

import './firebase' // storing credentials and initializing firebase
import Vue from 'vue'
import App from './App'
import VueFire from 'vuefire'

Vue.use(VueFire)
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})
<template>
  <div id="app" class="container">
    <div class="page-header">
      <h1>Vue Movies</h1>
    </div>
 
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3>Add Movie</h3>
      </div>
 
      <div class="panel-body">

        <div v-if="!isEditing">
          <form id="form" class="form-inline" v-on:submit.prevent="addMovie">
            <div class="form-group">
              <label for="movieTitle">Title:</label>
              <input type="text" id="movieTitle" class="form-control" v-model="newMovie.title">
            </div>
            <div class="form-group">
              <label for="movieDirector">Director:</label>
              <input type="text" id="movieDirector" class="form-control" v-model="newMovie.director">
            </div>
            <div class="form-group">
              <label for="movieUrl">URL:</label>
              <input type="text" id="movieUrl" class="form-control" v-model="newMovie.url">
            </div>
            <input type="submit" class="btn btn-primary" value="Add Movie">
          </form>
        </div>

        <div v-else>
          <form id="form" class="form-inline" v-on:submit.prevent="saveEdit(movie)">
            <div class="form-group">
              <label for="movieTitle">Title:</label>
              <input type="text" id="movieTitle" class="form-control" v-model="movie.title">
            </div>
            <div class="form-group">
              <label for="movieDirector">Director:</label>
              <input type="text" id="movieDirector" class="form-control" v-model="movie.director">
            </div>
            <div class="form-group">
              <label for="movieUrl">URL:</label>
              <input type="text" id="movieUrl" class="form-control" v-model="movie.url">
            </div>
            <input type="submit" class="btn btn-primary" value="Save">
            <button v-on:click="cancelEdit(movie['.key'])">Cancel</button>
          </form>
        </div>

      </div>

    </div>
 
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3>Movies List</h3>
      </div>
      <div class="panel-body">
        <table class="table table-stripped">
          <thead>
            <tr>
              <th>Title</th>
              <th>director</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="movie in movies">

              <td>
                <a v-bind:href="movie.url" v-bind:key="movie['.key']" target="_blank">{{movie.title}}</a>
              </td>
              <td>
                {{movie.director}}
              </td>
              <td>
                <button v-on:click="editMovie(movie)">Edit</button>
              </td>
              <td>
                <button v-on:click="removeMovie(movie)">Remove</button>
              </td>

            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </div>
</template>

<script>

import { moviesRef } from './firebase'

export default {
  name: 'app',
  firebase: {
    movies: moviesRef
  },
  data () {
    return {
      isEditing: false, // could this potentially help?
      newMovie: {
        title: '',
        director: '',
        url: 'http://',
        edit: false // perhaps this??
      }
    }
  },
  methods: {
    addMovie: function() {
      moviesRef.push( this.newMovie )
      this.newMovie.title = '',
      this.newMovie.director = '',
      this.newMovie.url = 'http://'
      this.newMovie.edit = false
    },
    editMovie: function (movie){
      moviesRef.child(movie['.key']).update({ edit:true }); // struggling with accessing this particular section using v-if, unclear why
      //this.newMovie = movie;
    },
    removeMovie: function (movie) {
      moviesRef.child(movie['.key']).remove()
    },
    cancelEdit(key){
      moviesRef.child(key).update({ edit:false })
    },
    saveEdit(movie){
      const key = movie['key'];
      moviesRef.child(key).set({
        title    : movie.title,
        director : movie.director,
        url      : movie.url,
        edit     : movie.edit
      })
    }
  }
}

</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Answer №1

Make sure to set the isEditing variable to true once the user clicks on the Edit button, and be sure to define the movie data.

editMovie: function (movie){
  ...
  this.movie = Vue.util.extend({}, movie); // Use deep cloning to avoid altering the original object
  this.isEditing = true;
},

Answer №2

Following the advice given in the response (from Ben), I included the movie declaration within the initial data object. The updated code now appears as follows:

data () {
    return {
      isEditing: false,
      newMovie: {
        title: '',
        director: '',
        url: 'http://',
        edit: false
      },
      movie: {
        edit: false
      }
    }
  },

The usage of v-if now functions correctly, illustrated by this example:

<div v-if="!movie.edit">

The variable "is Editing" was deemed unnecessary and thus has been eliminated.

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

Creating HTML content in TypeScript with NativeScript using document.write()

Essentially, I am looking to create a set number of labels at various row and column positions depending on the user's input. However, I have been unable to find any resources that explain how to write to the .component.html file from the .component.t ...

What is the best method for ensuring image orientation is displayed correctly?

When utilizing multer node and express for uploading images to my application, I've noticed that some of the images appear rotated 90 degrees once they reach the client side. What could be causing this issue, and how can I resolve it? Just to clarif ...

Is it possible to access JSON with a numeric key and receive undefined as a result?

I've been attempting to extract information from my JSON data, but I keep getting an undefined result. Here is a snippet of my JSON: { "1": "A", "2": "B", "3": "C", "4": "D", "5": "E", "6": "F", "key":"pair" } This i ...

Using AngularJS to create a select dropdown menu with nested objects as the options

Currently, I am working on developing an AngularJS application with a complex data structure. The data source consists of an array of individuals with their languages and skill levels. My goal is to be able to filter these individuals based on language sk ...

Unable to render page with scrapy and javascript using splash

I am currently trying to crawl this specific page. Following a guide on Stack Overflow to complete this task, I attempted to render the webpage but faced issues. How can I resolve this problem? This is the command I used: scrapy shell 'http://local ...

Sharing models between AngularJS controllers

I am currently in the process of developing an application that will showcase various charts and controls to filter the presented data. I have structured the HTML page in a way that remains consistent throughout, leading me to consider creating an HTML tem ...

Is it possible to utilize a conditional statement in my EJS document to determine a directory path within my Node.js and Express application?

Just starting out with EJS and I'm trying to create a conditional statement. Basically, what I want is if I am on a specific directory path, then replace a link in my navigation bar. <% let url = window.document.URL; if(!url.includes(&a ...

``From transitioning from Django templating to implementing a full RESTful architecture?

Looking to convert my django/html/css website to a REST (json) structure. Previously reliant on django template rendering for frontend responses. Interested in how to manage url redirection and incorporate json data into html templates without the use of ...

Leveraging Multiple MongoDB Databases in Meteor.js

Can 2 Meteor.Collections fetch data from separate MongoDB database servers? Dogs = Meteor.Collection('dogs') // mongodb://192.168.1.123:27017/dogs Cats = Meteor.Collection('cats') // mongodb://192.168.1.124:27017/cats ...

Effective monitoring of dependencies in a personalized connection

My goal is to implement a method to visually filter table rows generated by the foreach binding. I want the filtered out rows to be hidden instead of removed from the DOM, as this can greatly improve rendering performance when filter conditions are changed ...

Leveraging Angular for Remote Configuration Management

How is everything going with you? I'm attempting to retrieve a configuration that I previously set up in Firebase's remote config using my Angular 15 application. The specific configuration is called "AllowedUsers." Here is the image of th ...

Tips for customizing column width in v-simple-table with Vuetify.js component

For my most recent projects UI component, I decided to use vuetify.js. I attempted to adjust the width of the th and td elements within a v-simple-table using CSS, but unfortunately, nothing seemed to happen. My goal was to set the width of every th and td ...

access the database information within the fullcalendar plugin

I've been exploring the calendar code on arshaw/fullcalendar and made some modifications, but I'm still unsure how to link JavaScript with a database. Here is the original code: $(document).ready(function() { var date = new Date(); var d = dat ...

Steps for ensuring a promise is fulfilled in Node.js and Firebase

I've been struggling with this issue for quite some time now and can't seem to figure it out. g_globalList.once("value").then(function(tickList){ var multiPaths = []; tickList.forEach(function(ticker){ ticker.val().forEach(fu ...

Ways to retrieve an input field value without triggering form submission

I'm currently working on a payment form where users input the amount in a text field. I also have another text field on the same form that should automatically display the amount in words based on the user input. However, I'm struggling to figure ...

tips for navigating through an AngularJS $resource instance

I am facing a frustrating issue that I need assistance with. The problem arises when I try to extract specific data from each element of the stock data fetched by my controller from Yahoo Stocks. Although the data is stored in $scope.stocks and can be disp ...

MUI Alert: Encountered an Uncaught TypeError - Unable to access properties of undefined when trying to read 'light' value

After utilizing MUI to create a login form, I am now implementing a feature to notify the user in case of unsuccessful login using a MUI Alert component. import Alert from '@mui/material/Alert'; The code snippet is as follows: <CssVarsProvide ...

The returned state from setState(prev) seems to be in the opposite order when referencing another useState variable within a useEffect

As part of my interactive chat simulation project, I have implemented a feature where users can click on a button named obj4 to start their chat session. Initially, everything functions smoothly, displaying messages 1-4 in the correct order. However, when ...

What steps can be taken to disable Angular's automatic trimming of fields?

Is there a global way to prevent Angular from automatically trimming input fields throughout the entire application? I know that I can avoid it for specific fields using the ngTrim directive, but it's not ideal to add this directive to every text fiel ...

Tips for creating AngularJS nested transcludes

I'm currently delving into the world of angular directives/transclusion to manage the creation of custom panels within my application. Unfortunately, I seem to have hit a roadblock as the transcluded content is not displaying in the HTML. Below is th ...