Home > database >  I have a form that takes in user input, creates a new object and gets pushed to an array. How can I
I have a form that takes in user input, creates a new object and gets pushed to an array. How can I

Time:07-11

I am basically trying to prevent duplicate objects from being created by iterating through the myLibrary array. If user input is a unique title, then add to array. If not, then deny entry.

No matter what I try, I get to the point where my code tells me a duplicate exists but still adds the duplicate object.

I am obviously new to this. Thank you in advance for any help.

let myLibrary = [];

class BookInfo {
    constructor(title, author, pages, genre) {
        this.title = title,
        this.author = author,
        this.pages = pages,
        this.genre = genre
    };
};

// Add new book to library array:
const addBook = function() {
    let title = document.getElementById("title");
    let author = document.getElementById("author");
    let pages = document.getElementById("pages");
    let genre = document.getElementById("genre");
    document.getElementById("Submit").addEventListener('click', (e) => {
        e.preventDefault();
        const newBook = new BookInfo(title.value, author.value, pages.value, genre.value);
        if (myLibrary.length === 0) {
            myLibrary.push(newBook); // Add first book to library.
            alert(`${title.value} has been added to your library!`);
            document.querySelector('form').reset(); // clear form after submit.
        } else {
            myLibrary.forEach(book => {
                console.log(newBook.title);
                if (book.title === newBook.title) { // Dup exists.
                    alert(`${title.value} already exists in your library.`);
                    document.querySelector('form').reset(); // clear form after submit.
                    return;
                } else {
                    myLibrary.push(newBook);
                    alert(`${title.value} has been added to your library.`);
                    document.querySelector('form').reset(); // clear form after submit.
                    return;
                }
            })
        };
    });
};

addBook();
    <form>
    <input type="text" id="title">
    <input type="text" id="author">
    <input type="number" id="pages">
    <input type="text" id="genre">
    <input type="button" value="Submit" id="Submit">
    </form>

CodePudding user response:

The built-in "forEach" method from Array.prototype wil not break with "break" or "return" https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach (look at the first blue note box)

In your case you can iterate using a for loop

for (let i = 0; i < myLibrary.length; i  ) {
   if (myLibrary[i].title === book.title) {
     break;
   } else if (i == myLibrary.length - 1) {
     myLibrary.push(book);
   }
}

(instead of "myLibrary.forEach")

Or you can add always and clean the duplication after that:

myLibrary = myLibrary.filter(
  (i, idx) => myLibrary.findIndex((j) => i.title === j.title) === idx
);

CodePudding user response:

You are looping the array and for each item, if it is not a match of the item to be inserted, then the item is inserted. The logical problem with this is that this will add the new item as many times as many mismatches were found in the array, independently of whether the item is already in the array. Instead of your approach, I'm using filter, which is a function that returns the subset of the array that matches the condition. In our case the condition is that it's matching. So, if there are any matches, then this subset will not be empty and therefore its length will differ from 0. So, I compare length to 0 and if it is indeed 0, it means it's a new item and it can be inserted. In that case, I'm pushing it to myLibrary, notify that it was added, reset the form and display the current content in a div. This displaying is unnecessary, but it was helpful in this example, so we can know whether this works properly

If the length is not 0, then I'm alerting that it's a duplicate and I do not do anything else, not even reset (because in the case of a typo it's not really user-friendly if the user would be punished by having to enter everything again.)

let myLibrary = [];

class BookInfo {
    constructor(title, author, pages, genre) {
        this.title = title,
        this.author = author,
        this.pages = pages,
        this.genre = genre
    };
};

// Add new book to library array:
const addBook = function() {
    let title = document.getElementById("title");
    let author = document.getElementById("author");
    let pages = document.getElementById("pages");
    let genre = document.getElementById("genre");
    document.getElementById("Submit").addEventListener('click', (e) => {
        e.preventDefault();
        if (myLibrary.filter(item => item.title === title.value).length === 0) {
            myLibrary.push(new BookInfo(title.value, author.value, pages.value, genre.value));
            alert("added");
            document.querySelector("form").reset();
            document.querySelector('div').innerText = JSON.stringify(myLibrary);
        } else {
            alert("duplicate");
        }
    });
};

addBook();
<form>
<input type="text" id="title" placeholder="title"><br>
<input type="text" id="author" placeholder="author"><br>
<input type="number" id="pages" placeholder="pages"><br>
<input type="text" id="genre" placeholder="genre"><br>
<input type="button" value="Submit" id="Submit">
</form>

<div></div>

CodePudding user response:

You cannot know in the first iteration whether the book title is new. For that you need to first complete all iterations.

But, why not use a different data structure for the library, one that is keyed by title. Then it doesn't need any iteration at all.

let myLibrary =  {};  // Different structure.

class BookInfo {
    constructor(title, author, pages, genre) {
        this.title = title;
        this.author = author;
        this.pages = pages;
        this.genre = genre;
    };
}

let title = document.getElementById("title");
let author = document.getElementById("author");
let pages = document.getElementById("pages");
let genre = document.getElementById("genre");
document.getElementById("Submit").addEventListener('click', (e) => {
    e.preventDefault();
    if (Object.hasOwn(myLibrary, title.value)) {
        alert("duplicate");
    } else {
        myLibrary[title.value] = new BookInfo(title.value, author.value, pages.value, genre.value);
        alert("added");
        document.querySelector("form").reset();
        document.querySelector('div').innerText = JSON.stringify(myLibrary);
    }
});
<form>
<input type="text" id="title" placeholder="title"><br>
<input type="text" id="author" placeholder="author"><br>
<input type="number" id="pages" placeholder="pages"><br>
<input type="text" id="genre" placeholder="genre"><br>
<input type="button" value="Submit" id="Submit">
</form>

<div></div>

  • Related