CRUD app - issues with updating items

CRUD app - issues with updating items
0

i am trying to create javascript CRUD app.When i load the page i am getting data (contacts) from the JSON server which show in the UI.Each contact has it s own name, email, phone and type.I am also able to delete or add new contacts.Since i am using HTTP requests i am manipulating them both in the UI and on the JSON server.However i am having problems when i want to update any of the particular contacts.If possible i would ask you to check updateContact() function in the app.js and tell me what i am doing wrong.I would also appreciate if you can tell me specific solution if possible in code instead of giving me general advice because at this point i feel lost.
I know i ask a lot.Thanks.
Github repo:

@ivan3928 When I run your project locally, I see an error in the browser console related to the following line:

document.querySelector(".update").addEventListener("submit", updateContact);

You need to resolve this error first. You are attempting to add an event listener to an element that has a class of “update”, but there is no such element.

ui.js

updateButton() {
    this.submitButton.className = "btn btn-block green darken-2 update";
  }

When i click edit button submit changes it s class to update

But when the page loads, the edit button has not yet been clicked, so there is no “update” class on an element to be able to add the event listener. That is why you get the error.

Plus, you still would have the other event listener (the one one the submit button) which will still try to fire. That is why a new contact gets added each time the submit button is clicked.

1 Like

Changing the classes of submitButton make it a ‘dynamic element’ (in that .update has become a dynamic property), which are notoriously difficult to attach listeners to. You have a couple options here, which way you go is really a matter of personal preference.

  1. You could attach a submitButtonHandler that simply checks, when the submit button is clicked, whether it has the class update. If so, handle the update action. If not, perform the add action.
  2. You could attach the listener a little higher up the DOM tree, at the nearest static container - but the process would be exactly the same. Check if event.target.classList.contains('update'), and perform a certain action in that instance.
1 Like

Thank you, that was immensely helpful.
app.js

//Submit contact

const submitContact = e => {
  const id = document.querySelector("#id").value;
  const name = document.querySelector("#name").value;
  const email = document.querySelector("#email").value;
  const phone = document.querySelector("#phone").value;
  const type = document.querySelector('input[name="type"]').value;
  const submitButton = document.querySelector("#submit-button");

  const data = {
    name: name,
    email: email,
    phone: phone,
    type: type
  };

  if (submitButton.classList.contains("update")) {
    axios
      .put(`http://localhost:3000/contacts/${id}`, data)
      .then(response => {
        getContacts();
        ui.clearFields();
        ui.removeCancelButton();
        ui.removeSubmitButton();
      })
      .catch(err => console.log(err));
  } else {
    axios
      .post("http://localhost:3000/contacts", data)
      .then(response => {
        getContacts();
        ui.clearFields();
      })
      .catch(err => console.log(err));
  }
  e.preventDefault();
};

document
  .querySelector("#submit-button")
  .addEventListener("click", submitContact);

ui.js

showSubmitButton() {
    this.submitButton.className = "btn btn-block indigo darken-4 update";
  }

  removeSubmitButton() {
    this.submitButton.className = "btn btn-block indigo darken-4 ";
  }

The only thing is that when i am editing contacts i am unable to update it s type which is a part of radio button input.

This would be a part of a larger conversation, I think. It’s getting into retrieving data (which you have down) and updating the HTML to display that data - and how to do that with radio buttons. At least, it seems to me that that’s where things are getting messy.

Do you have this in a codepen or a repl? When you go to edit an existing contact, when you display that edit form, are you displaying the proper radio button? Is the problem that you can’t figure how to display that, or that the updated value isn’t being read in the submitContact function?

Yes, i know it s a mess…When i was starting this project i knew that i was going to have issues with this, so i ll try to be as concise as i can.
My problem is two fold.
When i click on edit button and call editContact function i am getting that radio input value in the console but not in the UI.You can try it yourself, just comment off console.log in that function.
The second problem is that the updated value isn’t being read in the submitContact function.I am always getting value of default checked input which is “personal”.
That goes when i want to POST data as well.
I think that the main problem is how to properly select value of a input that i want to check.
This is the syntax that i was using throughout this project:

const type = document.querySelector('input[name="type"]').value;

I have updated my Github repo for this project so you can check it there if you wish.In the meantime here are the snippets of the code.
HTML

 <!--Radio buttons-->
            <p>
              <label>
                <input name="type" type="radio" value="personal" checked />
                <span>Personal</span>
              </label>
              <label>
                <input name="type" type="radio" value="profesional" />
                <span>Profesional</span>
              </label>
            </p>

app.js

//Edit contact

const editContact = e => {
  if (e.target.parentElement.classList.contains("edit")) {
    const id = e.target.parentElement.dataset.id;
    const name =
      e.target.parentElement.parentElement.previousElementSibling
        .previousElementSibling.previousElementSibling.previousElementSibling
        .children[0].textContent;
    const email =
      e.target.parentElement.parentElement.previousElementSibling
        .previousElementSibling.previousElementSibling.textContent;
    const phone =
      e.target.parentElement.parentElement.previousElementSibling
        .previousElementSibling.textContent;
    const type =
      e.target.parentElement.parentElement.previousElementSibling
        .previousElementSibling.previousElementSibling.previousElementSibling
        .children[1].textContent;

    const data = {
      id: id,
      name: name,
      email: email,
      phone: phone,
      type: type
    };

    ui.fillForm(data);
    ui.showCancelButton();
    ui.showSubmitButton();

    console.log(data);
  }
  e.preventDefault();
};

document.querySelector("#contact-list").addEventListener("click", editContact);

//Submit contact

const submitContact = e => {
  const id = document.querySelector("#id").value;
  const name = document.querySelector("#name").value;
  const email = document.querySelector("#email").value;
  const phone = document.querySelector("#phone").value;
  const type = document.querySelector('input[name="type"]').value;
  const submitButton = document.querySelector("#submit-button");

  const data = {
    name: name,
    email: email,
    phone: phone,
    type: type
  };

  if (submitButton.classList.contains("update")) {
    axios
      .put(`http://localhost:3000/contacts/${id}`, data)
      .then(response => {
        getContacts();
        ui.clearFields();
        ui.removeCancelButton();
        ui.removeSubmitButton();
      })
      .catch(err => console.log(err));
  } else {
    axios
      .post("http://localhost:3000/contacts", data)
      .then(response => {
        getContacts();
        ui.clearFields();
      })
      .catch(err => console.log(err));
  }
  e.preventDefault();
};

document
  .querySelector("#submit-button")
  .addEventListener("click", submitContact);

ui.js

showContacts(contacts) {
    let output = "";

    contacts.forEach(contact => {
      output += `
      <divclass="row contact-row">
      <div class="col s12">
      <div class="card">
      <div class="card-content">
      <p class="card-title indigo-text text-darken-4"><span>${contact.name}</span>
      
      <a class="waves-effect indigo darken-4 btn right"> ${contact.type}</a>
      
      </p>
      <p><i class="fas fa-envelope-open"></i> ${contact.email}</p>
      
      <p><i class="fas fa-phone"></i> ${contact.phone}</p>
      <br>
      <p>
      <a class="waves-effect grey darken-4 btn-flat edit" data-id="${contact.id}"><span class="white-text">Edit</span></a>
  <a class="waves-effect red darken-2 btn-flat delete" data-id="${contact.id}"><span class="white-text">Delete</span></a>
      </p>
      </div>
      </div>
      </div>
      </div>`;
    });
    this.contactList.innerHTML = output;
  }

This is how you get text node from a checked radio button.It works now.I am able to update value of radio buttons along with text inputs.I thought it might interest you.

const type = document.querySelector('input[name="type"]:checked')
    .parentElement.textContent;

Thanks for all of your help.

why would you not just get the value of the checkbox?

const type = document.querySelector('input[name='type']:checked').value;

And how you set the radiobuttons to show the selected (assuming they all have the same set of radio buttons) would be much the reverse:

// let's assume the variable type==="personal"
// This selector will find the radiobutton with the value "Personal", and check it.
document.querySelector(`input[type='radio'][value='${type}']`).setAttribute("checked", "checked");
1 Like