JavaScript - unable to view updated information without refreshing page

I am currently developing a Single Page Application (SPA) using Rails for the backend and JavaScript for the frontend. When I submit the initial form to create a Resource, it shows up on the page immediately upon pressing the submit button. However, when I try to edit the Resource, I have to refresh the page to see the updated information.

Is there a way to make sure that the updated Resource is displayed on the page without needing to refresh?

index.js

const materialIndex = "http://localhost:3000/api/v1/materials"
const categoryIndex = "http://localhost:3000/api/v1/categories"

document.addEventListener('DOMContentLoaded', () => {
    getMaterials()

    const createMaterialForm = document.querySelector("#create-material-form")

    createMaterialForm.addEventListener("submit", (e) => createFormHandler(e))

    const materialContainer = document.querySelector('#material-container')
    materialContainer.addEventListener('click', e => {
        //debugger
        const id = parseInt(e.target.closest('[data-id]').dataset.id)
        const material = Material.findById(id)
      ​  document.querySelector('#edit-material').innerHTML = material.renderPatchForm()
        console.log(material)
    })
    document.querySelector('#edit-material').addEventListener('submit', e => updateForm(e))
})

function getMaterials() {
    fetch(materialIndex) //get request
    .then(response => response.json())
    .then(materials => {
        materials.data.forEach(material => {
            let newMaterial = new Material(material, material.attributes)
                document.querySelector('#material-container').innerHTML += newMaterial.renderMaterialCard()
        })
        
    })
}

function createFormHandler(e) { 
    e.preventDefault()
    const nameInput = document.querySelector('#input-name').value
    const descriptionInput = document.querySelector('#input-description').value
    const urlInput = document.querySelector('#input-url').value
    const categoryId = parseInt(document.querySelector('#categories').value)
    postFetch(nameInput, descriptionInput, urlInput, categoryId)
}

function updateForm(e) {
    e.preventDefault()
    const id = parseInt(e.target.closest('[data-id]').dataset.id)
    const material = Material.findById(id)
    const name = e.target.querySelector('#input-name').value
    const description = e.target.querySelector('#input-description').value
    const url = e.target.querySelector('#input-url').value
    const category_id = parseInt(e.target.querySelector('#categories').value)
    patchMaterial(material, name, description, url, category_id)
}

function postFetch(name, description, url, category_id) {
    const bodyData = {name, description, url, category_id}
    fetch(materialIndex, {
        method: "POST",
        headers: {"Content-Type": "application/json"},
        body: JSON.stringify(bodyData)
    })
    .then(response => response.json())
    .then(material => {
        const materialData = material.data
        let newMaterial = new Material(materialData, materialData.attributes)
      ​  document.querySelector('#material-container').innerHTML += newMaterial.renderMaterialCard()
    })
}

function patchMaterial(material, name, description, url, category_id) {
    const patchJSON = {name, description, url, category_id}
    fetch(`http://localhost:3000/api/v1/materials/${material.id}`, {
        method: 'PATCH',
        headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
        },
        body: JSON.stringify(patchJSON),
    })
    .then(response => response.json())
    .then(material => {
        const materialData = material.data
      
        let newMaterial = Material(materialData, materialData.attributes)
      ​  document.querySelector('#material-container').innerHTML += newMaterial.renderMaterialCard()
    })
}

material.js

class Material {
    constructor(material, materialAttributes) {
        this.id = material.id
        this.name = materialAttributes.name
        this.description = materialAttributes.description
        this.url = materialAttributes.url
        this.category = materialAttributes.category
        Material.all.push(this)
    }

    renderMaterialCard() {
        return `
            <div data-id=${this.id}>
            <h3>${this.name}</h3>
            <p>${this.description}</p>
            <p><small><a href="${this.url}">${this.url}</a></small></p>
            <p>${this.category.title}</p>
            <button data-id=${this.id}>edit</button>
            </div>
          ​  <br><br>`
    }

    static findById(id) {
        return this.all.find(material => material.id == id)
    }


    renderPatchForm() {
        return `
            <form data-id=${this.id} >
                <h2>Edit the Resource</h2>

                <label>Name</label>
                <input id='input-name' type="text" name="name" value="${this.name}" class="input-name">
                <br><br>

                <label>Description</label>
                <textarea id='input-description' name="description" rows="8" cols="80" value="">${this.description}</textarea>
                <br><br>

                <label>URL</label>
                <input id='input-url' type="text" name="url" value="${this.url}" class="input-text">
                <br><br>

                <label>Category</label>
                <select id="categories" name="categories" value="${this.category.name}">
                    <option value="1">Criminal Justice Reform</option>
                    <option value="2">Bail Funds</option>
                    <option value="3">Clothing</option>
                    <option value="4">Organizations</option>
                    <option value="5">Mutual Aid</option>
                    <option value="6">Fundraisers</option>
                    <option value="7">Petitions</option>
                    <option value="8">Articles</option>
                    <option value="9">Artists</option>
                    <option value="10">Instagram</option>
                </select>
                <br><br>

                <input id='edit-button' type="submit" name="submit" value="Edit Resource" class="submit">
            </form> `
  }
}

Material.all = []

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Beneficial Resources</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="style.css">
        <script type="text/javascript" src="src/material.js"></script>
        <script type="text/javascript" src="src/index.js"></script>
    </head>
    <body>
        <center>
        <h1>A Space For Resources</h1>
        <h5>An open space that hosts resources dedicated to urgent issues around the World.</h5>
        </center>
        <div class="form-container">
            <form id="create-material-form">
                <h2>Add a new Resource</h2>

                <input id='input-name' type="text" name="name" value="" placeholder="Resource Name" class="input-text">
                <br><br>
                <textarea id='input-description' name="description" rows="8" cols="80" value="" placeholder="Enter the description of your Resource..."></textarea>
                <br><br>
                <input id="input-url" type="text" name="url" value="" placeholder="URL" class="input-text">
                <br>

                <h4>What Category is your Resource?</h4>
                <select id="categories" name="categories">
                    <option value="1">Criminal Justice Reform</option>
                    <option value="2">Bail Funds</option>
                    <option value="3">Clothing</option>
                    <option value="4"& ...

Answer №1

Issue: Event handler added before form is in DOM

The problem seems to be that the event handler

document.querySelector('#edit-material').addEventListener('submit', e => updateForm(e))
for the update form is being added before the form itself is present in the DOM. To solve this, make sure to add the event listener after the form has been added:

const materialContainer = document.querySelector('#material-container')
    materialContainer.addEventListener('click', e => {
        //debugger
        const id = parseInt(e.target.closest('[data-id]').dataset.id)
        const material = Material.findById(id)
        document.querySelector('#edit-material').innerHTML = material.renderPatchForm()
        console.log(material) // Add the line below
        document.querySelector('#edit-material').addEventListener('submit', e => updateForm(e)) // <------ Add this line here!!
    })
    //// document.querySelector('#edit-material').addEventListener('submit', e => updateForm(e)) // remove this line from here

Utilize default Rails functionality

You can avoid rendering a renderPatchForm inline with JavaScript by using plain HTML and Ruby. Consider following the best practices outlined here: .

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

VueJS: interactive input field with dynamic value binding using v-model

I am facing an issue with VueJS regarding setting the value of an input radio along with v-model. I am confused as to why I am unable to dynamically set a value to an input and use a model to retrieve the user's selection. Here is a clearer represent ...

How can I open the Ion-datetime view for the current year without allowing the selection of a specific day?

I am currently troubleshooting an issue with an Ionic date-time picker component. Upon opening the datepicker, it defaults to showing May 2021. As I scroll to the present date, I notice a circle highlighting today's date indicating that it selects th ...

Sending fragmented files straight to Amazon's s3

Currently seeking straightforward examples of uploading directly to Amazon s3 in chunks without any server-side processing, except for signing the request. I have explored various options, but all examples I have found either focus solely on chunking from ...

Developing a custom JavaScript function to iterate through a group of html elements

In my mission to create a function that loops through a set of HTML elements and gathers their values, I aim to then utilize those values to produce an HTML textarea. Thus far, I've established a series of HTML input boxes and a JavaScript function f ...

Leveraging the power of jQuery Ajax in conjunction with node.js and express for email validation functionality

Hey there! I have a contact form on my website that uses ajax for validation and email sending. The issue is that the validation file is set up for PHP, but I'm trying to make it work with my NodeJS app. Unfortunately, when I tried modifying the ajax ...

When using v-for to render an array list fetched from AsyncData, an error is thrown: The virtual DOM tree rendered on the client-side does not match the one

For my application, I am utilizing Nuxt.js. On one of the pages, I am using AsyncData to fetch an array of data objects from my API asynchronously. These data objects are then rendered in my template using v-for. Everything is functioning properly until I ...

minimize javascript syntax (stackoverflow 2022)

I'm struggling with this puzzle game. Sometimes, when I start a new game, the pieces get shuffled incorrectly. I tried adding a function to fix it, but it doesn't seem to be working. It's really frustrating and I want to simplify the code as ...

Modifying an element in an array while preserving its original position

Currently, I am working on updating the state based on new information passed through response.payload. Here is my existing code snippet: if(response.events.includes('databases.*.collections.*.documents.*.update')) { setMemos(prevState => pre ...

Tampermonkey feature: Extract source code with a button click from a constantly updating AJAX page

My goal is to create a simple script that can copy the source code of a dynamic AJAX page whenever I press a button. The current code, which I have included below, seems to be working fine: // ==UserScript== // @require http://ajax.googleapis.com/ajax/li ...

Variable missing in the ExpressJs view

Hey there! I'm new to Nodejs and currently experimenting with it. I've been trying to convert some of my basic Python codes to JavaScript. In one of my projects, I am sending a get request to the YouTube API and receiving 50 results in JSON forma ...

Unable to assign a className to a personalized React component - troubleshooting needed!

I have a component that relies on another component. I am trying to pass CSS positioning from the outer component to the inner one by using the following code: import OptionsMenu from './OptionsMenu' import { withStyles } from 'material-ui/ ...

Cross-building targets for Node modules for deployment on npm platform

I'm working on an ES6 module that needs to be compatible with different environments. I'm not sure whether to use webpack or rollup for building, and how to target specific environments. Building for Different Environments ES6 environments like ...

How can parameters be passed to a JavaScript or jQuery function?

I am currently utilizing a JS/JQ function to convert values into currency by adding commas. Although the function is running smoothly, I am encountering an issue when attempting to pass parameters to it. Kindly provide assistance on how to successfully pas ...

Display complete information of the selected list in a modal window by clicking on it in PHP Yii

I recently started working with the Yii framework and encountered a challenge when trying to pass data from a list to a modal using AJAX. The modal is located within the same view as the list. Here's a snippet of my code: This is my view: <div id ...

Tips on sending a form to the server with ajax technology

I'm struggling with sending a button id to my server through ajax in order to submit a form without having to constantly reload the page every time I click on a button. Unfortunately, it's not working as expected and I can't figure out why. ...

The screen reader seems to be malfunctioning as soon as I include this particular code

//Finding the height of the header let headerHeight = document.querySelector('header'); let height = headerHeight.offsetHeight; //Adjusting the #navbarNav's top margin to accommodate the header let nn = docu ...

What is the best way to paginate a dynamically updated data table using AJAX in Laravel?

I'm currently facing an issue with rendering a Blade template in Laravel. The template includes an HTML table populated with data fetched via AJAX, and I need to implement manual pagination using Laravel's LengthAwarePaginator. The main Blade fi ...

The Dynamic Data Duo: JSON and Python

Currently, I am in the process of creating a web interface for Arduino using Python, with JSON being utilized for automatic updates and display. However, an intriguing issue has arisen. Within the code snippet below, a command is sent to a python function ...

Tips for using jQuery dropdown menus

I am currently in the process of creating a prototype for a quick dropdown menu using jQuery. However, I have reached the limits of my knowledge on jQuery and could use some assistance in solving my issue. My objective is to have a dropdown animate down w ...

Encasing a variety of child elements within a div container

My goal is to group a range of children elements within a div so that I can manipulate them collectively in different locations. The challenge arises from having a list with randomly generated li tags, and no matter how many appear, I need every batch of t ...