I am trying to make a schema generator which will work something like this:
https://wtools.io/breadcrumb-json-ld-schema-generator
But the problem is i am able to add values and generate the schema list items but everytime i click "click me" a value is added to the schema as ListItem which is clearly not the intended behavior. Also, am failing to remove any added item from the generated schema even when i remove it from the list above.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
body {
background: silver;
}
.dis {
display: none;
}
</style>
</head>
<body>
<form>
<label for="item">Add an item: </label>
<input id="item" type="text" size="20"><br>
<input id="url" type="url" size="20"><br>
<input id="submitButton" type="button" value="Add!">
</form>
<ul id="ul">
</ul>
<p> Click an item to remove it from the list. </p>
<button onclick="myFunction();">Click me</button>
<br><br> <script type="application/ld+json"><br>
<div class="output">{ "#context": "https://schema.org", "#type": "BreadcrumbList", "itemListElement": [ { "#type": "ListItem", "position": 1, "name": "Google", "item": "google.com" } ] }</div></script>
</body>
</html>
window.onload = function() {
var button = document.getElementById("submitButton");
button.onclick = addItem;
}
function addItem() {
var textInput = document.getElementById("item"); //getting text input
var text = textInput.value; //getting value of text input element
var ul = document.getElementById("ul"); //getting element <ul> to add element to
var li = document.createElement("li"); //creating li element to add
li.setAttribute("class", "breadcrumb-item");
li.innerHTML = text; //inserting text into newly created <li> element
li.onclick = function() {
this.parentNode.removeChild(this);
setTimeout(function() {}, 1000);
}
ul.appendChild(li);
}
//script generation code here
// Create Script
var el = document.createElement('script');
el.type = 'application/ld+json';
// Set initial position
var position = 0;
// Create breadcrumb object
var breadcrumb = {
position: 0,
name: "",
item: ""
}
// Empty array for list items
var listArray = []
function myFunction() {
// Loop through each breadcrumb link and set attributes
var items = document.querySelectorAll('.breadcrumb-item');
for (var i = 0; i < 1; i++) {
var newItem = Object.create(breadcrumb);
var curItem = items[i];
newItem["#type"] = "ListItem";
position++;
newItem.position = position;
newItem.name = document.getElementById("item").value;
newItem.item = document.getElementById("url").value;
listArray.push(newItem);
}
// Create overarching Schema object
var breadcrumbSchema = {
"#context": "https://schema.org/",
"#type": "BreadcrumbList",
"itemListElement": listArray
};
var finalSchema = JSON.stringify(breadcrumbSchema);
// Add schema to Script
el.text = finalSchema;
// Set head variable with browser fallback
var head = document.head || document.getElementsByTagName("head")[0];
// Testing purposes - Show example of string in HTML
document.querySelector('.output').innerHTML = finalSchema;
// This won't work in codepen
head.appendChild(el);
// Testing purposes - Inspect source to see script generated inside of the "output" div
document.querySelector('.output').appendChild(el);
}
This is my first time working with JS so any help will be appreciated.
When you create the function to remove an item from your unordered list try adding a call to remove it from the listArray.
let textInput = document.getElementById("item"); //getting text input
let text = textInput.value; //getting value of text input element
let ul = document.getElementById("ul"); //getting element <ul> to add element to
let li = document.createElement("li"); //creating li element to add
li.setAttribute("class", "breadcrumb-item");
li.innerHTML = text; //inserting text into newly created <li> element
li.onclick = function() {
this.parentNode.removeChild(this);
//call to remove from listArray goes here
setTimeout(function() {
}, 1000);
}
ul.appendChild(li);
It might look like:
function removefromlist(item_position)
{
for(l in listArray){
if(listArray[1].position == item_position){
listArray.splice(l,1);
break;
}
}
}
Unless I'm missing something I'm not sure what other type would be added to your schema, because on line 92 of your code "ListItem" is the only type you ever assign.
Related
I want to add html elements to the body of my page as an unordered list. I have used DocumentFragment method to create a fragment of the reply button and comment span. Now I need to add a textbox and a add reply to that ul whenever a user clicks on the reply button and add all the replies as a list next to respective comment. Here is what I've tried:
function comment() {
var my_comment = document.getElementById('comments');
my_comment.innerHTML = "<textarea id='user_comment'> </textarea> <button onclick='addNewItem()'>Post Comment</button>";
}
function addNewItem() {
var thediv = document.getElementById("comments_and_replies");
var listItem = document.createElement("ul");
var replyBox = document.createElement("textbox");
var commentSpan = document.createElement("span");
var user_comment = document.getElementById('user_comment');
var replyButton = document.createElement("button");
listItem.className = "comments-list";
replyButton.innerText = "Reply";
replyButton.className = "reply";
replyButton.addEventListener("click", function() {
var g = document.getElementById('comments_and_replies');
for (var i = 0, len = g.children.length; i < len; i++) {
(function(index) {
g.children[i].onclick = function() {
listItem.insertBefore(replyBox, listItem.children[index]);
}
})(i);
}
})
commentSpan.textContent = user_comment.value;
var documentFragment = document.createDocumentFragment();
documentFragment.appendChild(listItem);
listItem.appendChild(commentSpan);
listItem.appendChild(replyButton);
thediv.appendChild(documentFragment);
}
<section><button onclick="comment()">Leave a comment</button></section>
<div id="comments"></div>
<div id="comments_and_replies"></div>
Event delegation on a single <form> can accommodate an unlimited amount of <button>s even if they are added after the page has loaded.
The example below uses the following:
document.forms
.elements
event.currentTarget
event.target
.matches()
.insertAdjacentHTML()
.previousElementSibling
.parentElement
.remove()
Note: Unless you are submitting data to a server, add type="button" to each <button>
Details are commented in code below
// Refernce <form>
const form = document.forms.commentsReplies;
// Any click on <form> invokes post()
form.onclick = post;
// Pass the event
function post(event) {
/* Reference all <fieldset>
(also <button>, <textarea>, etc) */
const field = event.currentTarget.elements;
// Reference the actual element clicked
const clicked = event.target;
// if element clicked has class postCom
if (clicked.matches('.postCom')) {
/* find <fieldset name="post"> and
insert HTML into it */
field.post.insertAdjacentHTML('beforeEnd', `<fieldset name='commentPost'><textarea></textarea><button class='comTxt' type='button'>Done</button></fieldset>`);
// Otherwise if clicked element has class comTxt
} else if (clicked.matches('.comTxt')) {
/* find the clicked element's element
that is right before it and get it's text */
const text = clicked.previousElementSibling.value;
/* find <fieldset name='comments'> and insert HTML */
field.comments.insertAdjacentHTML('afterBegin', `<fieldset>${text}<button class='postRep' type='button'>Reply</button><ul></ul></fieldset>`);
// Remove <fieldset name='commentPost'>
field.commentPost.remove();
} else if (clicked.matches('.postRep')) {
clicked.insertAdjacentHTML('afterEnd', `<ul><textarea></textarea><button class='repTxt' type='button'>Done</button></ul>`);
} else if (clicked.matches('.repTxt')) {
const text = clicked.previousElementSibling.value;
const list = clicked.parentElement;
list.insertAdjacentHTML('afterBegin', `<li>${text}<button class='postRep' type='button'>Reply</button></li>`);
clicked.previousElementSibling.remove();
clicked.remove();
} else {
return false;
}
}
button {
display: block;
margin-left: 25%;
}
<form id='commentsReplies'>
<fieldset name='post'><button class='postCom' type='button'>Leave a comment</button>
</fieldset>
<fieldset name="comments">
<legend>Comments</legend>
</fieldset>
</form>
I'm just starting to learn JS and collided with a specific task that i dont understand how to solve.
Suppose we have a page that has a list, and there is a button with which I can supplement this list with new cases.
The problem that I encountered:
I need to implement a function in a certain way that will change the style of the selected line from the list of all existing and added elements.
For example, if our list - "a list of things that we have to do", i need to make so that the user can press the "Done" button, and select the desired line. After the selection the selected line gets a line-through.
function addItemToTheList() {
var newItem = document.createElement("li");
var input = document.getElementById("Input");
newItem.innerHTML = input.value;
input.value = "";
document.getElementById("todo").appendChild(newItem);
}
#todo {
font-family: Arial;
}
#todo .done {
color:gray;
text-decoration:line-through;
}
<!doctype html>
<html>
<head>
<title> How can user change added and predefined elements in the list?</title>
</head>
<pre>
<input type = "text" id = "Input" maxlength = "42" size = "42" placeholder = " Add a task here"> <input
type = "button" value = "Add" onclick = "addItemToTheList()">
</pre>
<hr align = "left" width = "378">
<body>
<div id = "todoList">
<ol id = "todo">
<li class = "done"> Watch all seasons of "Game of Thrones"</li>
<li class = "done"> Write a book</li>
<li class = "undone"> Learn "JS"</li>
</ol>
</div>
</body>
</html>
Would anybody be willing to point me in the right direction?
You have to add, first, a click event on each undone tasks.
Then when you create a task just add another clickevent.
Then you just have to click on an undone tasks to change his state.
Hope this is what you want :
function addItemToTheList() {
var newItem = document.createElement("li");
var input = document.getElementById("Input");
newItem.innerHTML = input.value;
input.value = "";
document.getElementById("todo").appendChild(newItem);
// Add click listener
newItem.addEventListener('click', done);
}
function done() {
this.className = "done";
this.removeEventListener('click',done);
}
// Initialize all listener for current undone tasks
function init() {
var undoneItems = document.getElementsByClassName('undone');
for(var i = 0; i < undoneItems.length; i++){
undoneItems[i].addEventListener('click', done);
}
}
#todo {
font-family: Arial;
}
#todo .done {
color:gray;
text-decoration:line-through;
}
#todo .undone {
cursor: pointer;
}
<!doctype html>
<html>
<head>
<title> How can user change added and predefined elements in the list?</title>
</head>
<body onload="init()">
<pre>
<input type = "text" id = "Input" maxlength = "42" size = "42" placeholder = " Add a task here"> <input
type = "button" value = "Add" onclick = "addItemToTheList()">
</pre>
<hr align = "left" width = "378">
<div id = "todoList">
<ol id = "todo">
<li class = "done"> Watch all seasons of "Game of Thrones"</li>
<li class = "done"> Write a book</li>
<li class = "undone"> Learn "JS"</li>
</ol>
</div>
</body>
</html>
You need to create another function, add a button to each of the li items and add an on click function to each button to change the class to done.
Here is a jsfiddle link where i've begun the work required. It isn't fully functional but what would you learn from me doing everything :)
https://jsfiddle.net/nu6b00o0/
(function(){
var buttons = document.getElementsByTagName('button');
for(i = 0; i <= buttons.length -1; i++){
buttons[i].addEventListener('click', function() {
doOrUndoItem();
}, false);
if(buttons[i].parentNode.className == 'done'){
buttons[i].className = 'btn-success';
} else {
buttons[i].className = 'btn-warning';
}
}
}());
Feel free to ask any more questions
Tom
Hope this helps...
//list your pre existing items
var items = document.querySelectorAll("li");
function createListElement(){
var li = document.createElement("li");
li.appendChild(document.createTextNode(input.value));
ul.appendChild(li);
//add the function in your new items
li.addEventListener("click", alterStatus)
//
input.value = "";
}
// add/remove class
function alterStatus(){
this.classList.toggle("done");
}
//set the function to the pre existing items
for (var i = 0; i < items.length; i++) {
items[i].addEventListener("click", alterStatus);
}
i am trying to build post it notes. I am reading Head First Series.
I did this code.
but somehow it's no working.
<form action="post">
<input id="note_text" type="text" placeholder="enter your Note">
<input type="button" id="add_button" value="Add Note">
</form>
<ul id="postItNotesList">
<li>This is my very first note.</li>
<li>This is my very Second note.</li>
</ul>
And here is the Js
window.onload=init;
// Add Sticky to Page
function addStickyToPage(value) {
var sticky = document.createElement("li");
span.setAttribute("class", "sticky");
document.getElementById("postItNotesList").appendChild(sticky);
}
// Create and get Sticky Note into the localStorage
function createSticky() {
var value = document.getElementById("note_text").value;
var key = "sticky_" + localStorage.length;
localStorage.setItem(key, value);
addStickyToPage(value);
}
function init() {
var button = document.getElementById("add_button");
button.onclick = createSticky;
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
if (key.substring(0, 6) == "sticky") {
var value = localStorage.getItem(key);
addStickyToPage(value);
}
}
}
So i've buld up a fiddle so that you can easily check it out
Here is the Fiddle
Please tell me where i am doing it wrong.
Thanks.
I have updated your Fiddle. Note : first you should create DOM element and then append text to this element and finally append this node to you body so your code should be like this:
window.onload=init();
function addStickyToPage(value) {
var sticky = document.createElement("li");
sticky.setAttribute("class", "sticky");
var t = document.createTextNode(value);
console.log(t);
sticky.appendChild(t);
document.getElementById("postItNotesList").appendChild(sticky);
}
And also windows.onload = init()with brackets
Thanks
I apologize for posting this question, I'm just learning JavaScript and have tried using the information from other posts but just cannot get my code to work. The object is to create an li tag and insert list items to this newly created tag, then assign an event handler to remove an item if the user clicks on it.
I have the list populating and can remove an item if I hardcode it but cannot for the life of me figure out how to assign the value of the item being clicked on to the removeItem function. I am also trying to clear the list when an item is entered but keep getting the error "Object doesn't support property or method 'reset'".
If someone could point me in the right direction I would appreciate it.
thanks!
<!doctype html>
<html lang="en">
<head>
<title> Add and delete items Objective </title>
<meta charset="utf-8">
<style>
p {
font-style: italic;
}
li:hover {
cursor: pointer;
}
</style>
<script>
// your code here!
var itemList = [];
window.onload = init;
function init() {
var addButton = document.getElementById("submitButton");
addButton.onclick = addItem;
//var itemList = document.getElementById("list");
var itemsList = document.getElementsByTagName("li");
itemsList.onclick = removeItem;
}
function addItem() {
var newItem = document.getElementById("item").value;
var ul = document.getElementById("list");
var li = document.createElement("li");
li.appendChild(document.createTextNode(newItem));
ul.appendChild(li);
itemList.push(newItem);
document.getElementById("item").reset();
}
function removeItem() {
var editList = document.getElementsByTagName("li");
// var editList = document.getElementsById("list");
for (var i = 0; i < editList.length; i++) {
var item = editList[i];
if(editList.options[i].selected) {
editList.removeChild(editList.childNodes[i]);
}
}
}
</script>
</head>
<body>
<form>
<label form="item">Add an item: </label>
<input id="item" type="text" size="20"><br>
<input id="submitButton" type="button" value="Add!">
</form>
<ul id="list">
</ul>
<p>
Click an item to remove it from the list.
</p>
</body>
</html>
Why not set the value of the item input to an empty string rather than using reset?
document.getElementById("item").value = "";
As for removing the list items...
for (var i = 0; i < ul.children.length; i++) {
ul.children[i].addEventListener("click", removeItem);
}
you can only reset forms, so you have to select the form and then reset will work. f.e. with:
document.forms[0].reset()
your code is adding the eventhandler to all existing li-Elements, if you create some new li-Elements later, you have to add the eventhandler to it manually. f.e. in your addItem-Function with:
li.onclick = removeItem;
after pushing the new Item
in your removeItem-Function you have access on the clicked Element via this, so you can remove only this Element with:
this.remove()
You could change your addItem() and removeItem() functions :
function addItem() {
var newItem = document.getElementById("item").value;
$('#list').append("<li id='" + newItem + "' onclick='removeItem(this)'>" + newItem + "</li>");
}
function removeItem(id) {
$(id).remove();
}
I have a Spring MVC application where I am required to capture a variable number of key value pairs based on user input. The HTML & JS part of the code to render the controls is as follows :
<tr>
<td><label>Attributes (Names & Value(s))</label></td>
<td><input id="Button1" type="button" value="Add" onclick="Button1_onclick()"/></td>
</tr>
<script language="javascript" type="text/javascript">
var NumOfRow = 1;
var attribs = {};
function Button1_onclick() {
NumOfRow++;
// get the reference of the main Div
var mainDiv = document.getElementById('MainDiv');
// create new div that will work as a container
var newDiv = document.createElement('div');
newDiv.setAttribute('id', 'innerDiv' + NumOfRow);
//create span to contain the text
var newSpan = document.createElement('span');
newSpan.innerHTML = "Attribute Type";
// create new textbox for type entry
var newTextBox = document.createElement('input');
newTextBox.type = 'text';
newTextBox.setAttribute('id', 'DimensionType' + NumOfRow);
//create span to contain the text
var newSpan2 = document.createElement('span');
newSpan2.innerHTML = "Attribute Value(s)";
// create new textbox for value entry
var newTextBox2 = document.createElement('input');
newTextBox2.type = 'text';
newTextBox2.setAttribute('id', 'DimensionValue' + NumOfRow);
// create remove button for each attribute
var newButton = document.createElement('input');
newButton.type = 'button';
newButton.value = 'Remove';
newButton.id = 'btn' + NumOfRow;
// attach event for remove button click
newButton.onclick = function RemoveEntry() {
var mainDiv = document.getElementById('MainDiv');
mainDiv.removeChild(this.parentNode);
NumOfRow--;
}
// append the span, textbox and the button
newDiv.appendChild(newSpan);
newDiv.appendChild(newTextBox);
newDiv.appendChild(newSpan2);
newDiv.appendChild(newTextBox2);
newDiv.appendChild(newButton);
// finally append the new div to the main div
mainDiv.appendChild(newDiv);
}
}
</script>
I am not sure how to send this captured data back to my controller when the form is submitted. Please advise. Also if there is a better way to capture such data, those suggestions are most welcome as well.
What about making Capture key event in a text field you can do this :
<html>
<head>
<script language="JavaScript" type = "text/javascript">
<!--
document.onkeypress = DisplayMsg;
function DisplayMsg(key_event)
{
if (document.all) //Checks for IE 4.0 or later
{
document.form1.text2.value = String.fromCharCode(event.keyCode);
}
else if (document.getElementById) //checks for Netscape 6 or later
{
document.form1.text2.value = String.fromCharCode(key_event.which);
}
else if (document.layers) //Checks for Netscape 4
{
document.form1.text2.value = String.fromCharCode(key_event.which);
}
}
//-->
</script>
<title>Capture Key Pressed</title>
</head>
<body>
<form name="form1">
<b>Type value in field: See what you typed:</b><br>
<input type = "text" name = "text1" onKeyPress="DisplayMsg(event)" size="20">
<input type = "text" name = "text2" onKeyPress="DisplayMsg(event)" size="20">
</form>
</body>
</html>