Cloning element based on dynamic value creating endless loop - javascript

I have a slider input field that gives a numeric value when slid. I would like to clone an object X times based on the slider value, however when I try to accomplish this it creates an endless loop. Is there anyway to get the number of cloned elements to match the slider value when it changes? Here is the code I was using.
jQuery(document).ready(function($) {
$(window).load(function() {
$('input#fieldname3_1').change(function() {
var e = $('#student-icons.icon > span');
var n = $('#fieldname9_1').val();
$('#student-icons.icon').html(
for (var i = 0; i < n; i++) {
e.clone().insertAfter(e);
});
}).change()
});
});

Try the following setup:
HTML:
<input type="range" id='fieldname3_1' style='width: 200px'>
<div id='student-icons' class='icon'></div>
JavaScript:
$(document).ready(function($) {
$('input#fieldname3_1').change(function() {
var n = $(this).val();
// reset the element
$('#student-icons.icon').html('');
for (var i = 0; i < n; i++) {
// The html of what you want to clone goes here
$('#student-icons.icon').append("<div id='hello'>"+i+"</div>")
}
});
});
I also recommend using the oninput event if browser support is not an issue (IE 9 and up only):
$(document).ready(function($) {
$('input#fieldname3_1')[0].oninput = function() {
var n = $(this).val();
$('#student-icons.icon').html('');
for (var i = 0; i < n; i++) {
$('#student-icons.icon').append("<div id='hello'>"+i+"</div>")
}
};
});
This will allow the event to fire as soon as the input is changed rather than wait on the keydown.
JsFiddle
JsFiddle w/ onInput

Related

Add and remove border when clicking on a button JS

hello I am struggling to use JS in order to make the buttons on my HTML page add a border to the button when it is clicked and to remove the border when it is clicked again. it works for the first 2 clicks but then no longer does anything after that. please excuse my js im extremely inexperienced.
JavaScript:
<script>
var flag = true;
var buttons = document.getElementsByClassName("btn");
function buttonFunction() {
if (flag) {
for (var i = 0; i < buttons.length; i++) {
document.getElementsByClassName("btn")[i].addEventListener("click", function() {
this.classList.add("buttonSelect");
flag = false
return
});
}
} else {
if (flag == false) {
for (var i = 0; i < buttons.length; i++) {
document.getElementsByClassName("btn")[i].addEventListener("click", function() {
this.classList.add("buttonUnselect");
flag = true
return
});
}
}
}
}
</script>
The real issue is you're adding both classes and never removing them. Get rid of the if else statement and just toggle the class on click. Don't need to wrap the loop in a function either. Just let the javascript execute the event listeners at runtime.
Also, make use of the buttons var you created instead of trying to query the DOM again for the same elements.
<script>
var buttons = document.getElementsByClassName("btn");
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", function() {
this.classList.toggle("buttonSelect");
})
}
</script>

Jquery trying to increment the data delay for every child

I am trying to increment the delay of every data-attribute inside the div element.
See my code
JQUERY
jQuery(document).ready(function($) {
var Column = [], startDelayTime, counter;
Column = $('.col-outside');
startDelayTime = 300;
addDelayTime = 25;
for(var i = 0; i < Column.length; i++) {
Column.attr('data-sal-delay', startDelayTime + addDelayTime[i]);
}
});
HTML:
<div class="col-md-3 col-outside" data-sal="slide-right" data-sal-easing="ease-out-bounce" data-sal-delay="300">
Hopefully someone can explain me what i am doing wrong, or what i have to do.
The logic in your loop needs to look like this. I removed the JQuery logic to simplify the example.
var currentDelay = 300;
var addDelayTime = 25;
for(var i = 0; i < 10; i++) {
// Column.attr('data-sal-delay', currentDelay);
console.log(currentDelay);
currentDelay += addDelayTime;
}
This will work:
You need to multiply by i on delayStart to get desired effect.
$(function() {
var Column = [], startDelayTime, counter;
Column = $('.col-outside');
startDelayTime = 300;
addDelayTime = 25;
Column.each(function(i, c){
$(c).attr('data-sal-delay', startDelayTime+ (addDelayTime*i));
});
});
You need to do two things:
Use the current column in your loop (Column[i] rather than Column).
Increment the value of startDelayTime every time the loop iterates.
Here's your edited code:
jQuery(document).ready(function($) {
var Column = [], startDelayTime, counter;
Column = $('.col-outside');
startDelayTime = 300;
addDelayTime = 25;
for(var i = 0; i < Column.length; i++) {
Column[i].attr('data-sal-delay', startDelayTime + addDelayTime);
startDelayTime += addDelayTime;
}
});
Now your code should work. Hopefully this helps!
There are a few problems with your code.
Within your loop, you need to access the single column node using Column[i] in order to set an attribute.
attr() is a jQuery method, so you need to use it on a jQuery selection like $(Column[i]).attr(name, value). Or you could just use the javascript method setAttribute like Column[i].setAttribute(name, value)
addDelayTime is an integer so addDelayTime[i] is undefined. What you want to do here instead is multiply addDelayTime by the current array index. addDelayTime * i
In this example I've fixed the above 3 issues and instead of a for loop I've used jQuery's each to iterate over the columns.
jQuery(document).ready(function($) {
var startDelayTime = 300;
var addDelayTime = 25;
$.each($(".col-outside"), function(index, item) {
$(item).attr("data-sal-delay", startDelayTime + index * addDelayTime);
});
});
.col-outside::after {
content: attr(data-sal-delay);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-outside"></div>
<div class="col-outside"></div>
<div class="col-outside"></div>
<div class="col-outside"></div>
<div class="col-outside"></div>

Fill Html Selection "FontSize" by JavaScript

I want to fill my Selection by Script. I am struggling with the filling method.
When I want to fill my FontSizeMenu I use this code:
function FillFontSizeMenu() { // run this at Start
FillSelection(GetPossibleFontSizes(), "fontSizeMenu"); // Fill the selection with values
}
function GetPossibleFontSizes(){ // Return all values for the menu
var sizeMin = 1;
var sizeMax = 100;
var possibleSizes = [];
for(var i = sizeMin; i <= sizeMax; i++)
{
possibleSizes.push(i);
}
return possibleSizes;
}
function FillSelection(possibleValues, elementId){ // Fill the menu
for(var i = 0; i < possibleValues.length; i++)
{
var optionElement = "<option></option>"; // add one option element per value
optionElement.html(possibleValues[i]);
optionElement.val(possibleValues[i]);
$(elementId).append(optionElement); // add the option element to the selection
}
}
Something is wrong with the "FillSelection" method, it says the option element is not a function.
Does someone knows what is wrong or missing?
Thanks
Wrap html string in jQuery()
var optionElement = $("<option></option>");
You can also use jQuery() to set html, value and call .appendTo()
$("<option></option>", {
html: possibleValues[i],
value: possibleValues[i],
appendTo: $(elementId)
});
Here is one more solution
You need to create new Option object
$(elementId).append(new Option("Font size "+i, possibleValues[i]));
and you should pass #id to function:
FillSelection(GetPossibleFontSizes(), "#fontSizeMenu")
function FillFontSizeMenu() { // run this at Start
FillSelection(GetPossibleFontSizes(), "#fontSizeMenu"); // Fill the selection with values
}
function GetPossibleFontSizes(){ // Return all values for the menu
var sizeMin = 1;
var sizeMax = 100;
var possibleSizes = [];
for(var i = sizeMin; i <= sizeMax; i++)
{
possibleSizes.push(i);
}
return possibleSizes;
}
function FillSelection(possibleValues, elementId){ // Fill the menu
for(var i = 0; i < possibleValues.length; i++)
{
$(elementId).append(new Option("Font size "+i, possibleValues[i])); // add the option element to the selection
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="FillFontSizeMenu()">Populate it</button>
<select id="fontSizeMenu">
</select>
You have to create an element first then append properties using jquery. Something like this
var ele = document.createElement("<option>");
$("body").append(ele);
$(ele).html(possibleValues[i]);
$(ele).val(possibleValues[i]);

onchange event not tracking properly

I have a form that I want to track any changes. Right now I have it set so when the user exits the page, an alert box displays saying how many changes were made to the form. However, it keeps registering 0. I've tested with adding an alert to the inputChanges function telling me a change has occurred and the alert fires, but the count still registers as 0 when I exit the page...
Here's my script:
window.onload = function() {
var totalChanges = "";
var inputHandles = 0;
var selectHandles = 0;
var textAreaHandles = 0;
window.onbeforeunload = function(){
alert("Total Form Changes:" + totalChanges);
}//onbeforeunload
var totalChanges = inputHandles + selectHandles + textAreaHandles;
function inputChanges() {
inputHandles++;
alert("Change");
}
var inputs = document.getElementsByTagName("input");
for (i = 0; i < inputs.length; i++){
inputs[i].onchange = inputChanges;
}
function selectChanges(){
selectHandles++;
}
var selects = document.getElementsByTagName("select");
for (i = 0; i < selects.length; i++){
selects[i].onselect = selectChanges;
}
function textAreaChanges(){
textAreaHandles++;
}
var textAreas = document.getElementsByTagName("textarea");
for (i = 0; i < textAreas.length; i++){
textAreas[i].onchange = textAreaChanges;
}
}//Onload
You declare totalChanges here:
var totalChanges = "";
...and then re-declare it here:
var totalChanges = inputHandles + selectHandles + textAreaHandles;
...at which point the things you're adding up are all 0.
You need to do that calculation at the point where you need the value:
window.onbeforeunload = function(){
totalChanges = inputHandles + selectHandles + textAreaHandles;
alert("Total Form Changes:" + totalChanges);
}
Or set totalChanges = 0 initially and then increment it every time the other variables change, but that's clunkier.
Note also that you're not tallying the number of fields that now have values different to their starting values, you're tallying the number of individual edits. So if the user changes a field twice with the second change being back to the original value your code will track that as two changes (when logically it's kind of zero changes).
Since the user can change values back to what they were, I suggest you compare all input.value with input.defaultValue and check select.options[select.selectedIndex]defaultSelected
also you might want to move the } and the alert to after the sum of total changes
something like this
window.onload = function() {
var totalChanges = 0;
window.onbeforeunload = function(){
var inputs = document.getElementsByTagName("input"); // ditto for "textarea"
for (var i = 0; i < inputs.length; i++){
totaChanges += inputs[i].value != inputs[i].defaultValue;
}
var selects = document.getElementsByTagName("select");
for (var i = 0; i < selects.length; i++){
totalChanges += !selects[i].defaultSelected;
}
alert("Total Form Changes:" + totalChanges);
}//onbeforeunload
}

Using labels like HTML5 placeholder

I am trying to use <label> elements in my html contact form like the HTML5 placeholder attribute for inputs. I have written the following JavaScript to to act as a reusable function witch will provide the following functionality.
Find the input by name.
Get the value of the input.
Find the label belonging to the input.
Change the label style depending on the state of the input.
Change the label style depending on the value of the input.
However it is not working and I don't know why as no errors appear in the console. What am I doing wrong? here is a JS Fiddle with code
function placeholder(field_name) {
// Get the input box with field_name
// Then get input value
var box = document.getElementsByName(field_name);
var i;
for (i = 0; i < box.length; i++) {
var value = document.getElementById(box[i].value);
}
// Get the labels belonging to each box using the HTML for attribute
var labels = document.getElementsByTagName('LABEL');
for (i = 0; i < labels.length; i++) {
if (labels[i].htmlFor !== '') {
var elem = document.getElementById(labels[i].htmlFor);
if (elem) {
box.label = labels[i];
}
}
}
// Colors
var focusColor = "#D5D5D5";
var blurColor = "#B3B3B3";
// If no text is in the box then show the label grey color
box.onblur = function () {
box.label.style.color = blurColor;
};
// If input focuses change label color to light grey
box.onfocus = function () {
box.label.style.color = focusColor;
};
// If there is text in the box then hide the label
if (box.value !== "") {
// Quick do something, hide!
box.label.style.color = "transparent";
}
}
// Call the function passing field names as parameters
placeholder(document.getElementsByName("email"));
placeholder(document.getElementsByName("firstName"));
placeholder(document.getElementsByName("lastName"));
This might be considered a little overkill on the number of listeners I've used, feel free to remove any you think unnecessary, but I've tried to employ your HTML structure as you have it and give you all desired effects. It should work for either the <label>s for matching the <input>s id OR matching it's <name> (given no id matches). I'll always say prefer using an id over name. I believe this JavaScript should also work in all browsers too, except the addEventListener for which you'd need a shim for old IE versions (let me know if it doesn't in one/the error message).
Demo
var focusColor = "#D5D5D5", blurColor = "#B3B3B3";
function placeholder(fieldName) {
var named = document.getElementsByName(fieldName), i;
for (i = 0; i < named.length; ++i) { // loop over all elements with this name
(function (n) { // catch in scope
var labels = [], tmp, j, fn, focus, blur;
if ('labels' in n && n.labels.length > 0) labels = n.labels; // if labels provided by browser use it
else { // get labels from form, filter to ones we want
tmp = n.form.getElementsByTagName('label');
for (j = 0;j < tmp.length; ++j) {
if (tmp[j].htmlFor === fieldName) {
labels.push(tmp[j]);
}
}
}
for (j = 0; j < labels.length; ++j) { // loop over each label
(function (label) { // catch label in scope
fn = function () {
if (this.value === '') {
label.style.visibility = 'visible';
} else {
label.style.visibility = 'hidden';
}
};
focus = function () {
label.style.color = focusColor;
};
blur = function () {
label.style.color = blurColor;
};
}(labels[j]));
n.addEventListener('click', fn); // add to relevant listeners
n.addEventListener('keydown', fn);
n.addEventListener('keypress', fn);
n.addEventListener('keyup', fn);
n.addEventListener('focus', fn);
n.addEventListener('focus', focus);
n.addEventListener('blur', fn);
n.addEventListener('blur', blur);
}
}(named[i]));
}
};
placeholder("email"); // just pass the name attribute
placeholder("firstName");
placeholder("lastName");
http://jsfiddle.net/cCxjk/5/
var inputs = document.getElementsByTagName('input');
var old_ele = '';
var old_label ='';
function hide_label(ele){
var id_of_input = ele.target.id;
var label = document.getElementById(id_of_input + '-placeholder');
if(ele.target == document.activeElement){
label.style.display = 'none';
}
if (old_ele.value == '' && old_ele != document.activeElement){
old_label.style.display = 'inline';
}
old_ele = ele.target;
old_label = label;
}
for(var i = 0; i < inputs.length; i++){
inputs[i].addEventListener('click', hide_label);
}
I will point out a couple things, you will have to find away around the fact that the label is inside the input so users now can't click on half of the input and actually have the input gain focus.
Also I guess you want to do this in IE (otherwise I would strongly advise using the html5 placeholder!) which means you would need to change the ele.target to ele.srcElement.

Categories