I am new to javascript. I am trying to creates a notesapp with notes made by user input. So far I am able to add and display the notes but each note is being displayed twice e.g if I input "hello" it prints hello but then if I then input "goodbye" it prints out "hello,hello,goodbye." I have my code printed below with my view and model class.
class NotesView{
constructor(model){
this.model = model;
this.mainContainerEL = document.querySelector('#main-container');
this.noteButton = document.querySelector('#add-note');
this.noteButton.addEventListener('click', () => { this.addNewNote() });
}
addNewNote(){
const new_note = document.getElementById('message').value;
this.model.addNote(new_note);
this.displayNotes();
}
displayNotes() {
const notes = this.model.getNotes();
notes.forEach(note =>{
const noteEl = document.createElement('div');
noteEl.textContent = note;
noteEl.className = 'note';
this.mainContainerEL.append(noteEl);
})
}
}
module.exports = NotesView;
class notesModel{
constructor(notes){
this.notes = []
}
getNotes(){
return this.notes
}
addNote(note){
return this.notes.push(note)
}
reset(){
this.notes.splice(0, this.notes.length)
}
}
module.exports = notesModel;
CodePudding user response:
The problem is that you are not "resetting" the DOM. Everytime you click the button addNewNote()
will be called which calls displayNotes()
. displayNotes()
will always create a new div for all elements in the notes
array and append that div to the #main-container
element.
So on first click on the button the array will contain hello
and one div
to display hello will be appended to the container. So far, so good.
Now on the second click you will add another element to the array so it will contain ["hello", "goodbye"]
. And you will create another to divs for those to elements and append that to the container. The container therefore now has three element: the hello div from the first click and a hello and goodbye div from the second click, that's why you'll see hello, hello, goodbye
.
Here a minimal example showcasing the error:
document.querySelector("#button").addEventListener("click", () => addSecondNote())
const notes = ["hello", "goodbye"];
function addSecondNote(){
const container = document.querySelector("#container");
notes.forEach(note => {
const noteDiv = document.createElement("div");
noteDiv.textContent = note;
container.append(noteDiv);
});
}
<button id="button">Add a second note</button>
<div id="container">
<div>hello<span>
<div/>
One of many possible ways to resolve this is to use replaceChildren()
which will take an Iterable of Node
or string
as a parameter. You can use map()
to create an array of the child div
s.
document.querySelector("#button").addEventListener("click", () => addSecondNote())
const notes = ["hello", "goodbye"];
function addSecondNote(){
const container = document.querySelector("#container");
const newChildDivs = notes.map(note => {
const noteDiv = document.createElement("div");
noteDiv.textContent = note;
return noteDiv;
});
container.replaceChildren(...newChildDivs);
}
<button id="button">Add a second note</button>
<div id="container">
<div>hello<span>
<div/>
CodePudding user response:
as Mushroomator said you are appending the whole model notes each time you add a note. so you either
- clear the container before adding all those notes.
- display the new notes as soon as you add them to the model.
- add an index to the model to only display the newest notes the index solution is something like this
class NotesView {
constructor(model) {
this.model = model;
this.mainContainerEL = document.querySelector("#main-container");
this.noteButton = document.querySelector("#add-note");
this.noteButton.addEventListener("click", () => {
this.addNewNote();
});
}
addNewNote() {
const new_note = document.getElementById("message").value;
this.model.addNote(new_note);
this.displayNotes();
}
displayNotes() {
const notes = this.model.getNotes();
for (let i = this.model.displayindex; i < notes.length; i ) {
const noteEl = document.createElement("div");
noteEl.textContent = notes[i];
noteEl.className = "note";
this.mainContainerEL.append(noteEl);
this.model.displayindex ;
}
}
}
class notesModel {
constructor(notes) {
this.notes = [];
this.displayindex = 0;
}
getNotes() {
return this.notes;
}
addNote(note) {
return this.notes.push(note);
}
reset() {
this.notes.splice(0, this.notes.length);
this.displayindex = 0;
}
}
let myNotes = new NotesView(new notesModel())
<button id="add-note">Add a second note</button>
<input type="text" id="message"/>
<div id="main-container">
<div>hello<span>
<div/>