So I'm working on a section of my Website which has a TODO List built in not I want the data to load just like other data that are loading alongside the page. I tried having onload in Body Tag in my HTML and I had also tried to $(document).ready(function(){}) as well however neither of them seemed to work nor was I getting any errors in my console. But the function is working as it is also link to another function which runs on click of a button which I don't want to keep happening. I want it to be seamless. Is there any reason why this might not be working.
Thanks for any help in advance.
My HTML and Javascript Code:
function create() {
unfinished_task_container = document.getElementById("main_container");
unfinished_task_container.innerHTML = "";
var user = firebase.auth().currentUser;
var uid;
if (user != null) {
uid = user.uid;
}
task_array = [];
firebase
.database()
.ref("/Users/" + uid + "/todo/")
.once("value", (snapshot) => {
snapshot.forEach((childSnapshot) => {
var childKey = childSnapshot.key;
var childData = childSnapshot.val();
task_array.push(Object.values(childData));
});
for (var i = 0; i < task_array.length; i++) {
task_key = task_array[i][0];
task_title = task_array[i][1];
//Data
task_container = document.createElement("div");
task_container.setAttribute("class", "task_container");
task_container.setAttribute("data-key", task_key);
task_data = document.createElement("div");
task_data.setAttribute("id", "task_data");
title = document.createElement("p");
title.setAttribute("id", "task_title");
title.setAttribute("contenteditable", false);
title.innerHTML = task_title;
//Tools
task_tool = document.createElement("div");
task_tool.setAttribute("id", "task_tool");
task_done_button = document.createElement("button");
task_done_button.setAttribute("id", "task_done_button");
task_done_button.setAttribute(
"onclick",
"task_done(this.parentElement.parentElement, this.parentElement)"
);
task_done_button.setAttribute("onclick", "task_done()");
fa_done = document.createElement("i");
fa_done.setAttribute("class", "fa fa-check");
unfinished_task_container.append(task_container);
task_container.append(task_data);
task_data.append(title);
task_container.append(task_tool);
task_tool.append(task_done_button);
task_done_button.append(fa_done);
}
});
}
<body onload="create();">
<div class="dentistToDo">
<p class="divlable">Your Personal To Do List</p>
<input id="input_box" placeholder="What needs to be done?" />
<button id="input_button" onclick="add_task()">Add Task</button>
<div class="container" id="main_container">
<!-- DIV for TODO List -->
</div>
</div>
Related
I'm trying to add a new item on an array that displays in a container on HTML. It's supposed to get an image file and an url from input, check the selected option and push each one to its specified array
Here is the relevant html:
<input type="file" name="comic-cover" id="comic-cover" required />
<input type="url" name="comic-url" id="comic-url" placeholder="url" required />
<select name="publisher-list" id="publisher">
<option value="publisher" disabled>Publisher</option>
<option value="dc">DC Comics</option>
<option value="marvel">Marvel</option>
</select>
<button type="submit" class="btn-submit">Add</button>
<h2 class="comic-publisher">DC Comics</h2>
<div class="dc" id="block-dc">
</div>
<h2 class="comic-publisher">Marvel</h2>
<div class="marvel" id="block-marvel">
</div>
and the js:
var comicCovers = ["imgs/Dark Knights of Steel-000.jpg", "imgs/Hawkeye-000.jpg"]
var trailers = ["https://www.youtube.com/watch?v=WspmgrmEgn4", "https://www.youtube.com/watch?v=ssj0P0uY08U"]
var publishers = [0, 1];
var i = 0;
var blockDC = document.querySelector("#block-dc");
var blockMarvel = document.querySelector("#block-marvel");
render()
var publisher = document.querySelector("select").value;
document.querySelector("select") = function renderPublisher() {
publisher = document.querySelector("select").value;
return publisher;
}
// add new comics to the list //
document.querySelector(".btn-submit") = function addOnList() {
var newCover = document.querySelector("#comic-cover");
var newTrailer = document.querySelector("#comic-url");
if (newCover.endsWith(".jpg") & newTrailer.startsWith("https://")) {
if (publisher == "dc") {
publisher.push(0);
} else {
publisher.push(1)
}
comicCovers.push(newCover.value);
trailers.push(newTrailer.value);
newCover.value = "";
newTrailer.value = "";
render()
}
}
function render() {
for (i; i < comicCovers.length; i++) {
// creates the comic covers using js var //
var comicCover = document.createElement("img");
comicCover.setAttribute("src", `${comicCovers[i]}`);
// creates trailer button //
var trailerButton = document.createElement("button");
// //
var container = document.createElement("div");
container.setAttribute("class", "container");
container.appendChild(trailerButton);
container.appendChild(comicCover);
blockDC.appendChild(container);
trailerButton.appendChild(document.createTextNode("Trailer"));
trailerButton.setAttribute("class", "trailer-button");
trailerButton.setAttribute("onclick", `openTrailer("${trailers[i]}")`);
if (publishers[i] == 0) {
blockDC.appendChild(container);
} else {
blockMarvel.appendChild(container);
}
}
}
I tried to use if (newCover != "" & newTrailer != "") and even changed the input type from file to url. What am I doing wrong?
You're tring to push values inside the variable called publisher which is just a string and not an array.
var publisher = document.querySelector("select").value;
publisher.push(0);
You're assigning a function to an html element by writing:
document.querySelector("select") = function renderPublisher() {
publisher = document.querySelector("select").value;
return publisher;
}
which is not correct.
Also The variables newCover and newTrailer are not strings.
var newCover = document.querySelector("#comic-cover");
var newTrailer = document.querySelector("#comic-url");
so you can't use the methods startsWith and endsWith for them, you have to access the elements' value instead. In order to get the name of the selected file you need to use the input tag's files attribute which returns an array of the selected files, we want the first file so we'll get the first item's name attribute.
var newCover = document.querySelector("#comic-cover").value;
var newTrailer = document.querySelector("#comic-url")?.files[0]?.name;
Overall first you need to grab the values provided inside the inputs, then push them inside the array related to the selected block(Marvel or DC), then you simply need to create the img, video and button tags and append them as a child to the selected block.
Url and file type validation should be handled also on both server and client side and it's gotta be much more than just checking if the fileName ends with ".jpg" or the url starts with "https://".
You need to store the uploaded image and video somewhere on the server. In order to do so, you'll have to attach an eventListener to the input tags so that whenever a file is selected, you'll send an upload request to the server, there you'll check if the file is valid and if so, you'll store the file somewhere on the server, then you'll pass the url of the uploaded photo/video as src to the img/video tags.
const publishers = {
dc: {
comicCovers: [],
trailers: []
},
marvel: {
comicCovers: [],
trailers: []
}
}
const blockDC = document.querySelector("#block-dc");
const blockMarvel = document.querySelector("#block-marvel");
const blocksDivs = {
dc: blockDC,
marvel: blockMarvel
};
const addButton = document.querySelector(".btn-submit");
// add new comics to the list //
addButton.addEventListener("click", () => {
const publisher = document.querySelector("#publisher").value;
const newCoverFileName = document.querySelector("#comic-cover")?.files[0]?.name;
const newTrailerUrl = document.querySelector("#comic-url").value;
if (newCoverFileName?.endsWith(".jpg") && newTrailerUrl?.startsWith("https://")) {
publishers[publisher].comicCovers.push(newCoverFileName);
publishers[publisher].trailers.push(newTrailerUrl);
var container = document.createElement("div");
var coverImg = document.createElement("img");
var playTrailerButton = document.createElement("button");
playTrailerButton.innerHTML = "play trailer"
coverImg.src = "http://yourserveraddress/imgs/" + newCoverFileName;
//test photo
coverImg.src = "https://picsum.photos/200/300"
container.appendChild(coverImg);
container.appendChild(playTrailerButton);
blocksDivs[publisher].appendChild(container);
playTrailerButton.setAttribute("class", "trailer-button");
playTrailerButton.addEventListener("click", () => {
var videoExists = document.getElementById(publishers[publisher].trailers.length)
if (!videoExists) {
var video = document.createElement('video');
video.setAttribute("id", publishers[publisher].trailers.length)
video.style.backgroundColor = "aliceblue"
video.setAttribute("src", newTrailerUrl);
video.setAttribute("width", "200")
video.setAttribute("height", "200")
container.appendChild(video);
playTrailerButton.innerHTML = "close Trailer"
} else {
container.removeChild(videoExists)
playTrailerButton.innerHTML = "play Trailer"
}
})
}
})
<input type="file" name="comic-cover" id="comic-cover" required />
<input type="url" name="comic-url" id="comic-url" placeholder="url" required />
<select name="publisher-list" id="publisher">
<option value="publisher" disabled>Publisher</option>
<option value="dc">DC Comics</option>
<option value="marvel">Marvel</option>
</select>
<button type="submit" class="btn-submit">Add</button>
<h2 class="comic-publisher">DC Comics</h2>
<div class="dc" id="block-dc">
</div>
<h2 class="comic-publisher">Marvel</h2>
<div class="marvel" id="block-marvel">
</div>
I am trying to make multiple comment boxes for a website. The first click to create the text area and submit button works fine. However when I click another it appends the text area and submit button twice - creating two text areas and submit buttons and then three and so on..
If you go to https://alexpd93.github.io/FAC-Website/ and click on various comment buttons it should make more sense.
I would like it so that each time I click on the comment button, it only creates one text area for each section.
How can I fix this?
function addComment(element) {
const boxContainer = element.parentNode.parentNode.parentNode;
const commentContainer = element.parentNode;
commentContainer.classList.add("comment-container-after-click");
const commentBox = document.createElement("textarea");
commentBox.classList.add("comment-box-after-click");
commentBox.placeholder = "What are your thoughts?";
commentBox.innerHTML = "";
const submitComment = document.createElement("button");
submitComment.classList.add("submit-comment-after-click");
submitComment.innerHTML = "Comment";
commentContainer.append(commentBox, submitComment);
submitComment.onclick = function submitComment() {
let comment = commentBox.value;
const newComments = document.createElement("p");
boxContainer.appendChild(newComments);
newComments.innerHTML = `${comment}`;
commentBox.value = "";
};
}
function comment(event) {
const commentButton = event.target;
commentButton.style.display = "none";
const commentIcon = document.getElementsByClassName("comment-icon");
const iconArray = Array.from(commentIcon);
iconArray.forEach((icon) => {
if (icon.nextElementSibling.style.display === "none") {
icon.style.display = "none";
addComment(commentButton);
}
});
}
<div class="comments-container" id="comments">
<img id="commentIcon" class="comment-icon" src="Images/Comment.png" alt="comment icon">
<button class="comment-button" id="commentButton" onclick="comment(event)" > Comment </button>
</div>
After playing around with the website I believe I understood the problem. You are calling addComment() for all elements with class comment-icon. And due to your (tbh) little bit weird handling of addComment() this adds a comment to every single one of this elements.
I've corrected the error below and marked my changes with comments.
function addComment(element) {
const boxContainer = element.parentNode.parentNode.parentNode;
const commentContainer = element.parentNode;
commentContainer.classList.add("comment-container-after-click");
const commentBox = document.createElement("textarea");
commentBox.classList.add("comment-box-after-click");
commentBox.placeholder = "What are your thoughts?";
commentBox.innerHTML = "";
const submitComment = document.createElement("button");
submitComment.classList.add("submit-comment-after-click");
submitComment.innerHTML = "Comment";
commentContainer.append(commentBox, submitComment);
submitComment.onclick = function submitComment() {
let comment = commentBox.value;
const newComments = document.createElement("p");
// why append to the box container? Then all comments from different textareas will be merged
// boxContainer.appendChild(newComments);
commentContainer.appendChild(newComments);
newComments.innerHTML = `${comment}`;
commentBox.value = "";
};
}
function comment(event) {
const commentButton = event.target;
commentButton.style.display = "none";
const commentIcon = document.getElementsByClassName("comment-icon");
// add the comment once not to every comment box available
addComment(commentButton);
const iconArray = Array.from(commentIcon);
iconArray.forEach((icon) => {
if (icon.nextElementSibling.style.display === "none") {
icon.style.display = "none";
// this causes that the comment is added multiple times
// addComment(commentButton);
}
});
}
<div div="all-comments">
<div class="comments-container" id="comments">
<img id="commentIcon" class="comment-icon" src="https://dummyimage.com/100x100/000/fff" alt="comment icon">
<button class="comment-button" id="commentButton" onclick="comment(event)"> Comment </button>
</div>
<div class="comments-container" id="comments">
<img id="commentIcon" class="comment-icon" src="https://dummyimage.com/100x100/000/fff" alt="comment icon">
<button class="comment-button" id="commentButton" onclick="comment(event)"> Comment </button>
</div>
<div class="comments-container" id="comments">
<img id="commentIcon" class="comment-icon" src="https://dummyimage.com/100x100/000/fff" alt="comment icon">
<button class="comment-button" id="commentButton" onclick="comment(event)"> Comment </button>
</div>
</div>
I want to be able to add an image to this div once the button is clicked and a check box is checked. I have already confirmed that the checkbox portion works properly, but can't get the photo to go into the div.
Here is what I currently have:
<button id="show_button">Show System</button>
<div class="box" id="AC1"></div>
<script>
var show_button = document.getElementById('show_button');
var show = function() {
// AC Relevant Components;
var ch_mGT = document.getElementById('mGT').checked;
// Set AC1
if (ch_mGT) {
var AC1_html = "<img src='http://localhost/....png' alt='Micro Turbine'
height='50px'>";
document.getElementById("AC1").innerHTML(AC1_html);
}
}
show_button.addEventListener("click",show);
</script>
I also have already tried:
var AC1_img = document.createElement("img");
AC1_img.src = 'http://localhost/....png'
document.getElementById('AC1').appendChild(AC1_img);
You said you tried using appendElement, but it seems to be working in the below example.
var show_button = document.getElementById('show_button');
var show = function() {
var ch_mGT = document.getElementById('mGT').checked;
var AC1_img = document.createElement('img')
AC1_img.src="https://i.ytimg.com/vi/r4Hve6fZ7ik/maxresdefault.jpg"
AC1_img.style.height = "50px"
AC1_img.alt = 'Micro Turbine'
if (ch_mGT) {
document.getElementById("AC1").appendChild(AC1_img)
}
}
show_button.addEventListener("click",show);
<div class="box" id="AC1"></div>
<input type="checkbox" id="mGT">
<button id="show_button">Show System</button>
I'm trying to create chat app using firebase database.
I have html:
<input type="text" name="txt" id="txt">
<button type="submit" id="btn-send" onclick="addElement()">SEND</button>
<p id="list-message"></p>
and javascript :
var rootRef = firebase.database();
var message = rootRef.ref().child('/message');
function addElement() {
var x = document.getElementById('txt').value;
var node = document.createElement("li");
var text = document.createTextNode(x);
node.appendChild(text);
document.getElementById('list-message').appendChild(node);
message.push().set({
Message: $("#txt").val()
});
}
Screenshot of my Firebase data
How can I retrieve all the data and show as a list in <p id="list-message"></p>?
Add a data listener which looks out for changes in the message node then update <p id="list-message"></p>.
message.on('child_added', function(snapshot) {
var msg = snapshot.val();
var msgDiv = document.createElement("div");
msgDiv.textContent = msg.Message;
document.getElementById("list-message").appendChild(msgDiv);
});
Refer to this codelab for more on how to build a chat app: https://codelabs.developers.google.com/codelabs/cloud-firebase-chat/.
I am trying to create FireBase chat with separate rooms and only display messages from that room. How can I only show messages with roomid = somenumber (currently set to 4)
Data might look like this:
This is the code following the firebase documentation.
<body>
<!-- CHAT MARKUP -->
<div class="example-chat l-demo-container">
<header>Firebase Chat Demo</header>
<div class='example-chat-toolbar'>
<label for="nameInput">Username:</label>
<input type='text' id='nameInput' placeholder='enter a username...'>
</div>
<ul id='example-messages' class="example-chat-messages"></ul>
<footer>
<input type='text' id='messageInput' placeholder='Type a message...'>
</footer>
</div>
<!-- CHAT JAVACRIPT -->
<script>
// CREATE A REFERENCE TO FIREBASE
var messagesRef = new Firebase('https://blistering-fire-1740.firebaseio.com/');
// REGISTER DOM ELEMENTS
var messageField = $('#messageInput');
var nameField = $('#nameInput');
var messageList = $('#example-messages');
// LISTEN FOR KEYPRESS EVENT
messageField.keypress(function (e) {
if (e.keyCode == 13) {
//FIELD VALUES
var username = nameField.val();
var message = messageField.val();
//SAVE DATA TO FIREBASE AND EMPTY FIELD
messagesRef.push({name:username, text:message, roomid:4});
messageField.val('');
}
});
// Add a callback that is triggered for each chat message.
messagesRef.limitToLast(10).on('child_added', function (snapshot) {
//GET DATA
var data = snapshot.val();
var username = data.name || "anonymous";
var message = data.text;
//CREATE ELEMENTS MESSAGE & SANITIZE TEXT
var messageElement = $("<li>");
var nameElement = $("<strong class='example-chat-username'></strong>")
nameElement.text(username);
messageElement.text(message).prepend(nameElement);
//ADD MESSAGE
messageList.append(messageElement)
//SCROLL TO BOTTOM OF MESSAGE LIST
messageList[0].scrollTop = messageList[0].scrollHeight;
});
</script>
</body>
firebase doc
Dan's answer will work, but it means that you're downloading all the chat messages. User's on smaller data plans will appreciate it if you don't download data that is not needed:
var roomMessages = messagesRef.orderByChild('roomid').equalTo(4);
roomMessages.limitToLast(10).on('child_added', function (snapshot) {
//GET DATA
var data = snapshot.val();
You'll need an index on roomid, as described here.
Simply filter out messages that don't belong to that room, when you add them to the DOM.
// Add a callback that is triggered for each chat message.
messagesRef.limitToLast(10).on('child_added', function (snapshot) {
var data = snapshot.val();
// break out of the function early if this message does not
// belong in this room.
if(data.roomId !== 4) return;
var username = data.name || "anonymous";
var message = data.text;
// ...
});
You probably don't want to hardcode the roomID into your code. It would make sense to store the current room ID in a variable somewhere, then check against that instead.
var currentRoomId = getRoomId(); // get from URL, or from Firebase
// ...
if(data.roomId !== currentRoomId) return;