Problem:
I’ve been stuck on this problem for awhile now.
I’ve given each component a className and im using GetElementsByClassName to access each individual component.
I need to get the value of the inputs for each individual component and create a note out of it (append it to the end of the custom component).
I’ve tried using innerHTML along with adding getElementByID to the end of the note variable
if(idNumber[12] == 1){
let note = document.getElementsByClassName("note")[0].getElementByID("title-input");
}
function addNote() {
//Creating the NoteComponent, Adding it to the Array and Inserting it into
//the document
let noteComponent = document.createElement("note-component");
noteComponentArray.push(noteComponent);
numberOfNoteComponentsAdded++;
document.getElementById("noteWorkingArea").append(noteComponent);
//Setting the ID on the NoteComponent
noteComponent.setAttribute("id", "note-component" +
numberOfNoteComponentsAdded);
noteComponent.setAttribute("class", "note");
//Setting the ID on the SubmitButton
let SubmitButtonElement = document.getElementById("submitButton");
let SubmitButtonID = "submitButton" + 1;
SubmitButtonElement.setAttribute("id", SubmitButtonID);
}
// Here is my attempt at updating the elements within the components
function addNoteDetails(numberOfNote) {
let idNumber = numberOfNote.split('');
//document.body.insertAdjacentHTML("afterend", idNumber[12]);
if (idNumber[12] == 1) {
let note = document.getElementsByClassName("note")[0];
}
if (idNumber[12] == 2) {
let note = document.getElementsByClassName("note")[1];
}
if (idNumber[12] == 3) {
let note = document.getElementsByClassName("note")[2];
}
if (idNumber[12] == 4) {
let note = document.getElementsByClassName("note")[3];
}
}
// Here is the Custom Component
class Note extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.innerHTML = `
<body>
<div class="fixed-action-btn" id="main-note">
<a class="btn-floating btn-large red">
<div id="deleteDiv" onclick="deleteNoteComponent()">
<i class="fa-solid fa-x"></i>
</div>
</a>
<div class="card">
<div class="card-content" id="cardContent">
<div class="input-group id="add-title-area" mb-3">
<input type="text" class="form-control" id="title-input"
placeholder="Note Title:">
<div class="input-group-append">
<button class="btn btn-outline-secondary"
id="addTitleButton"
type="button" onclick="addNoteTitle()">Add</button>
</div>
</div>
<textarea class="note-input" id="input-note" contenteditable="true"
placeholder="enter your note..."></textarea>
</div>
<span class="button-row">
<button class="btn waves-effect waves-light submit-button"
id="submitButton"
type="submit" name="action"
onclick="addNoteDetails(this.getAttribute('id'))">Submit
</button>
</span>
<div id="noteButtonContainer" class="centerButtons">
</div>
<span class="button-row">
<button id="deleteNote"class="btn waves-effect waves-light delete-
button" type="default"
name="action" onclick="deleteNote()">Delete Note
</button>
</span>
</div>
</body>`;
}
}
customElements.define('note-component', Note);
Solution:
The question was a bit confusing.. it wasn’t clear why you had a button to add a title to the single note, like if the input itself wasn’t enough. Did you need multiple titles?
Anyway since the problem was stated as the addNoteDetails
function and yet its exact task wasn’t perfectly clear based on its content, I just sticked to
I need to get the value of the inputs for each individual component
and create a note out of it (append it to the end of the custom
component).
So here in this demo I slightly replicated your same custom element just stripping away unnecessary parts to make it easier to read and added a feature to collect all notes contained in a given container and set the #output
value with their content joined.
Note that I didn’t use ids in the custom component because it was tedious to change all of them when every instance was created (by the way you limited your attempt to the textarea but it was not the only element having an id that can’t be duplicated). Plus the deleteNote
function is defined in the class itself and it uses the .closest()
api function to find its parent before removal.
In the end I also added an event emitSubmitEvent
on your component that will be fired by the .submit
button of the corresponding note. So that you can listen to it from your caller that when the event will trigger, will log the corresponding note on console. That’s not perfectly matching the request of creating a new button performing such action only when the submit is clicked… at first I thought it didn’t make sense to me but it actually does.. it would be like an extra watch button after submitting to note somewhere.
// Here is the Custom Component
class Note extends HTMLElement {
constructor() {
super();
//this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.innerHTML = `
<div class="main-note">
<div class="delete">
<i class="fa-solid fa-x"></i>
</div>
<div class="card">
<div class="card-content">
<textarea
class="note-input"
contenteditable="true"
placeholder="enter your note..."></textarea>
<button type="button" class="submit">submit</button>
</div>
</div>
</div>`;
//we are adding the event listener programmatically instead of using onclick attr
this.querySelector('.delete').addEventListener('click', this.deleteNote);
this.querySelector('.submit').addEventListener('click', this.emitSubmitEvent.bind(this));
}
deleteNote(event) {
this.closest('note-component').remove();
}
emitSubmitEvent() {
const textareaValue = this.querySelector('.note-input').value;
const event = new CustomEvent('submit', {
detail: {
text: textareaValue
}
});
this.dispatchEvent(event);
}
}
customElements.define('note-component', Note);
//adds the click event handler on #addNote that will call addNote over noteWorkingArea container
document.getElementById('addNote')
.addEventListener('click', ()=>{
const noteWorkingArea = document.getElementById("noteWorkingArea");
addNote(noteWorkingArea);
});
//adds the click event handler on #collectNotes
//that will call collectNoteContents over noteWorkingArea container
//and will set the output content as the join of all notes
document.getElementById('submit-button')
.addEventListener('click', ()=>{
const noteWorkingArea = document.getElementById("noteWorkingArea");
const noteContents = collectNoteContents(noteWorkingArea);
document.querySelector('#output')
.innerText = noteContents;
});
//appends a new note-component instance in the container
function addNote(container) {
let noteComponent = document.createElement("note-component");
container.append(noteComponent);
noteComponent.setAttribute("class", "note");
//listen for submit event on the notecomponent and log its note on console
noteComponent.addEventListener('submit', (event) => {
const noteText = event.detail.text;
console.log(noteText);
});
}
//defined outside the "scope" of the single notes..
//it will collect all the note contents in the noteWorkingArea and return the joined text
function collectNoteContents(container) {
let result = '';
container.querySelectorAll('.note-input')
.forEach(note => {
result += note.value + "\n--------------------------\n";
});
return result;
}
#noteWorkingArea{
border: dashed 4px purple;
min-height: 2em;
margin-bottom: 1em;
}
note-component{
border: solid 1px gray;
margin: 1em;
display: block;
}
#output{
margin-top: 1em;
border: dashed 4px red;
min-height: 2em;
}
button{
cursor: pointer;
padding: 1em;
}
textarea{
width: 100%;
box-sizing: border-box;
}
.submit{
width: 100%;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- area were the notes (components) will be appended -->
<h2>Notes:</h2>
<div id="noteWorkingArea">
</div>
<!-- button that will append a new note inside the target -->
<button id="addNote">Add Note</button>
<!-- button to add a new note in #noteWorkingArea -->
<!-- I didn't use type=submit because there's no form in this scenario -->
<button
id="submit-button"
class="btn btn-primary waves-effect waves-light"
type="button"
name="action">COLLECT CONTENTS</button>
<!-- where you'll see the note contents collected -->
<h2>Output:</h2>
<div id="output">
</div>