Loop for generating html inputs to processingjs - javascript

I am trying to use html input fields to control a sketch. Now I want to make a loop to generate more then one input.
var uivars = {
tA: "40", // set initial values
tB: "10",
};
Then I refer to those variables in the sketch:
<script type="application/processing" data-processing-target="pjs">
void draw() {
background(255);
var a = uivars.tA;
var b = uivars.tB;
line(0,b,a,b);
}
</script>
Then I get the values from the input fields and update the uivar variable in the beginning:
<script type="text/javascript" >
$(document).ready(function(){
$("#word_textboxA").keyup(function () { // whenever text is entered into input box...
uivars.tA = $(this).val(); // update word variable,
});
$("#word_textboxB").keyup(function () { // whenever text is entered into input box...
uivars.tB = $(this).val();
});
$("#word_textboxA").val(uivars.tA); // initialize input textbox contents.
$("#word_textboxB").val(uivars.tB); // initialize input textbox contents.
});
</script>
And the inputs:
<div id="PVarray">
<input type="text" id="word_textboxA"/><br/>
<input type="text" id="word_textboxB"/>
<div/>
I am building a sketch using processing js and will have over 40 inputs. So I am looking for a way to make a loop for these steps.
No I've managed to generate a number of input fields putting this somewhere:
<!-- <script>
window.onload = initAll;
function initAll(){
for(var i = 0; i<=1; i++)
{
var c=document.getElementById('PVarray');
var input = document.createElement('input');
input.setAttribute('type','text');
input.setAttribute('size','1');
input.setAttribute('id','num'+(i+1));
input.setAttribute('value', 'id' );
//Adds first input to container
c.appendChild(input);
input = '';
}
document.getElementById("show").innerHTML = uivars.tA;
}
</script> -->
But I just cannot find a way to refer in the jquery part to the changing id's of the html inputs.
I am not a experienced programmer. I looked around to find the answer but this is just a difficult one for me. My sketch will need over 40 inputs. the loop should just generate the html inputs, set the initial variables, update the variables on inputchange and give the values to the sketch. The names of the inputs and initial values can be put in a array.

If I understand correctly, the solution is quite simple.
You tagged the question with "jQuery", so here is a jQuery solution.
$(document).ready(function () {
//This is the keyup event handler, attached below to all <input> elements
function updateUivars() {
uivars[this.id] = this.value;
}
//a jQuery-wrapped reference to the PVarray container
var $c = $('#PVarray');
//Loop through uivars properties to create <input> elements with :
// - id equal to the property (the key)
// - an initial value equal to uivars[key]
$.each(uivars, function(key, value) {
$('<input type="text" size="1" />').attr('id', key).val(value).appendTo($c).on('keyup', updateUivars);
});
});
EDIT
So now, for each univars property, there is one value and two pieces of associated text.
var uivars = {
Ins: [30, "Insulation", "kWh/m2/day"],
D: [40, "Deterioration", "%"],
AO: [10, "Azimuth Offset", "%"],
SD: [20, "Surface Deposits", "%"],
TC: [30, "Temperature", "DegC"]
};
The loop that creates the input elements clearly needs to be amended to cause the associated text to be displayed.
Maybe it is less clear that the keyup event handler also needs to be modified to store values back in element [0] of the appropriate array.
Something like this should do it :
$(document).ready(function () {
//This is the keyup event handler, attached below to all <input> elements
function updateUivars() {
uivars[this.id][0] = this.value;
}
//a jQuery-wrapped reference to the PVarray container
var $c = $('#PVarray');
//Loop through uivars properties to create an inner div containing:
// - a label for the property's name
// - an <input> elements with :
// * id equal to the property (the key)
// * an initial value equal to uivars[key][0]
// - a label for the property's units
$.each(uivars, function(key, arr) {
var $div = $('<div class="property"/>').appendTo($c);//inner block element
$('<label/>').text(arr[1]).appendTo($div);
$('<input type="text" size="3" />').attr('id', key).val(arr[0]).appendTo($div).on('keyup', updateUivars);
$('<label/>').text(arr[2]).appendTo($div);
});
});
If desired, the inner divs can be styled in CSS with a .property {...} directive.

Related

How to remove inner HTML content onchange

I created a form where a user selects options from a checkbox list. So when a user selects an option in the checkbox, I use a function to show the value of the input field using onchange within inner HTML. My question is, how do we remove that same inner HTML content if the user un-selects those options? So when the user toggles back and forth, it either appears or when un-selected, the value gets removed. Thanks
function functionOne() {
var x = document.getElementById("wheels").value;
document.getElementById("demo").innerHTML = x;
}
<input type="checkbox" id="wheels" onchange="functionOne()" value="feature 1">
<div id="demo"></div>
Check the state of the checkbox before you read the value.
function functionOne(cb) {
var x = cb.checked ? cb.value : '';
document.getElementById("demo").innerHTML = x;
}
<input type="checkbox" id="wheels" onchange="functionOne(this)" value="feature 1">
<div id="demo"></div>
Inside the change function on deselect do this:
document.getElementById("demo").innerHTML = '';
The element that is changed has a checked property which can be inspected - it will be either true or false. So write an if/else condition to update the content of the demo element depending on its value.
I've adjusted your code slightly to cache the elements outside of the function, and to add an event listener to the checkbox instead of using inline JS which is a bit old-school these days. Also, since the value is just a string textContent is more suitable in this case than innerHTML.
// Cache the elements
const wheels = document.getElementById('wheels');
const demo = document.getElementById('demo');
// Add a listener to the wheels element which calls the
// handler when it changes
wheels.addEventListener('change', handleChange);
// Here `this` refers to the clicked element. If its
// checked property is `true` set the text content of
// `demo` to its value, otherwise use an empty string instead
function handleChange() {
if (this.checked) {
demo.textContent = this.value;
} else {
demo.textContent = '';
}
}
<input type="checkbox" id="wheels" value="feature 1">
<div id="demo"></div>

How to bind 2 input fields dynamically added in a table with Jquery

I am not very familiar with javascript/Jquery Syntax, I would like to bind 2 input text fields that were dynamically added to a table inside a loop. The main goal is to automatically fill the second text field with text from the first one. I was able to do it for 2 static text field by doing that.
$(document).bind('input', '#changeReviewer', function () {
var stt = $('#changeReviewer').val();
stt = stt.replace(/ /g,'.')
$("#changeReviewerEmail").val(stt + "##xxxxxx.com");
});
I have tried a few things but when I try to get the value of the first input, it always returns empty. Thanks.
Check this code
$(document).on('input', '#changeReviewer', function() {
var stt = $('#changeReviewer').val();
stt = stt.replace(/ /g, '.');
$("#changeReviewerEmail").val(stt + "##xxxxxx.com");
});
$('#addbtn').click(function() {
$('div').empty().append(`<input id='changeReviewer'><input id='changeReviewerEmail'>`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<button id='addbtn'>add inputs</button>
</div>

Recreate Select Control Options Dynamically jQuery

I have the following function which I use to populate a Select control with options. I am grabbing values from objects on the document, and if a condition is met, throwing another value into a Select Control as an option...
function dispatchList() {
//grab list element
var list = document.getElementById("techName");
//foreach div assigned the .square class,
$('.square').each(function () {
//convert each div with .square class toString
var square = $(this).html().toString();
//grab availability value
var availability = $(this).find('tr:eq(4)').find('td').text();
//grab IP
var online = $(this).find('tr:eq(3)').find('td').text()
//if availability and IP values meet below condition...
if ((availability === "True") && (online.indexOf("10.") === 0)) {
//grab the name value from this div
var availableName = $(this).find('tr:eq(0)').find('td').text();
//create a new option element
var item = document.createElement("option");
//create a new text node containing the name of the tech
item.appendChild(document.createTextNode(availableName));
//append the new text node (option) to our select control
list.appendChild(item);
}
})
}
This function works great, but it runs when the document is ready. I need it to run when the document is ready, but also to recreate this list without refreshing the page. Ideally the select control could be emptied and recreated with a click event on a div.
This is the part I have struggled with. I have the following click event which it would make sense to chain this to, but I have not been able to work it out...
function availability() {
//for each element with a class of .square...
$('.square').each(function () {
//grab the id of each input element (button) contained in each .square div...
var btnId = $(this).find("input").attr("id");
//when .square div is clicked, also click it's associated asp button...
$(this).on('click', function (clickEvent) {
document.getElementById(btnId).click();
//****AND ALSO TRIGGER THE dispatchList() FUNCTION TO REBUILD THE #techName LIST****
})
})
}
Can this be done without AJAX or some other post back on the select control?
Does the #techName list need to be emptied first, and then rebuilt?
Thank you for any advice!
$(document).ready(function(){
$(".square").on('click', function (clickEvent) {
var el = clickEvent.target || clickEvent.srcElement
document.getElementById($(el).find('input').attr("id")).click();
dispatchList();
})
})
That's all i can do with the given question. I didn't test the code. You can give fiddle or anything to test. Also this function is written in the browser.

JQuery Datatables search within input and select

Using Jquery Datatables with inputs and selects as shown here: http://datatables.net/examples/api/form.html
or if I used a custom column render handler to produce the input and selects how can I make the global table search work?
If you view the example you'll notice that only the first column, the read only one, is included in the search, what can I do to include the other columns in the search?
If you view the example in the link in my question and type "Tokyo" into the search all rows are returned. This is because "Tokyo" is an option in all dropdowns. I would want only rows with Tokyo selected to show. If you type in "33" you see no rows even though the first row has a value of "33" in the first column.
I can't seem to find any documentation on how to define what the search value is for a particular cell in a datatable.
It is not very well documented. And it seems to work differently, or not work at all, between (sub)versions. I think dataTables is intended to automatically detect HTML-columns, but for some reason, most of the times, it doesnt. The safest way is to create your own search-filter :
$.fn.dataTableExt.ofnSearch['html-input'] = function(value) {
return $(value).val();
};
This will return 33 on <input>'s with value 33, and Tokyo on <select>'s where Tokyo is selected. Then define the desired columns as of type html-input ;
var table = $("#example").DataTable({
columnDefs: [
{ "type": "html-input", "targets": [1, 2, 3] }
]
});
see demo based on http://datatables.net/examples/api/form.html -> http://jsfiddle.net/a3o3yqkw/
Regarding live data: The issue is, that the type based filter only is called once. dataTables then caches the returned values so it not need to "calculate" all the values over and over. Luckily, dataTables 1.10.x has a built-in function for cells, rows and pages called invalidate that forces dataTables to reset the cache for the selected items.
However, when dealing with <input>'s there is also the problem, that editing the value not is changing the value attribute itself. So even if you call invalidate(), you will still end up in filtering on the old "hardcoded" value.
But I have found a solution for this. Force the <input>'s value attribute to be changed with the <input>'s current value (the new value) and then call invalidate :
$("#example td input").on('change', function() {
var $td = $(this).closest('td');
$td.find('input').attr('value', this.value);
table.cell($td).invalidate();
});
For textareas use text() instead :
$("#example td textarea").on('change', function() {
var $td = $(this).closest('td');
$td.find('textarea').text(this.value);
table.cell($td).invalidate();
});
This is also the case when dealing with <select>'s. You will need to update the selected attribute for the relevant <option>'s and then invalidate() the cell as well :
$("#example td select").on('change', function() {
var $td = $(this).closest('td');
var value = this.value;
$td.find('option').each(function(i, o) {
$(o).removeAttr('selected');
if ($(o).val() == value) $(o).attr('selected', true);
})
table.cell($td).invalidate();
});
forked fiddle -> http://jsfiddle.net/s2gbafuz/ Try change content of the inputs and/or the dropdowns, and search for the new values ...
If the point here is to search through all the inputs within a table based on the live values (and "regular" cells), you might want to build your own custom search ($.fn.DataTable.ext.search.push()):
//custom search function
$.fn.DataTable.ext.search.push((_,__,i) => {
//get current row
const currentTr = dataTable.row(i).node();
//look for all <input>, <select> nodes within
//that row and check whether current value of
//any of those contains searched string
const inputMatch = $(currentTr)
.find('select,input')
.toArray()
.some(input => $(input).val().toLowerCase().includes($('#search').val().toLowerCase()));
//check whether "regular" cells contain the
//value being searched
const textMatch = $(currentTr)
.children()
.not('td:has("input,select")')
.toArray()
.some(td => $(td).text().toLowerCase().includes($('#search').val().toLowerCase()))
//make final decision about match
return inputMatch || textMatch || $('#search').val() == ''
});
The complete DEMO of this approach you may find below:
const srcData = [{id:1,item:'apple',category:'fruit'},{id:2,item:'banana',category:'fruit'},{id:3,item:'goosberry',category:'berry'},{id:4,item:'eggplant',category:'vegie'},{id:5,item:'carrot',category:'vegie'}];
const dataTable = $('table').DataTable({dom:'t',data:srcData,columns:[{title:'Id',data:'id'},{title:'Item',data:'item',render:data=>`<input value="${data}"></input>`},{title:'Category',data:'category',render:data=>`<select>${['fruit', 'vegie', 'berry'].reduce((options, item) => options+='<option value="'+item+'" '+(item == data ? 'selected' : '')+'>'+item+'</option>', '<option value=""></option>')}</select>`}]});
$.fn.DataTable.ext.search.push((_,__,i) => {
const currentTr = dataTable.row(i).node();
const inputMatch = $(currentTr)
.find('select,input')
.toArray()
.some(input => $(input).val().toLowerCase().includes( $('#search').val().toLowerCase()));
const textMatch = $(currentTr)
.children()
.not('td:has("input,select")')
.toArray()
.some(td => $(td).text().toLowerCase().includes($('#search').val().toLowerCase()))
return inputMatch || textMatch || $('#search').val() == ''
});
$('#search').on('keyup', () => dataTable.draw());
<!doctype html><html><head><script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script><script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script><link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css"></head><body><input id="search"></input><table></table></body></html>
This should search the entire table instead of specific column(s).
var table = $('#table').DataTable();
$('#input').on('keyup', function() {
table.search(this.val).draw();
});
Best thing to do here is just update the cell container to the new value from the input and keep the datatable data object sync with the UI input:
$("#pagesTable td input,#pagesTable td select").on('change', function () {
var td = $(this).closest("td");
dataTable.api().cell(td).data(this.value);
});
Replace you input by Textarea, and add the css below. It will make your textarea looks like an input.
textarea{
height: 30px !important;
padding: 2px;
overflow: hidden;
}

How to differentiate between DOM elements in jQuery

I have some code that loops over each row of the table and creates a json object. The elements in the rows can be either of the following:
<input type="text" id="myelem"/>
or
<p id="myelem">foo</p>
Notice that the id attribute for the both is same. This is because on the table there is a button Add a new Row when this button is clicked another row is added to the table with a checkbox. When user submits the form the checkbox goes away and the value they entered turns into <p id="myelem">value they entered</p>
Below is the code I'm using for this.
$('.input-row').each(function(index, row) {
var innerObject = {};
var key = $('#myelem', row).val().toUpperCase();
jsonObject[key] = "bar";
});
The above works fine for textboxes becuse I'm using the .val() function. However, how do I get the data from the row if it contains <p id="myelem">foo</p> ??
my pseudo code would be something like this:
$('.input-row').each(function(index, row) {
var innerObject = {};
/*
if #myelem is a text box then use .val()
if #myelem is a <p> tag then use .html()
*/
var key = $('#myelem', row).val().toUpperCase();
jsonObject[key] = "bar";
});
ids should always be globally unique on a page. If you need multiple elements to be referenced, you should use classes. If you set myelem as a class rather than an id you could then reference it like this
$('.input-row .myelem')
You can check which type the element is with
var value = null;
if($('#myid').is('input')) {
value = $('#myid').val();
}
else if($('#myid').is('p')) {
value = $('#myid').html();
}
IDs are unique. You cannot use more than one ID in the same page. If you do so how should you decide which element to use?
You could use jQuery is() eg if $('#myelem').is ('p'){...}
If still want to stick your development way then below might help you:
$('.input-row').each(function(index, row) {
var innerObject = {};
var c = $('#myelem', row);
var isInputField = c.get(0).tagName.toUpperCase()=="INPUT";
var key =isInputField ? c.val().toUpperCase():c.html().toUpperCase();
jsonObject[key] = "bar";
});
This is to just get you started. You are using .each on class input-row but you have not shown the class in your code that you provided. I have used class instead of id in this example. Use it to work ahead.
Fiddle

Categories