skip to Main Content

I am trying to edit a post and dynamicaly update the Dom with my editPost function
(The posts are created with another Javascript function).

function editPost(post_id){

  // get the post text
  const post_element = document.getElementById(post_id);
  const post_text_element = post_element.querySelector('p.card-text');
  const post_text = post_text_element.textContent.trim();

  console.log(post_text_element)

  // create the textarea and populate it with the content of the post
  const textarea = document.createElement('textarea');
  textarea.setAttribute('rows', 3);
  textarea.setAttribute('cols', 50);
  textarea.setAttribute('id', `edit-post-${post_id}`);
  textarea.value = post_text;

  // create the save button and add Event Listener
  const save_button = document.createElement('button');
  save_button.textContent = 'Save';

  save_button.addEventListener('click', () => {
    
    const new_post_text = textarea.value;
    
    fetch('/update_post/' + post_id, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ new_text: new_post_text })
    })
    .then(response => response.json())
    .then(data => {
      const updated_post_text = data.new_text;
      const updated_post_element = document.createElement('p');
      updated_post_element.className = "card-text";
      updated_post_element.textContent = updated_post_text;

      post_element.replaceChild(updated_post_element, textarea);
      post_element.removeChild(save_button);

    });
  });

    post_element.replaceChild(textarea, post_text_element);
    post_element.appendChild(save_button);    

}

but when clicking the Edit button I get an error in the console pointing to the post_element.replaceChild at the bottom saying:

Uncaught DOMException: Failed to execute ‘replaceChild’ on ‘Node’: The
node to be replaced is not a child of this node.
at editPost (http://127.0.0.1:8000/static/network/index.js:214:18)
at HTMLButtonElement.onclick (http://127.0.0.1:8000/:75:9) editPost @ index.js:214 onclick @ (index):75

dont really get it…
Post_text_element is a html paragraph element
console.log(post_text_element) shows the right element.

below you can see the creation of the post_element
post_text_element is in the middle with class name "card-text"

// create a div element for each post
    posts.forEach(post => {
        let cardDiv = document.createElement('div');
        cardDiv.className = "card";
        cardDiv.setAttribute('id', post['id']);
        cardDiv.innerHTML = `
        <div class="card-body">
          <div class="row card-title">
            <span class="col">
              <a id="user-link" href="profile/${post['user'][0].username}">
                <h6>${post['user'][0].username}</h6>
              </a>
            </span>
            <h7 class="col d-flex justify-content-end card-subtitle mb-2 text-muted">${post['timestamp']}</h7>
          </div>

          <p class="card-text">${post['text']}</p>

          <div class="row">
            <div class="col d-flex justify-content-start">
              <button class="like-button" onclick="likePost(${post.id});">
                ♥ 
                <span class="like-count">${post['total_likes']}</span>
              </button>
            </div>
            ${post['user'][0].id == request_user_id ? 
              `<span class="col d-flex justify-content-end">
                <button class="edit-button" onclick="editPost(${post.id});">Edit</button>
              </span>` : ''}
          </div>
        </div>
        `;

2

Answers


  1. For Node.replaceChild(newChild, oldChild), Node must be the immediate parent of oldChild. In your code, oldChild is post_text_element but its parent is <div class="card-body">, which is not post_element (post_element is <div class="card" id=…>). Instead of calling the .replaceChild() method on post_element, get the parent of post_text_element with .parentElement and then call .replaceChild() on that like:

    function editPost(post_id){
    
      // get the post text
      const post_element = document.getElementById(post_id);
      const post_text_element = post_element.querySelector('p.card-text');
      const post_text = post_text_element.textContent.trim();
    
      console.log(post_text_element)
    
      // create the textarea and populate it with the content of the post
      const textarea = document.createElement('textarea');
      textarea.setAttribute('rows', 3);
      textarea.setAttribute('cols', 50);
      textarea.setAttribute('id', `edit-post-${post_id}`);
      textarea.value = post_text;
    
      // create the save button and add Event Listener
      const save_button = document.createElement('button');
      save_button.textContent = 'Save';
    
      save_button.addEventListener('click', () => {
        
        const new_post_text = textarea.value;
        
        fetch('/update_post/' + post_id, {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ new_text: new_post_text })
        })
        .then(response => response.json())
        .then(data => {
          const updated_post_text = data.new_text;
          const updated_post_element = document.createElement('p');
          updated_post_element.className = "card-text";
          updated_post_element.textContent = updated_post_text;
    
          post_element.replaceChild(updated_post_element, textarea);
          post_element.removeChild(save_button);
    
        });
      });
    
        post_text_element.parentElement.replaceChild(textarea, post_text_element);
        post_element.appendChild(save_button);    
    
    }
    <div class="card" id=0>
      <div class="card-body">
        <div class="row card-title">
          <span class="col">
          <a id="user-link" href="profile/${post['user'][0].username}">
            <h6>${post['user'][0].username}</h6>
          </a>
        </span>
          <h7 class="col d-flex justify-content-end card-subtitle mb-2 text-muted">${post['timestamp']}</h7>
        </div>
    
        <p class="card-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed leo mi, hendrerit vitae quam sit amet, gravida mattis odio. Etiam fermentum vitae leo vitae gravida. Quisque id dolor sit amet risus semper fermentum at id tellus. Nam nisl magna, lobortis
          sed egestas eget, varius at nibh. Sed vestibulum rhoncus felis in sodales.</p>
    
        <div class="row">
          <div class="col d-flex justify-content-start">
            <button class="like-button" onclick="likePost(${post.id});">
            ♥ 
            <span class="like-count">${post['total_likes']}</span>
          </button>
          </div>
          <span class="col d-flex justify-content-end">
          <button class="edit-button" onclick="editPost(0);">Edit</button>
        </span>
        </div>
      </div>
    </div>

    You may also need to do something similar within the save_button.addEventListener() callback too.

    Login or Signup to reply.
  2. The node to be replaced is not a child of this node

    So probably you’ll need the parent. I have tried to boil your code down to a minimal reproducable example. Maybe it helps.

    document.addEventListener(`click`, handle);
    
    function handle(evt) {
      if (evt.target.id === `bttn`) {
        const newTextarea = Object.assign(
          document.createElement(`textarea`), {
            className: `card-text`,
            textContent: `${new Date().toLocaleString()}nSome new text!`
          });
        const oldText = document.querySelector(".card-text");
        oldText.parentNode.replaceChild(newTextarea, oldText);
        //      ^ the parent
      }
    }
    <div>
      <div>
        <span>
            <h6>Pete</h6>
        </span>
        <h7></h7>
      </div>
    
      <p class="card-text">The original text</p>
    
      <div>
        <div>
          <button>♥<span>0 likes</span></button>
        </div>
      </div>
    </div>
    
    <p>
      <button id="bttn">replaceChild Example</button>
    </p>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search