Making list from textarea value by new lines - javascript

This may be very easy to solve but my brain is dead for some reason I can't find out the right road to success :(
I have some text area where by pressing enter for each word or more words in one line I get an list item.
$(document).on('click','#addList', function(){
var lines = $('#list').val().split(/\n/);
var texts = []
for (var i=0; i < lines.length; i++) {
if (/\S/.test(lines[i])) {
texts.push($.trim(lines[i]));
}
}
var list = JSON.stringify(texts);
for(var e=0; e<list.length; e++){
var li = li+'<li class="c1_2v">'+list[e]+'</li>';
}
$('.content').append($('<ul>'+li+'</ul>'));
});
By doing this $.trim I am getting problem if I have more words in one line but it is useful if I have more empty new lines or spaces before first word.
Example:
<textarea>
this is
a
something
that
I want to add to new lists
</textarea>
By my code and first for loop I get something like: ['this','is','a','something','that','I','want','to','add','to','new','lists']
By second for loop I get into li tags every letter or character from [ to ] inside li tags
I don't understand regex I saw many websites but it is not getting into my head so even if you add it as more easier answer without explanation what is used for what I wouldn't know how it works..
And this is basically what I need to get in .content div:
<ul>
<li class="c1_2v">this is</li>
<li class="c1_2v">a</li>
<li class="c1_2v">something</li>
<li class="c1_2v">that</li>
<li class="c1_2v">I want to add to new lists</li>
</ul>
I will add snippet how it works till now:
$(document).on('click','#addList', function(){
var lines = $('#list').val().split(/\n/);
var texts = []
for (var i=0; i < lines.length; i++) {
if (/\S/.test(lines[i])) {
texts.push($.trim(lines[i]));
}
}
var list = JSON.stringify(texts);
for(var e=0; e<list.length; e++){
var li = li+'<li class="c1_2v">'+list[e]+'</li>';
}
$('.content').append($('<ul>'+li+'</ul>'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="list"></textarea>
<button id="addList">Add</button>
<div class="content"></div>
And also there is something undefined Idk what :(
As #AlexKudryashev commented I used array as string not as array and if I add var li before for loop undefined will go away.

$(document).on('click', '#addList', function() {
var lines = $('#list').val().split(/\n/);
var texts = []
for (var i = 0; i < lines.length; i++) {
if (/\S/.test(lines[i])) {
texts.push($.trim(lines[i]));
}
}
//var list = JSON.stringify(texts);
var list = texts;
var li = "";
for (var e = 0; e < list.length; e++) {
li = li + '<li class="c1_2v">' + list[e] + '</li>';
}
$('.content').append($('<ul>' + li + '</ul>'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="list"></textarea>
<button id="addList">Add</button>
<div class="content"></div>
JSON.stringify converts the value to JSON string. So you are looping every string instead of the array. Also, you were getting undefined since li is not defined. To avoid simply define li as "" empty string.

Here is a simplified solution that requires no regex. You can use array.filter and array.map to consolidate.
document.querySelector('button').onclick = () => {
var text = document.querySelector('textarea').value;
var lines = text.split('\n');
var html = lines
.filter(line => line.trim() !== '')
.map(line => `<li class="c1_2v">${line}</li>`)
.join('');
document.querySelector('ul').innerHTML = html;
}
<textarea>
this is
a
something
that
I want to add to new lists
</textarea>
<button>Click me</button>
<ul><!--output goes here--></ul>

Related

javascript printing array into paragraphs

I am trying to make a local html to display some text from txt file (also local).
I used this to read file into array and print it:
<input type="file" name="files" id="inputfile">
<script type="text/javascript">
document.getElementById('inputfile')
.addEventListener('change', function() {
var test=new FileReader();
test.onload=function(){
document.getElementById('output')
.textContent=fl.result;
}
test.readAsText(this.files[0]);
})
</script>
However, I would like to print it from the array into paragraphs, line by line (first line goes into heading, second into paragraph, third into heading and so on...).
Is there a way to do it automaticaly from an array, or would I have to do it by hand for each one?
I am kinda green in javascript so I would rather refrain from using node etc.
If the headers and paragraphs are always strictly alternating, you can check whether each array index is odd or even to decide whether to wrap it in header or paragraph tags. One way:
arr = ["header", "paragraph", "header", "paragraph", "header", "paragraph"]
joined = arr.map((el, i) => {
return (i % 2 === 0) ? `<h1>${el}</h1>` : `<p>${el}</p>` ;
}).join('')
console.log(joined)
const arr = ['Heading 1','Para1','Heading 2','Para2','Heading 3','Para3'];
const result = arr.map((val, i) => i%2===0 ? `<h2>${val}</h2>` : `<p>${val}</p>`).join('');
document.getElementById('output').innerHTML = result ;
<div id="output"></div>
Put this in your code:
function arrToPar(arr){ //For JS-Array --> HTML content
var out = "";
for(var i = 0; i < arr.length; i++){
out += arr[i] + "<br>";
}
return(out);
}
Or...
function arrToString(arr,joiner = " "){ //For JS-Array --> JS-String
var out = ""; //The parameter "joiner", by default, is a space
//This means that you only need to specify "arr", but you can do
//a second parameter. This function behaves like arr.join(joiner).
for(var i = 0; i < arr.length; i++){
out += arr[i] + joiner;
}
}

How can insert code in createTextNode

Is there a way to insert HTML tag in 'createTextNod' or what else can I do
$.each(JSON.parse(results), function(i, field){
for(var i = 1; i < JSON.parse(results).length; i++) {
var newLi = document.createElement('li');
var textNode = document.createTextNode(field.fname + ' ' + field.lname + ((field.status == 1) ? '<span class="userChatNameOnline">online</span>' : ''));
newLi.appendChild(textNode);
var ul = document.getElementById('ulUsers');
ul.insertBefore(newLi, ul.childNodes[0]);
}
})
Issues
The following part of OP code is pretty awful:
$.each(JSON.parse(results), function(i, field){
for(var i = 1; i < JSON.parse(results).length; i++) {...
$.each() iterates through for each field in JSON which is OK. But you use another loop which is totally unnecessary since $.each() and for loop both iterate through arrays. Each of these loops is calling JSON.parse() on each iteration. Although no matter how bad this is, you'll probably never notice any lag unless you handle large amounts of data.
References
The following are links to what was used:
Template Literals
.insertAdjacentHTML()
Demo
var results = `[{"first":"Kaiser","last":"Soze","status":"1"},{"first":"Darth","last":"Vader","status":"0"},{"first":"Boba","last":"Fett","status":"0"},{"first":"Grim","last":"Reaper","status":"1"},{"first":"zer0","last":"0ne","status":"1"}]`;
var JSONData = JSON.parse(results);
var list = document.getElementById('users');
$.each(JSONData, function(idx, field) {
var name = `[${idx}]: ${field.first} ${field.last}`;
var status = `<b class='status' data-status='${field.status}'>${field.status === "1" ? 'Online' : 'Offline'}</b>`;
list.insertAdjacentHTML('beforeend', `<li class='userData'>${name} ${status}</li>`);
});
#users {
width: 50%;
list-style: none
}
.userData {
font: 400 16px/1.5 Consolas
}
.status {
float: right
}
[data-status='1'] {
color: green
}
[data-status='0'] {
color: red
}
<ul id='users'></ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
createTextNode is for creating a TextNode specifically, not inserting HTML. For the latter you can use innerHTML or insertAdjecentHtml
since you're using jQuery, you probably want to just create your nodes using $() and .html():
$.each(JSON.parse(results), function(i, field){
var ul = $('#ulUsers');
for (var i = 1; i < JSON.parse(results).length; i++) {
var li = $('<li></li>').html('<span>' + ... + '</span>');
ul.before(li);
}
}
If you want to streamline it, I suggest appending to a DocumentFragment and then appending the fragment's contents to #ulUsers in one go. jQuery encapsulates this if you pass an array of elements to be apppended (of course, if you want to give the dynamic effect of seeing the list grow as elements are added to the list, you wouldn't (need to) do this):
$.each(JSON.parse(results), function(i, field){
var ul = $('#ulUsers');
var li_array = [];
for (var i = 1; i < JSON.parse(results).length; i++) {
var li = $('<li></li>').html('<span>' + ... + '</span>');
li_array.push(li);
}
ul.before(li_array);
}

Strange Javascript for loop behavior when using Jquery append

I'm probably missing/doing something silly, but I can't seem to work this out:
Here's a fiddle showing the problem:
https://jsfiddle.net/jhqjmcn4/1/
Note that you will need to open your console to see what is happening.
Basically, in this example, I have two functions containing a for loop that are identical to each other except the second one contains a JQuery append.
The goal of the function is to get the html elements from within a string, which works fine in the first function, but not the second.
As can be seen in the console, this causes anything that is not a text node to be ignored and not added to the list. In this case, the b and p tags are not being included.
Here is the code again:
JS:
function parse_text(text) {
var div = document.createElement("DIV");
div.innerHTML = text;
var elements = div.childNodes;
var container = jQuery("#container");
var list = [];
for (var i = 0; i < elements.length; i++){
var element = elements[i];
list.push(element);
console.log("First", list);
}
}
function parse_text_two(text) {
var div = document.createElement("DIV");
div.innerHTML = text;
var elements = div.childNodes;
var container = jQuery("#container2");
var list = [];
for (var p = 0; p < elements.length; p++){
var element = elements[p];
list.push(element);
console.log("Second", list);
container.append(element);
}
}
var text = "Here is <b>some</b> text with <p>html</p> in it";
parse_text(text);
parse_text_two(text);
html (irrelevant):
<div id="container">
</div>
<div id="container2">
</div>
Thanks in advance.
I suppose you need to have a Array.prototype.filter() method to get the html elements:
function parse_text_two(text) {
var div = document.createElement("DIV");
div.innerHTML = text;
var elements = [].filter.call(div.childNodes, function(el) {
return el.nodeType !== 3;
});
var container = jQuery("#container2");
var list = [];
for (var p = 0; p < elements.length; p++) {
var element = elements[p];
list.push(element);
console.log("Second", list);
container.append(element);
}
}
var text = "Here is <b>some</b> text with <p>html</p> in it";
parse_text_two(text);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
</div>
<div id="container2">
</div>
You can check updated fiddle here jsfiddle.net/bharatsing/jhqjmcn4/3/
Its return same result for both methods in console as per you want.
function parse_text_two(text) {
var div = document.createElement("DIV");
div.innerHTML = text;
var elementsOrg = div.childNodes;
var elements = Array.prototype.slice.call(elementsOrg);;
var container = jQuery("#container2");
var list = [];
for (var p = 0; p < elements.length; p++){
var element = elements[p];
list.push(element);
console.log("Second", list);
container.append(element);
}
}
The issue I saw by putting a debug point inside the loop was this:
The container.append(element); statement was actually modifying the elements array and was removing the appended element from the array. Which meant that in the loop for various values of 'p' the elements array looked like this:
p = 0 -> elements : [ text, b, text, p, text ] // text node at 0 picked
p = 1 -> elements : [ b, text, p, text ] // text node at 1 picked
p = 2 -> elements : [ text, p, text ] // text node at 2 picked
That is why the loop only ran 3 times instead of the original length of the elements array , i.e. 5.
This probably happens because jQuery 'moves' the node from its original place to the container div.
You can either clone the element node and then append into the container:
function parse_text_two(text) {
var div = document.createElement("DIV"),
p,
element,
elements,
container = jQuery("#container2"),
list = [];
div.innerHTML = text;
elements = div.childNodes;
for (p = 0; p < elements.length; p++){
element = elements[p];
list.push(element);
console.log("Second", list);
container.append($(element).clone());
}
}
Or use a while loop as suggested in Venkatesh's answer. Anyway, it is always better to know the root cause. :)
Hope this helps.
In second function in each loop comment this line container.append(element);

Select all element with same tag name using javascript and highlight content partially

I made a code that should highlight searched string but it is not working.
Here is the code:
<body>
<div>div is here</div>
<div id="divid">
<div>this is a div 1</div>
<div> this is a div 2</div>
<div> this is a div3</div>
</div>
<div> another div is here</div>
</body>
Here is a javascript code.
function checkit(){
var hlWord = "div";
var nregex = new RegExp(hlWord,"gi");
var div = document.getElementById("divid").getElementsByTagName('div');
for(var i=0; i <= div.length; i++){
var div1 = div[i].innerHTML;
var rword = div1.replace(nregex,"<b>"+hlWord+"</b>");
div1.innerHTML = rword;
}
}
There are begginer mistakes in your code. Let me correct them:
function checkit(){
var hlWord = "div"; //Define string that will be emphasized by <b> tag
var nregex = new RegExp(hlWord,"gi");//Create global, case-insensitive regexp
var div = document.getElementById("divid").getElementsByTagName('div'); //Get element collection of divs in div#divid
for(var i=0; i < div.length; i++){ //Loop through my element collection
var div1 = div[i].innerHTML; //Get the innerHTML of on of the divs
var rword = div1.replace(nregex,"<b>"+hlWord+"</b>"); //Surround my string with <b>
div[i].innerHTML = rword; //Change the innerHTML back
}
}
You used this for condition: i<=div.length. This is wrong. Do not forget, that we count from 0 so: [0, 1, 2, 3].length = 4. Last element for such array has index 3. The [] is an array literal.
By mistake, you assigned div1.innerHTML. div1 was a string. The element you want to change is div[i].
I made a JSFiddle too!
The problem with you code will be, amongst other problems, that nested div elements will be broken. You should use some kind of recursion if you want to highlight the word 'div'.
Here is such a function:
function highLight(term,root){
var allDiv = root.querySelectorAll('div'),
replacer = function(a){return '<span class="highlight">'+a+'</span>'};
for (var i=0; i<allDiv.length; i+=1){
if (allDiv[i].querySelectorAll('div').length){
highLight(term, allDiv[i]);
} else {
var re = RegExp('('+term+')','gi');
allDiv[i].innerHTML = allDiv[i].innerHTML.replace(re,replacer);
}
}
}
And here is a jsfiddle to play around with it
A more advanced jsfiddle
You have several errors: there you go:
http://jsfiddle.net/55U6j/1/
function checkit(){
var hlWord = "div";
var nregex = new RegExp(hlWord,"gi");
var divs = document.getElementById("divid").getElementsByTagName('div');
for(var i=0; i < divs.length; i++){
var div = divs[i];
var html = div.innerHTML;
var rword = html.replace(nregex,"<b>"+hlWord+"</b>");
div.innerHTML = rword;
}
}

Create and Append an element, innerHTML? the horror... [please no jquery]

I have a script that returns a list in alphabetical order as follows
<div id="x">
<ul>
<li>Apple
<li>Banana
<li>Blackberry
<li>Blueberry
<li>Cherry
<li>Cranberry
</ul>
</div>
However there are many items (almost 100) in the list and I am hoping to rearrange them as follows
<div id="x">
<span id="A">A</span>
<ul>
<li>Apple
</ul>
<span id="B">B</span>
<ul>
<li>Banana
<li>Blackberry
<li>Blueberry
</ul>
<span id="C">C</span>
<ul>
<li>Cherry
<li>Cranberry
</ul>
<div>
I'm not really sorting fruit btw, this is just an example.
It MUST be in that form, for reasons that matter not, I just need help creating and appending the span elements and the individual lists.
I have tried using inner/outer HTML and I'm finding it really really difficult. I currently have something like this:
function getAllLists()
{
var page = document.getElementById("x")
var allLists = page.getElementsByTagName("li");
var num = allLists.length;
//Some form of a for counter loop here
for (var counter = 0; counter < num; counter++) {
var first=allLists[counter].outerHTML;
var second=allLists[counter+1].outerHTML;
var firstletter= (allLists[counter].substring(0, 1)).toUpperCase();
var secondletter= (allLists[counter+1].substring(0, 1)).toUpperCase();
allLists[counter].outerHTML = '<span id="'+firstletter+'">'+firstletter+'</span>'+first;
}
}
PLEASE PLEASE PLEASE PLEASE AVOID USING JQUERY.
I can't stress this enough!!
Not only do I find it extremely difficult to understand, as I am still an amateur at javascript and find js already difficult enough as it is, the syntax for jquery is like just stupidly hard to understand.
I am certain it is possible to achieve what I am aiming for WITHOUT the need to use jquery.
Any ideas? all help/comments/ideas are more than appreciated.
Many thanks.
Firstly forget all about manipulating the DOM using inner/outerHTML. They are handy for inserting chunks of HTML or sections of documents, but they are definitely not intended for general DOM manipulation.
Use DOM methods.
Firstly, load all the LI elements into an array. Then sort them using a sort function. Then put them back into the DOM wrapped in UL elements and separated by spans each time the first letter changes.
Edit
Here's a function that does the job. It sorts the lIs, not sure if that's really needed. If not, the function becomes a lot simpler.
<script type="text/javascript">
// Simple helper
function getText(el) {
if (typeof el.textContent == 'string') {
return el.textContent.replace(/^\s+|\s+$/g,'');
}
if (typeof el.innerText == 'string') {
return el.innerText.replace(/^\s+|\s+$/g,'');
}
}
function sortLIs(id) {
// Get the element
var el = document.getElementById(id);
// Get the UL element that will be replaced
var sourceUl = el.getElementsByTagName('ul')[0];
// Get the LIs and put them into an array for sorting
var nodes = sourceUl.getElementsByTagName('li');
var li, lis = [];
for (var i=0, iLen=nodes.length; i<iLen; i++) {
lis[i] = nodes[i];
}
// Sort them
lis.sort(function(a, b) {
return getText(a) > getText(b)? 1 : -1;
});
// Now put them into the document in different ULs separated
// by spans.
// Create some temporary elements for cloning
var ul, ulo = document.createElement('ul');
var sp, spo = document.createElement('span');
var frag = document.createDocumentFragment(); // fragments are handy
var firstChar, currentChar;
// For each LI in the array...
for (i=0; i<iLen; i++) {
li = lis[i];
firstChar = getText(li).substr(0,1) || '';
// If first char doesn't match current, create a new span
// and UL for LIs
if (firstChar !== currentChar) {
currentChar = firstChar;
// New span
sp = spo.cloneNode(false);
sp.appendChild(document.createTextNode(firstChar.toUpperCase()));
sp.id = firstChar;
frag.appendChild(sp);
// New UL
ul = ulo.cloneNode(false);
frag.appendChild(ul);
}
// Add the li to the current ul
ul.appendChild(li);
}
// Replace the UL in the document with the fragment
el.replaceChild(frag, sourceUl);
}
</script>
<div id="x">
<ul>
<li>Cherry
<li>Banana
<li>Apple
<li>Blueberry
<li>Cranberry
<li>Blackberry
</ul>
</div>
<button onclick="sortLIs('x');">Sort</button>
Note that the LIs are just moved to the document fragment and that the original UL is replaced by multiple elements. I've jumbled the LIs to show that the sort works.
Edit 2
If you have the array as text, then:
var fruits = ['Cherry','Banana','Apple','Blueberry',
'Cranberry','Blackberry'].sort();
function insertFruits(id) {
var el = document.getElementById(id);
// Check that the above worked
if (!el) return;
var frag = document.createDocumentFragment();
var li, lio = document.createElement('li');
var ul, ulo = document.createElement('ul');
var sp, spo = document.createElement('span');
var firstChar, currentChar;
for (var i=0, iLen=fruits.length; i<iLen; i++) {
fruit = fruits[i];
firstChar = fruit.substr(0,1).toUpperCase();
if (firstChar !== currentChar) {
currentChar = firstChar;
sp = spo.cloneNode(false);
sp.appendChild(document.createTextNode(firstChar));
sp.id = firstChar;
frag.appendChild(sp);
ul = ulo.cloneNode(false);
frag.appendChild(ul);
}
li = lio.cloneNode(false);
li.appendChild(document.createTextNode(fruit));
ul.appendChild(li);
}
el.appendChild(frag);
}
HTML:
<body>
<div id="x">
<ul>
<li>Apple
<li>Banana
<li>Blackberry
<li>Blueberry
<li>Cherry
<li>Cranberry
</ul>
<ul id="new"></ul>
JavaScript:
var list = document.querySelector('#x ul'),
newUl = document.getElementById('new'),
fruits = [],
key = "A";
for(var i=0; i<list.children.length; i++){
fruits.push(list.children[i].innerText);
}
fruits.sort();
for(var i=0; i<fruits.length; i++){
if(key == fruits[i].split('')[0]){
var span = document.createElement('span'),
li = document.createElement('li');
span.setAttribute('id', key);
li.innerText = fruits[i];
if(document.getElementById(key)){
document.getElementById(key).appendChild(li);
}
else{
span.appendChild(li);
newUl.appendChild(span);
}
}
if(fruits[i+1]){
key = fruits[i+1].split('')[0];
}
}
Example:Live Code
Well, this is the way I get it done:
var allLists, elements, item, lastLetter, lastUl, letter, page, span, _i, _len;
page = document.getElementById("x");
allLists = page.getElementsByTagName("li");
lastLetter = null;
lastUl = null;
elements = document.createDocumentFragment();
for (_i = 0, _len = allLists.length; _i < _len; _i++) {
item = allLists[_i];
letter = item.innerText[0].toUpperCase();
if (letter !== lastLetter) {
lastLetter = letter;
span = document.createElement('span');
span.innerText = letter;
span.id = letter;
elements.appendChild(span);
lastUl = document.createElement('ul');
elements.appendChild(lastUl);
}
lastUl.appendChild(item.cloneNode(true));
}
while (page.firstChild) page.removeChild(page.firstChild);
page.appendChild(elements.cloneNode(true));
See this working here: http://jsfiddle.net/HjWhY/

Categories