1

I am trying to edit/update current data using the contenteditable attribute which I have successfully enabled onclick. My 'enter' key allows the data to be submitted. However, the console.log reads that a PUT request has been made for a particular list item but without the 'title' or 'isbn' being updated along with it.

Another prominent issue is that my console.log shows books.forEach is not a function, and I have no idea why this is the case since the code inside that function is processed.

HTML ('li' items are solely JS-Generated with a POST request)

<div id="divShowBooks">
  <li id="[object HTMLParagraphElement]">
    <p id="24" name="anID" placeholder="24">1</p>
    <p id="TEST" name="aTitle" placeholder="TEST">TEST</p>
    <p id="12345" name="anISBN" placeholder="12345" contenteditable="true">12345</p>
    <button>Delete</button>
  </li>
</div>

JavaScript

var book_list = document.querySelector('#divShowBooks');

    book_list.innerHTML = "";

    var books = JSON.parse(this.response);

    books.forEach(function (book) {

        // Text information to be displayed per item
        var id = document.createElement('p');
        id.type = 'text';
        id.innerHTML = book.id;
        var title = document.createElement('p');
        title.type = 'text';
        title.innerHTML = book.title;

        var isbn = document.createElement('p');
        isbn.type = 'text';
        isbn.innerHTML = book.isbn;

        // Defining the element that will be created as a list item
        var book_item = document.createElement('li');

        // Displays id, title and ISBN of the books from the database
        book_item.appendChild(id);
        book_item.appendChild(title);
        book_item.appendChild(isbn);

        // Creates an ID attribute per list item
        book_item.setAttribute("id", id)

        // Assigns attributes to p items within book items
        id.setAttribute("id", book.id)
        title.setAttribute("id", book.title)
        isbn.setAttribute("id", book.isbn)

        // Adding a generic name to these elements
        id.setAttribute("name", "anID")
        title.setAttribute("name", "aTitle")
        isbn.setAttribute("name", "anISBN")


        title.addEventListener('click', function (e) {
            e.preventDefault();
            title.contentEditable = "true";
            title.setAttribute("contenteditable", true);
            title.addEventListener('keypress', function (e) {
                if (e.keyCode === 13) {
                    e.preventDefault();
                    xhttp.open("PUT", books_url + '/' + book.id, true);
                    var editTitle = new FormData() /
                        editTitle.append("title", document.getElementsByName("aTitle")[0].value)
                    xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
                    xhttp.send(); //
                }
            });
        });

UPDATE

I have added the following to my code. This seems to display my database items as an array in the log. But, I am now having a similar issue with Uncaught TypeError: JSON.parse(...).map is not a function:

var params = [
    id = 'id',
    title = 'title',
    isbn = 'isbn',
    createdAt = 'createdAt',
    updatedAt = 'updatedAt'
];

var books = JSON.parse(this.response).map(function(obj) {
    return params.map(function(key) {
        return obj[key];
    });
});
console.log(books);

UPDATE 2

Here is an image of what I receive in the console.log. The first part displays the original JSON content and the second is my attempt to convert each object into an array.

See Image

AelaHuntress
  • 61
  • 2
  • 9
  • Did you try to dump the books variable to verify it contains an array ( console.log(books);) ? – Goran.it Jan 10 '19 at 08:04
  • .forEach() is an array method. Are you sure your variable is an array even? – Abana Clara Jan 10 '19 at 08:04
  • Your code has some unbalanced brackets. Can you fix it and use proper indentation so we can see the structure? – Barmar Jan 10 '19 at 08:08
  • I have checked within the console.log and it appears that it isn't processed as an array. How would I appropriately change this? – AelaHuntress Jan 10 '19 at 12:26
  • @AelaHuntress You should include the actual data structure of the books you console.log'ed so we can understand what we're looking at – Abana Clara Jan 11 '19 at 01:27
  • @AbanaClara For confidentiality, I am reluctant to show specific database information. However, I have updated the original post. – AelaHuntress Jan 11 '19 at 06:40
  • @AelaHuntress `.map()` is still an array method. If you call it on a non-array variable, it's going to throw a not a function error. – Abana Clara Jan 11 '19 at 06:42
  • @AbanaClara So, how did I make my variable non-array (if that is the needed solution)? – AelaHuntress Jan 11 '19 at 06:49
  • @AelaHuntress You won't be able to loop through it if it isn't an object or an array. This problem is very hard to answer if we won't be able to see the content of `books` – Abana Clara Jan 11 '19 at 06:56

2 Answers2

0

You are getting books from JSON.parse(), which means books is an object and not an array. forEach is an array method. Try console logging books and look for an array inside of it.

0

You have to make sure that your books variable actually contains an Array after parsing.

Alternatively, but this wouldn't make sense, just to address the "books.forEach is not a function" issue, You can use Object.assign([], this.response);. To make sure that books will contain an array, you wrap it in a try catch and make something like this:

var books = [];

try {
    books = Object.assign([], this.response);

} catch (error) {
    books = [];
}

books.forEach will then be expected to always work but you have to be careful because something like this could happen:

var myStringObject = "{'myProperty':'value'}";
var myArray = Object.assign([], myStringObject );
//myArray value is ["{", "'", "myProperty", "'", ":", "'", "value", "'", "}"]

Which will leave you having to check the book in your forEach callback if it is correct:

//at the topmost of your forEach callback
if(!book.id) throw BreakException; //A simple break will not work on forEach

This will leave you again with another exception to handle. Or leave you having to use the traditional for loop since you cannot short circuit Array.forEach with a break.

TLDR: make sure books always contains an Array.

Alex Pappas
  • 2,377
  • 3
  • 24
  • 48