I'm new to JS. I'm trying to delete the parent node with all the children by clicking a button. But the console tells me that undefined is not a function. What am I missing?
Fiddle:
http://jsfiddle.net/vy0d8bqt/
HTML:
<button type="button" id="output">Get contacts</button>
<button type="button" id="clear_contacts">clear contact</button>
<div id="output_here"></div>
JS:
// contact book, getting data from JSON and outputting via a button
// define a JSON structure
var contacts = {
"friends" :
[
{
"name" : "name1",
"surname" : "surname1"
},
{
"name" : "name2",
"surname" : "surname2"
}
]
};
//get button ID and id of div where content will be shown
var get_contacts_btn = document.getElementById("output");
var output = document.getElementById("output_here");
var clear = document.getElementById("clear_contacts");
var i;
// get length of JSON
var contacts_length = contacts.friends.length;
get_contacts_btn.addEventListener('click', function(){
//console.log("clicked");
for(i = 0; i < contacts_length; i++){
var data = contacts.friends[i];
var name = data.name;
var surname = data.surname;
output.style.display = 'block';
output.innerHTML += "<p> name: " + name + "| surname: " + surname + "</p>";
}
});
//get Children of output div to remove them on clear button
//get output to clear
output_to_clear = document.getElementById("output_here");
clear.addEventListener('click', function(){
output_to_clear.removeNode(true);
});
You should use remove() instead of removeNode()
http://jsfiddle.net/vy0d8bqt/1/
However, this also removes the output_to_clear node itself. You can use output_to_clear.innerHTML = '' if you like to just delete all content of the node, but not removing the node itself (so you can click 'get contacts' button again after clearing it)
http://jsfiddle.net/vy0d8bqt/3/
You want this for broad support:
output_to_clear.parentNode.removeChild(output_to_clear);
Or this in modern browsers only:
output_to_clear.remove();
But either way, make sure you don't try to remove it after it has already been removed. Since you're caching the reference, that could be an issue, so this may be safer:
if (output_to_clear.parentNode != null) {
output_to_clear.remove();
}
If you were hoping to empty its content, then do this:
while (output_to_clear.firstChild) {
output_to_clear.removeChild(output_to_clear.firstChild);
}
I think using jQuery's $.remove() is probably the best choice here. If you can't or don't want to use jQuery, The Mozilla docs for Node provides a function to remove all child nodes.
Element.prototype.removeAll = function () {
while (this.firstChild) { this.removeChild(this.firstChild); }
return this;
};
Which you would use like:
output_to_clear.removeAll();
For a one-off given the example provided:
while (output_to_clear.firstChild) { output_to_clear.removeChild(output_to_clear.firstChild); }
Related
I have the following tag in my view.jsp:
<liferay-ui:input-localized id="message" name="message" xml="" />
And I know that I can set a XML and have a default value on my input localized. My problem is that I want to change this attribute with javascript. I am listening for some changes and call the function "update()" to update my information:
function update(index) {
var localizedInput= document.getElementById('message');
localizedInput.value = 'myXMLString';
}
Changing the value is only updating the currently selected language input (with the whole XML String). The XML String is correct, but I am not sure on how to update the XML for the input with javascript.
Is this possible?
PS: I have posted this in the Liferay Dev forum to try and reach more people.
After a week of studying the case and some tests, I think that I found a workaround for this. Not sure if this is the correct approach, but it is working for me so I will post my current solution for future reference.
After inspecting the HTML, I noticed that the Liferay-UI:input-localized tag creates an input tag by default, and then one more input tag for each language, each time you select a new language. Knowing that I created some functions with Javascript to help me update the inputs created from my liferay-ui:input-localized. Here is the relevant code:
function updateAnnouncementInformation(index) {
var announcement = announcements[index];
// the announcement['message'] is a XML String
updateInputLocalized('message', announcement['message']);
}
function updateInputLocalized(input, message) {
var inputId = '<portlet:namespace/>' + input;
var xml = $.parseXML(message);
var inputCurrent = document.getElementById(inputId);
var selectedLanguage = getSelectedLanguage(inputId);
var inputPT = document.getElementById(inputId + '_pt_PT');
inputPT.value = $(xml).find("Title[language-id='pt_PT']").text();
var inputEN = document.getElementById(inputId + '_en_US');
if (inputEN !== null) inputEN.value = $(xml).find("Title[language-id='en_US']").text();
else waitForElement(inputId + '_en_US', inputCurrent, inputId, xml);
var inputLabel = getInputLabel(inputId);
if (selectedLanguage == 'pt-PT') inputLabel.innerHTML = '';
else inputLabel.innerHTML = inputPT.value;
if (selectedLanguage == 'pt-PT') inputCurrent.value = inputPT.value;
else if (inputEN !== null) inputCurrent.value = inputEN.value;
else waitForElement(inputId + '_en_US', inputCurrent, inputId, xml);
}
function getSelectedLanguage(inputId) {
var languageContainer = document.getElementById('<portlet:namespace/>' + inputId + 'Menu');
return languageContainer.getElementsByClassName('btn-section')[0].innerHTML;
}
function getInputLabel(inputId) {
var boundingBoxContainer = document.getElementById(inputId + 'BoundingBox').parentElement;
return boundingBoxContainer.getElementsByClassName('form-text')[0];
}
function waitForElement(elementId, inputCurrent, inputId, xml) {
window.setTimeout(function() {
var element = document.getElementById(elementId);
if (element) elementCreated(element, inputCurrent, inputId, xml);
else waitForElement(elementId, inputCurrent, inputId, xml);
}, 500);
}
function elementCreated(inputEN, inputCurrent, inputId, xml) {
inputEN.value = $(xml).find("Title[language-id='en_US']").text();
var selectedLanguage = getSelectedLanguage(inputId);
if (selectedLanguage == 'en-US') inputCurrent.value = inputEN.value;
}
With this I am able to update the liferay-ui:input-localized inputs according to a pre-built XML String. I hope that someone finds this useful and if you have anything to add, please let me know!
To change the text value of an element, you must change the value of the elements's text node.
Example -
xmlDoc.getElementsByTagName("title")[0].childNodes[0].nodeValue = "new content"
Suppose "books.xml" is loaded into xmlDoc
Get the first child node of the element
Change the node value to "new content"
I'm trying to make a small script that allows for a little notes section. This section would have an input box that allows for adding elements to the list; which will be saved in localStorage so they are not lost when I refresh or close the browser. The code I have is as follows (it's all done through JS even the html, but ignore that.)
var notes = [];
var listthings = "<h2 id=\"titlething\">Notes</h2>" +
"<ul id=\"listing\">" +
"</ul>"
"<input type=\"text\" name=\"item\" id=\"textfield\">" +
"<input type=\"submit\" id=\"submitthing\" value=\"Submit\">";
JSON.parse(localStorage.getItem('notes')) || [].forEach( function (note) {
"<li id=\"listitem\">" + notes + "</li>";
})
$('#submitthing').click(function() {
notes.push($('#textfield').val());
});
localStorage.setItem('notes', JSON.stringify(notes));
Also, how would I go about appending the latest added li between the opening and closing tag? Obviously I'd usually do it using jQuery, but this is puzzling me a little. However, only the 'Notes' loads at the top, any ideas?
Your approach is way off the mark. You don't need JSON at all (this just confuses things) and you don't need to manually create HTML.
Also, you can use an array to store the notes, but since localStorage is the storage area, so an array is redundant. Additionally, without using an array, you don't need JSON. The entire problem becomes much easier to solve.
Unfortunately, the following won't run here in this snippet editor, due to security issues, but it would do what you are asking. This fiddle shows it working: https://jsfiddle.net/Lqjwbn1r/14/
// Upon the page being ready:
window.addEventListener("DOMContentLoaded", function(){
// Get a reference to the empty <ul> element on the page
var list = document.getElementById("notes");
// Loop through localStorage
for (var i = 0; i < localStorage.length; i++){
// Make sure that we only read the notes from local storage
if(localStorage.key(i).indexOf("note") !== -1){
// For each item, create a new <li> element
var item = document.createElement("li");
// Populate the <li> with the contents of the current
// localStorage item's value
item.textContent = localStorage.getItem(localStorage.key(i));
// Append the <li> to the page's <ul>
list.appendChild(item);
}
}
// Get references to the button and input
var btn = document.getElementById("btnSave");
var note = document.getElementById("txtNote");
// Store a note count:
var noteCount = 1;
// When the button is clicked...
btn.addEventListener("click", function(){
// Get the value of the input
var noteVal = note.value;
// As long as the value isn't an empty string...
if(noteVal.trim() !== ""){
// Create the note in localStorage using the
// note counter so that each stored item gets
// a unique key
localStorage.setItem("note" + noteCount, noteVal);
// Create a new <li>
var lstItem = document.createElement("li");
// Set the content of the <li>
lstItem.textContent = noteVal;
// Append the <li> to the <ul>
list.appendChild(lstItem);
// Bump up the note counter
noteCount++;
}
});
});
<input type=text id=txtNote><input type=button value=Save id=btnSave>
<ul id=notes></ul>
This is how I would approach it using jquery. but depens how complex this should be. this is just simple demo.
<input type="text" id="note" />
<button id="add">add note</button>
<ul id="notes"></ul>
javascript and jquery
function addNote(){
var data = localStorage.getItem("notes")
var notes = null;
if(data != null)
{
notes = JSON.parse(data);
}
if(notes == null){
notes = [];
}
notes.push($("#note").val());
localStorage.setItem("notes", JSON.stringify(notes));
refreshNotes();
}
function refreshNotes(){
var notesElement =$("#notes");
notesElement.empty();
var notes = JSON.parse(localStorage.getItem("notes"));
for(var i = 0; i< notes.length; i++){
var note = notes[i];
notesElement.append("<li>"+note+"</li>");
}
}
$(function(){
refreshNotes();
$("#add").click(function(){
addNote();
});
})
example:
http://codepen.io/xszaboj/pen/dOXEey?editors=1010
I am using Meteor and I am trying to check if a text is html. But usual ways do not work. This is my code:
post: function() {
var postId = Session.get("postId");
var post = Posts.findOne({
_id: postId
});
var object = new Object();
if (post) {
object.title = post.title;
if ($(post.content).has("p")) { //$(post.content).has("p") / post.content instanceof HTMLElement
object.text = $(post.content).text();
if (post.content.match(/<img src="(.*?)"/)) {
object.image = post.content.match(/<img src="(.*?)"/)[1];
}
} else {
console.log("it is not an html------------------------");
object.text = post.content;
}
}
return object;
}
Actually, this is the most "working" solution I have used up to now. Also, I pointed out the two most common ways which I use (next to the if statement). Is it possible to happen without regex.
Can use approach you already started with jQuery but append response to a new <div> and check if that element has children. If jQuery finds children it is html.
If it is html you can then search that div for any type of element using find().
// create element and inject content into it
var $div=$('<div>').html(post.content);
// if there are any children it is html
if($div.children().length){
console.log('this is html');
var $img = $div.find('img');
console.log('There are ' + $img.length +' image(s)');
}else{
console.log('this is not html');
}
Use the jquery $.parseHTML function to parse the string into an array of DOM nodes and check if it has any HTMLElement.
var htmlText = "----<b>abc</b>----<h3>GOOD</h3>----";
htmlText = prompt("Please enter something:", "----<b>abc</b>----");
var htmlArray = $.parseHTML(htmlText);
var isHtml = htmlArray.filter(function(e){ return e instanceof HTMLElement;}).length;
console.log(htmlText);
//console.log(htmlArray);
if (isHtml)
console.log(isHtml + " HTML Element(s) found.");
else
console.log("No HTML Elements found!");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'm trying to make a quiz powered by jQuery (and maybe JSON), with the values stored in a database. It works fine so far, but I'd like to hide the radio buttons (CSS: display: none) and make each question look like a button (much easier to select than a tiny radio button).
However, when I do this, the following JavaScript doesn't work, and the quiz isn't scored.
var imgpath = "/images/sections/test/";
var jsonpath = "/2b/inc/pages/quiz-php/json/";
var jsonfile = "key";
$(document).ready(function(){
//Make sure radio buttons are not disabled or checked (helpful when refreshing)
$("input[type='radio']").attr("disabled", false);
$("input[type='radio']").attr("checked", false);
$(".submit").click(function(e){
e.preventDefault();
//Check the quiz results
checkQuiz();
});
//Build the json filename
jsonfile = $("#quiz").attr("rel")+".php";
});
//Load json file
function getData(update){
$.getJSON(jsonpath+jsonfile, function(json){
//Execute the callback
update(json);
}).error(function(){alert("error");});
}
function checkQuiz(){
$(".submit").remove();
getData(function(data){
var ans = data.key;
var result = {};
$(".Question").each(function(){
//Get the question id
var _q = $(this).attr("id");
//Get the selected answer class
var _a = $("#"+_q+" input:checked").closest("li").attr("class");
//Add the values to the result object
result[_q] = _a;
//Compare the selected answer with the correct answer
if(ans[_q]==_a){
$(this).addClass("correct");
}else{
$(this).addClass("wrong");
}
});
//Build the feedback
var fdbck = "You got "+$(".correct").length+" out of "+$(".Question").length+" correct. "
if($(".correct").length==0){
fdbck += "Better luck next time.";
}else if($(".correct").length>$(".Question").length/2){
fdbck += "Good job!";
}else{
fdbck += "Not bad.";
}
$(".feedback").text(fdbck);
$(".feedback").show();
});
}
So I wondered if there's some way to record scores besides a radio button. I created a JSFiddle # http://jsfiddle.net/9j7fz99w/6/ to illustrate how I'm using jQuery and CSS to style correct and incorrect answers. Is there a way to modify the code above to similarly recognize correct questions based on their "selection," rather than a radio button?
Just a small example using a JS questions Array with Objects
var $quizEl = $("#quizEl");
var $submit = $("#submit");
var quiz = [
{ // obj
"Q" : "What color is the Sun?",
"A" : ["Red", "Black", "Yellow"],
"C" : 2
},{
"Q" : "What color is an Elephant?",
"A" : ["Gray", "Blue", "Yellow"],
"C" : 0 // zero indexed!
},{
"Q" : "What color is the Sea?",
"A" : ["Fuchsia", "Blue", "Gold"],
"C" : 1
}
];
var qNum = quiz.length;
// FUNCTION THAT CREATES AND APPENDS AN `UL` TO `DIV #quizEl`
function generateQuestion( obj, idx ) {
var html = "<h2>"+ obj.Q +"</h2><ul>";
for (var i=0; i<obj.A.length; i++) {
html += "<li>"+
"<label>"+
"<input type='radio' name='"+ idx +"' value='"+i+"'>"+
obj.A[i] +"</label>"+
"</li>";
}
$quizEl.append( html+"</ul>" );
}
// GENERATE ALL QUESTIONS:
for(var i=0; i<qNum; i++) {
generateQuestion( quiz[i], i ); // quiz[i] is the {QAC} object
}
$quizEl.on("change", ":radio", function(){ // Record User choice (U property)
quiz[this.name].U = this.value; // set 0,1,2 to the new U property {QACU}
});
$submit.on("click", function(e){
e.preventDefault();
console.log( quiz ); // To test how it looks
// Check if user answered them all:
for(var i=0; i<qNum;i++){
if(!quiz[i].hasOwnProperty("U")){ // User did not answered if "U" property doesn't exists
return alert("Please,\nanswer the question "+ (i+1) +":\n"+ quiz[i].Q );
}else{ // Add classes...
$("ul").eq(i).find(":checked").closest("li")
.addClass( +quiz[i].U === quiz[i].C ? "correct":"wrong");
}
}
// Finally colour them!
$(".correct").css({background:"green"});
$(".wrong").css({background:"red"});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="quizEl"></div>
<input id="submit" type="submit">
I am new to javascript and I can't populate many fields with one click.
<script>
function addTxt(txt, field)
{
var myTxt = txt;
var id = field;
document.getElementById(id).value = myTxt;
}
</script>
<input type="text" name="xx" id="info" autofocus="required">
<p>x</p>
I've got 3 more fields.
Thanks.
You can use
function addTxt(txt, ids)
{
for (var i=0, l=ids.length; i<l; ++i) {
document.getElementById(ids[i]).value = txt;
}
}
And call it like
addTxt('Some text', ['id1', 'id2', 'id3']);
You can populate multiple fields. I have shared a jsfiddle link. You can populate multiple fields using this code.
function addTxt(_val, _id,_no)
{
var _myTxt = _val;
var _id = _id;
for(var i=1;i<=_no;i++){
document.getElementById(_id+i).value = _myTxt;
}
}
Click here to see DEMO
I think you don't need a function to do this.
Just use
document.getElementById('id1').value
= document.getElementById('id2').value
= document.getElementById('id3').value
= 'Some text';
Or, if you think document.getElementById is too long, use a shortcut:
var get = document.getElementById;
/* ... */
get('id1').value = get('id2').value = get('id3').value = 'Some text';
Try getting the elements by tagName or by className instead of by id, then using a for loop to iterate through each one.