Why isn't JavaScript for loop incrementing? - javascript

I'm trying to replace the <li> with 1. 2. 3. respectively. I managed to change the <li> to a number, but that number is 0. The loop doesn't want to work. To be honest, this method may be impossible.
Take a look at the Fiddle if you'd like.
This is my function(){...} :
function doIt(){
var input = document.getElementById("input");
var li = /<li>/; // match opening li
var liB = /<\/li>/; // match closing li
var numberOfItems = input.value.match(li).length; // number of lis that occur
for(var i = 0; i < numberOfItems; i++) {
insertNumber(i); // execute insertNumber function w/ parameter of incremented i
}
function insertNumber(number){
input.value = input.value.replace(li, number + "." + " ").replace(liB, "");
}
}
I understand the insertNumber(){...} function is not necessary.

Here's an alternative method, turning your HTML textarea contents into DOM elements that jQuery can manipulate and managing them that way:
function doIt() {
var $domElements = $.parseHTML( $('#input').val().trim() ),
output = [],
i = 1;
$.each($domElements, function(index, element) {
if($(this).text().trim() != '') {
output.push( i + '. ' + $(this).text().trim() );
i++;
}
});
$('#input').val(output.join('\n'));
}

Related

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);
}

How to move this function call out of my HTML code

I am trying to change a javascript function that uses a inline event handler to one that of one with a more modern approach. I would like to remove the ugly event handler from the actual HTML markup and put it in a modular external javascript file. Here is the test case:
Here is the current code (working fine as far as functionality is concerned
function formatPhone(obj) {
var numbers = obj.value.replace(/\D/g, ''),
char = {0:'(',3:') ',6:' - '};
obj.value = '';
for (var i = 0; i < numbers.length; i++) {
obj.value += (char[i]||'') + numbers[i];
}
}
What I would like to accomplish is something like this:
var TargetEl = $('[name="pnumb"]');
TargetEl.on('blur', function() {
var UserInput = $('[name="pnumb"]').value.replace(/\D/g, ''),
char = {0:'(',3:') ',6:' - '};
TargetEl.value = '';
for (var i = 0; i < UserInput.length; i++) {
TargetEl.value += (char[i]||'') + numbers[i];
}
My main focus is to remove the inline js and onblur="" event handler.I also want have the phone number formatted after the targeted El is blurred. Lastly I want this to be called by simply assigning a class of say .pnumbFormat... (Thanks in advance for your help SO!)
Here is the fiddle ... http://jsfiddle.net/UberNerd/ae4fk/
Modify your function to accept string and return string.
function formatPhone(value) {
var numbers = value.replace(/\D/g, ''),
char = {
0: '(',
3: ') ',
6: ' - '
};
value = '';
for (var i = 0; i < numbers.length; i++) {
value += (char[i] || '') + numbers[i];
}
return value;
}
var TargetEl = $('[name="pnumb"]');
TargetEl.on('blur', function () {
$(this).val(formatPhone($(this).val()))
});
DEMO
Even better
Thanks #KevinB for Great improvisation.
function formatPhone(_,value) {
var numbers = value.replace(/\D/g, ''),
char = {
0: '(',
3: ') ',
6: ' - '
};
value = '';
for (var i = 0; i < numbers.length; i++) {
value += (char[i] || '') + numbers[i];
}
return value;
}
var TargetEl = $('[name="pnumb"]');
TargetEl.on('blur', function () {
$(this).val(formatPhone)
});
DEMO
In your HTML, consider adding an attribute so you know which fields to format.
<input value="22" type="text" name="pnumb" data-formatter="phone" />
Then in your JavaScript, you can select those elements and set up the handlers:
$('input[data-formatter="phone"]').each(function (index, element) {
// Add blur handlers or whatever here.
});
This way, you only need to add that attribute to your markup, and your global JS takes care of it. Much less to hook up on a per-page basis.

two delimiters output formatting javascript

I thought this would be easier, but running into a weird issue.
I want to split the following:
theList = 'firstword:subwordone;subwordtwo;subwordthree;secondword:subwordone;thirdword:subwordone;subwordtwo;';
and have the output be
firstword
subwordone
subwordtwo
subwordthree
secondword
subwordone
thirdword
subwordone
subwordtwo
The caveat is sometimes the list can be
theList = 'subwordone;subwordtwo;subwordthree;subwordfour;'
ie no ':' substrings to print out, and that would look like just
subwordone
subwordtwo
subwordthree
subwordfour
I have tried variations of the following base function, trying recursion, but either get into infinite loops, or undefined output.
function getUl(theList, splitOn){
var r = '<ul>';
var items = theList.split(splitOn);
for(var li in items){
r += ('<li>'+items[li]+'</li>');
}
r += '</ul>';
return r;
}
The above function is just my starting point and obviously doesnt work, just wanted to show what path I am going down, and to be shown the correct path, if this is totally off base.
It seems you need two cases, and the difference between the two is whether there is a : in your string.
if(theList.indexOf(':') == -1){
//Handle the no sublist case
} else {
//Handle the sublist case
}
Starting with the no sublist case, we develop the simple pattern:
var elements = theList.split(';');
for(var i = 0; i < elements.length; i++){
var element = elements[i];
//Add your element to your list
}
Finally, we apply that same pattern to come up with the implementation for the sublist case:
var elements = theList.split(';');
for(var i = 0; i < elements.length; i++){
var element = elements[i];
if(element.indexOf(':') == -1){
//Add your simple element to your list
} else {
var innerElements = element.split(':');
//Add innerElements[0] as your parent element
//Add innerElements[1] as your child element
//Increment i until you hit another element with ':', adding the single elements each increment as child elements.
//Decrement i so it considers the element with the ':' as a parent element.
}
}
Keep track of the current list to add items to, and create a new list when you find a colon in an item:
var baseParent = $('ul'), parent = baseParent;
$.each(theList.split(';'), function(i, e) {
if (e.length) {
var p = e.split(':');
if (p.length > 1) {
baseParent.append($('<li>').append($('<span>').text(p[0])).append(parent = $('<ul>')));
}
parent.append($('<li>').text(p[p.length - 1]));
}
});
Demo: http://jsfiddle.net/Guffa/eWQpR/
Demo for "1;2;3;4;": http://jsfiddle.net/Guffa/eWQpR/2/
There's probably a more elegant solution but this does the trick. (See edit below)
function showLists(text) {
// Build the lists
var lists = {'': []};
for(var i = 0, listKey = ''; i < text.length; i += 2) {
if(text[i + 1] == ':') {
listKey = text[i];
lists[listKey] = [];
} else {
lists[listKey].push(text[i]);
}
}
// Show the lists
for(var listName in lists) {
if(listName) console.log(listName);
for(var j in lists[listName]) {
console.log((listName ? ' ' : '') + lists[listName][j]);
}
}
}
EDIT
Another interesting approach you could take would be to start by breaking it up into sections (assuming text equals one of the examples you gave):
var lists = text.match(/([\w]:)?([\w];)+/g);
Then you have broken down the problem into simpler segments
for(var i = 0; i < lists.length; i++) {
var listParts = lists[i].split(':');
if(listParts.length == 1) {
console.log(listParts[0].split(';').join("\n"));
} else {
console.log(listParts[0]);
console.log(' ' + listParts[1].split(';').join("\n "));
}
}
The following snippet displays the list depending on your requirements
var str = 'subwordone;subwordtwo;subwordthree;';
var a = []; var arr = [];
a = str;
var final = [];
function split_string(a){
var no_colon = true;
for(var i = 0; i < a.length; i++){
if(a[i] == ':'){
no_colon = false;
var temp;
var index = a[i-1];
var rest = a.substring(i+1);
final[index] = split_string(rest);
return a.substring(0, i-2);
}
}
if(no_colon) return a;
}
function display_list(element, index, array) {
$('#results ul').append('<li>'+element+'</li>');
}
var no_colon_string = split_string(a).split(';');
if(no_colon_string){
$('#results').append('<ul><ul>');
}
no_colon_string.forEach(display_list);
console.log(final);
working fiddle here

Get the value from only selected checkbox

I am trying to get the value from a checkbox using javascript.
I want only one checkbox value to be passed to the javascript function, and if multiple are selected, an alert box informing that only one box can be checked for the function.
I've tried this:
var publish_trigger = document.querySelector("#publish_trigger");
publish_trigger.onclick = function() {
var _posts = document.getElementsByName('post_id[]');
var check = _posts.checked;
var boxes = _posts.length;
var txt = "";
if(check.length > 1) {
alert("Only one at a time");
} else {
for (i = 0; i < boxes; i++) {
if (_posts[i].checked) {
txt = txt + _posts[i].value + " "
}
}
}
alert(txt);
return false;
}
This code is wrong:
var _posts = document.getElementsByName('post_id[]');
var check = _posts.checked;
getElementsByName() returns a NodeList (effectively an array) of elements, so your variable _posts doesn't have a checked property. You need to loop through _posts to count the checked property on the individual elements within _posts.
You already have a for loop so add the validation in there:
var count = 0;
for (var i = 0; i < boxes; i++) {
if (_posts[i].checked) {
if (++count > 1) {
alert("Only one checkbox may be checked at a time.");
return false;
}
// I don't know what you're trying to do with the following line
// but I've left it in.
txt = txt + _posts[i].value + " "
}
}
(Note: unrelated to your question, you should declare the loop counter i within your function otherwise it will be global and might lead to hard to debug problems if you are using it in other places too.)

How do I make this ghostType jquery function do line breaks?

I'm playing around with a jquery function called ghostType which basically types out text as though it is being typed on screen. Its kinda cool, but I can't seem to have it do line breaks.
The jquery is as follows:
(function( $ ){
$.fn.ghostType = function() {
return this.each(function() {
var $this = $(this);
var str = $this.text();
$this.empty().show();
str = str.split("");
str.push("_");
// increase the delay to ghostType slower
var delay = 100;
$.each(str, function (i, val) {
if (val == "^") {
// Do nothing. This will add to the delay.
}
else {
$this.append('<span>' + val + '</span>');
$this.children("span").hide().fadeIn(100).delay(delay * i);
}
});
$this.children("span:last").css("textDecoration", "blink");
});
};
})( jQuery );
From what I can tell this code takes each character in the chosen elements TEXT and puts it into seperate tags, therefor omitting the HTML (ie br's) with the line var str = $this.text();
How would you go about making this code include line breaks?
The best I could come up with was by adding an extra 'else if' statement like so:
else if ( val == "*" ) {
$this.append('<br />');
}
And therefor * signs would become line breaks... but this damages the functionality where blinking cursor doesn't sit beside each letter as it fades in. otherwise, it works...
You can see an example of what I've done at http://jsfiddle.net/JNyQV/
(function( $ ){
$.fn.ghostType = function() {
return this.each(function() {
var $this = $(this);
var str = $this.text();
$this.empty().show();
str = str.split("");
str.push("_");
// increase the delay to ghostType slower
var delay = 55;
$.each(str, function (i, val) {
if (val == "^") {
// Do nothing. This will add to the delay.
}
else {
if (val == "*") val = "<br/>";
$this.append('<span>' + val + '</span>');
$this.children("span").hide().fadeIn(100).delay(delay * i);
}
});
$this.children("span:last").css("textDecoration", "blink");
});
};
})( jQuery );
$('#example').ghostType();
Your best bet is to treat the selected element as an element, and not just simply grab its text.
Here is an excerpt from one of my plugins that handles text...
var findText = function(element, pattern, callback) {
for (var childi= element.childNodes.length; childi-->0;) {
var child= element.childNodes[childi];
if (child.nodeType==1) {
findText(child, pattern, callback);
} else if (child.nodeType==3) {
var matches= [];
var match;
while (match= pattern.exec(child.data))
matches.push(match);
for (var i= matches.length; i-->0;)
callback.call(window, child, matches[i]);
}
}
}
I originally got this piece of code from an answer here by bobince.
By examining the rest of my plugin, you should be able to pick up how it works. Basically, it iterates over all text nodes recursively, wrapping each character in a span which is later animated.
This is how I would write the script... just add the entire partial string instead of each individual letter. The biggest difference is that the last letter doesn't fade in. I didn't think the effect was that noticeable, but it should be possible to just add the last letter and have that fade in if it is a necessity. Here is a demo.
(function($) {
$.fn.ghostType = function() {
return this.each(function() {
// increase the delay to ghostType slower
var delay = 55,
$this = $(this),
str = $this.text(),
i = 0,
l = str.length,
t,
loop = function() {
if (i <= l) {
t = str.substring(0,i++).replace(/\^/g, '').replace(/\*/g, '<br>');
$this.html(t + '<span class="blink" >_</span>');
setTimeout(loop, delay);
}
};
$this.empty().show();
loop();
});
};
})(jQuery);
$('#example').ghostType();

Categories