having problem creating a loop for my jQuery - javascript

I have this scripts that works. As of now it changes the image correctly for the last set, I want to put it in a loop where I have m=k, but it does not work
like
for (m = 0; m < k; ++m) {
<script>
$(function() {
var m = 1;
var resultb = $('[id^=input_]').filter(function () {
return this.id.match(/input_\d+$/); //regex for the pattern "input_ followed by a number"
}).length;
var k = resultb;
m = k;
$("#input_"+m).change(function() {
var val = $("#input_"+m+" option:selected").text();
var valval = $("#input_"+m+"option:selected").val();
var n = val.indexOf('(');
val = val.substring(0, n != -1 ? n : val.length);
var img_option='images/sample/'+val+'.jpg';
if ($("#input_"+m+" option:selected").val() > 0)
$("a.lb:first").html( "<img src="+ img_option+">");
$('a.lb:first img').css({'width' : '350px' });
$('a.lb:first img').addClass( "img-fluid" );
});
});
</script>

Your m values appear to be 1-based, so your loop will want to start at 1.
That being said, you don't need a for loop at all. Just select the elements you want:
$(function() {
const inputs = $('[id^=input_]').filter(function () {
return this.id.match(/input_\d+$/); //regex for the pattern "input_ followed by a number"
});
inputs.on('change', function() {
// I'm assuming that `#input_X` is actually a `<select>`, not an `<input>`
// You should probably adjust your naming convention to be less confusing
let text = this.options[this.selectedIndex].text;
let value = this.options[this.selectedIndex].value;
let parenthesis = text.indexOf("(");
if( parenthesis > -1) text = text.substring(0, parenthesis);
let source = `images/sample/${text}.jpg`;
if( value > 0) $("a.lb:first").html(`<img src="${source}" style="width: 350px" class="img-fluid" />`);
});
});
You'll notice I've given your variables more reasonable names, used let and const as somewhat more appropriate, and just generally tidied the code up to be as clean and understandable as possible.

Related

Target one letter in a string with javascript

Suppose I have this string:
"hello" in a <span> tag, and I want to execute a code for each letter (example: hide, change opacity, etc..). How can I make this with JS/Jquery without having to do this:
<span>h</span><span>e</span><span>l</span><span>l</span><span>o</span>
No and yes. As far as I know, no, a span tag around each letter is necessary, but, yes, you can swing it in JavaScript. A couple examples here, using this concept to randomly apply a color and size to each character.
forEach loop method:
JSFiddle
<span>hello</span>
<script>
var span = document.querySelector('span')
var str = span.innerHTML
span.innerHTML = ''
str.split('').forEach(function (elem) {
var newSpan = document.createElement('span')
newSpan.style.color = "#"+((1<<24)*Math.random()|0).toString(16)
newSpan.style.fontSize = (Math.random() * (36 - 10) + 10) + 'px'
newSpan.innerHTML = elem
span.appendChild(newSpan)
})
</script>
setTimeout method:
JSFiddle
<span>hello</span>
<script>
var span = document.querySelector('span')
var str_arr = span.innerHTML.split('')
span.innerHTML = ''
var ii = 0
~function crazy(ii, str_arr, target) {
if ( ii < str_arr.length ) {
var newSpan = document.createElement('span')
newSpan.style.color = "#"+((1<<24)*Math.random()|0).toString(16)
newSpan.style.fontSize = (Math.random() * (72 - 36) + 36) + 'px'
newSpan.innerHTML = str_arr[ii]
target.appendChild(newSpan)
setTimeout(function () {
crazy(ii += 1, str_arr, target)
}, 1000)
}
}(ii, str_arr, span)
</script>
You can do this.
In html
<span id="my-text">hello</span>
<div id="split-span" ></div>
In Javascript,
var text = $('#my-text').html().split('');
for(var i=0; i<text.length; i++){
$('#split-span').append('<span>'+text[i]+'</span>');
}
You can do this fairly easily in vanilla javaScript without the need of a library like jquery. You could use split to convert your string into an array. This puts each letter into an index of the array. From here you can add markup to each index (or letter) with a loop.
example:
var str = "hello";
var res = str.split('');
for( var i = 0; i < res.length; i++ ){
res[ i ] = '<span>' + res[ i ] + '</span>'
}

Why isn't JavaScript for loop incrementing?

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

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

Comparing two variables sting array to see if any value matches - javascript jquery

Hi I am trying to compare two arrays to each other and then hide a list element if any of the values match.
One array is tags that are attached to a list item and the other is user input.
I am having trouble as I seem to be able to cross reference one user input work and can't get multiple words against multiple tags.
The amount of user input words might change and the amount of tags might change. I have tried inArray but have had no luck. Any help would be much appreciated. See code below:
function query_searchvar() {
var searchquery=document.navsform.query.value.toLowerCase();
if (searchquery == '') {
alert("No Text Entered");
}
var snospace = searchquery.replace(/\s+/g, ',');
event.preventDefault();
var snospacearray = snospace.split(',');
$('li').each(function() {
var searchtags = $(this).attr('data-searchtags');
//alert(searchtags);
var searcharray = searchtags.split(',');
//alert(searcharray);
var searchtrue=-1;
for(var i = 0, len = searcharray.length; i < len; i++){
if(searcharray[i] == searchquery){
searchtrue = 0;
break;
}
}
if (searchtrue == 0) {
$(this).show("normal");
}
else {
$(this).hide("normal");
}
});
}
Okay so I've tried to implement the code below but have had no luck. It doesn't seem to check through both arrays.
function query_searchvar()
{
var searchquery=document.navsform.query.value.toLowerCase();
if(searchquery == '')
{alert("No Text Entered");
}
var snospace = searchquery.replace(/\s+/g, ' ');
event.preventDefault();
var snospacearray = snospace.split(' ');
alert(snospacearray[1]);
$('li').each(function() {
var searchtags = $(this).attr('data-searchtags');
alert(searchtags);
var searcharray = searchtags.split(' ');
alert(searcharray[0]);
jQuery.each(snospacearray, function(key1,val1){
jQuery.each(searcharray,function(key2,val2){
if(val1 !== val2) {$(this).hide('slow');}
});
});
});
}
Working code:
function query_searchvar()
{
var searchquery=document.navsform.query.value.toLowerCase();
if(searchquery == '')
{alert("No Text Entered");
}
var queryarray = searchquery.split(/,|\s+/);
event.preventDefault();
$('li').each(function() {
var searchtags = $(this).attr('data-searchtags');
//alert(searchtags);
var searcharray = searchtags.split(',');
//alert(searcharray);
var found = false;
for (var i=0; i<searcharray.length; i++)
if ($.inArray(searcharray[i], queryarray)>-1) {
found = true;
break;
}
if (found == true )
{
$(this).show("normal");
}
else {
$(this).hide("normal");
}
});
}
var snospace = searchquery.replace(/\s+/g, ',');
var snospacearray = snospace.split(',');
Note that you can split on regular expressions, so to the above would equal:
var queryarray = searchquery.split(/,|\s+/);
To find whether there is an item contained in both arrays, use the following code:
var found = searcharray.some(function(tag) {
return queryarray.indexOf(tag) > -1;
});
Although this will only work for ES5-compliant browsers :-) To support the others, use
var found = false;
for (var i=0; i<searcharray.length; i++)
if ($.inArray(searcharray[i], queryarray)>-1) {
found = true;
break;
}
In plain js, without jQuery.inArray:
var found = false;
outerloop: for (var i=0; i<searcharray.length; i++)
for (var j=0; j<queryarray.length; j++)
if (searcharray[i] == queryarray[j]) {
found = true;
break outerloop;
}
A little faster algorithm (only needed for really large arrays) would be to sort both arrays before running through them linear.
Here's psuedo code that should solve your problem.
get both arrays
for each item in array 1
for each element in array 2
check if its equal to current element in array 1
if its equal to then hide what you want
An example of this coude wise would be
jQuery.each(array1, function(key1,val1){
jQuery.each(array2,function(key2,val2){
if(val1 == val2) {$(your element to hide).hide();}
});
});
If there's anything you don't understand please ask :)

Categories