What would be the best way to create a multidimensional associative array from form inputs?
The form looks like this:
<div id="items">
<h4>Engraving Text</h4>
<div class="item" data-position="1">
<h4 id="engraving-item">Item 1</h4>
<label>Engraving Line 1: </label>
<input type="text" class="engraving-input engraving-line1" name="trophy" id="item1-line1">
<br />
<label>Engraving Line 2: </label>
<input type="text" class="engraving-input engraving-line2" name="trophy" id="item1-line2">
<br />
<label>Engraving Line 3: </label>
<input type="text" class="engraving-input engraving-line3" name="trophy" id="item1-line3">
<br />
</div>
</div>
If the user enters that they want multiple items - additional inputs are dynamically added to the form using these first 3 as a template.
I'm looking to create this sort of array (for example if the user added 2 items):
var myArray = {
item1 :
[
{
engraving-line1 : "user entered data",
engraving-line2 : "more user data",
engraving-line3 : "yep, more data"
}
],
item2 :
[
{
engraving-line1 : "user entered data",
engraving-line2 : "more user data",
engraving-line3 : "yep, more data"
}
]
};
I had written this but I think I am headed in the wrong direction with it or at the very least - writing it poorly.
var totalItems = $("#quantity_wanted").val();
jsonObj = [];
i=1;
while (i < totalItems){
items = {};
$('.item[data-position="'+i+'"] :input').each(function(){
var name = $(this).attr("name");
var engraving = $(this).val();
item = {}
item ["name"] = name;
item ["engraving"] = engraving;
items.push(item);
});
jsonObj.push(items)
i++;
}
Just looking for help writing the javascript that will help me to iterate through the inputs on the screen and push them into a multidimentional associative array like the one I listed.
Your code could be much simplified.
data-position attribute in jquery selector doesn't make sense
since you don't actually use its value. You just need to select all
input group containers by their shared class (.item), then, for
each container, select all descendant inputs.
Your code building item element is redundant. You can use inline
object literal/initializer ({...}) instead.
Furthermore, as #Andy noted, items array should be initialized by array literal ([]), not object ({}).
So the code should look like this:
var jsonObj = [];
$('div.item').each(function(){
var items = [];
$(this).find('input').each(function() {
items.push({
name: $(this).attr("name"), engraving: $(this).val()
});
});
jsonObj.push(items)
});
Related
So, I'm creating a table on which the users will fill out the table's header with their options. For this example let's say I want to create 3 headers as options: "fruits", "desserts" and "others".
The "applicants" will fill their answers for those headers.
The problem I'm trying to solve is the following:
I need to sort those answers, and I had the idea to use the header as the variable of the array, and I'd fill that array with the answer, like:
let fruits = [];
fruits.push(*applicant's answers*);
I can create an array with the headers after the table is ready to be filled, like "headers = [fruits, desserts, others]" but I don't know how to create the "fruits = []" or "desserts = []", as I don't know the headers until the table is filled and ready to be answered.
Is there a way to solve this or I'll need to sort it out in an another way?
You can use an event listener on click of the input entries to run a function with arr.reduce() to iterate over an array of the titles, passing in the inputs values combining both arrays as an object, then push the object into another array with each new entry of your inputs.
const inputs = document.querySelectorAll('.inputs')
const submit = document.getElementById('submit')
const titles = ['fruits', 'deserts', 'others']
let entries = new Array()
const combineArrays = (titles, input) => {
return titles.reduce((acc, val, index) => {
acc[val] = input[index].value
return acc
}, {})
}
submit.addEventListener('click', () => {
entries.push(combineArrays(titles, inputs))
if (entries.length > 0) {
submit.value = 'Add more'
}
console.log(entries)
})
.titles {
display: inline-block;
width: 5rem;
line-height: 2em;
}
<div><span class="titles">Fruits : </span><input class="fruits inputs" name="fruits" type="text"></div>
<div><span class="titles">Deserts : </span><input class="deserts inputs" name="deserts" type="text"></div>
<div><span class="titles">Others : </span><input class="others inputs" name="others" type="text"></div>
<span class="titles"></span><input value="Add Entry" type="button" id="submit"></td>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have this:
<form>
Input name: <input type="text"/><br/>
Input last name: <input type="text"/><br/>
Your age: <input type="number"/><br/>
Your points: <input type="number"/><br/>
Overral: <input type="number"/><br/>
<button type="submit">Submit</button><br>`
What I want to do, so, as you can so i have button sumbit, and I want when i click it to make numbered list of my form. Something like this:
Mark
Williams
....
Try this, it takes all inputs and appends into a list
$(document).ready(function(){
$('button').click(function(e){
e.preventDefault();
$('#a').append('<ol><li>'+$("#name").val()+'</li><li>'+$("#last").val()+'</li><li>'+$("#age").val()+'</li><li>'+$("#points").val()+'</li><li>'+$("#over").val()+'</li></ol>')
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
Input name: <input type="text" id="name"/><br/>
Input last name: <input type="text" id="last"/><br/>
Your age: <input type="number" id="age"/><br/>
Your points: <input type="number" id="points"/><br/>
Overral: <input type="number" id="over"/><br/>
<button type="submit">Submit</button><br></form>
<div id="a"></div>
At the risk of overly complicated and wordy to newcomers (particularly when compared to 5 lines of jQuery) - here's a plain JavaScript approach with a bit of explanation as to what's going on at every step.
Adding people to the list:
<!--
1 ) Add an ID so we can identify the form
-->
<form id="person-add">
Input name: <input type="text"/><br/>
Input last name: <input type="text"/><br/>
Your age: <input type="number"/><br/>
Your points: <input type="number"/><br/>
Overral: <input type="number"/><br/>
<!-- 2 ) Add an onclick event to run a JavaScript function.-->
<button onclick="addPerson(event);">Submit</button><br>
</form>
<!-- 3 ) Add the list we'll add people to. This has an ID as well.-->
<ol id="person-list">
</ol>
<!-- 4 ) Then the JavaScript function that activates when the button is pressed. -->
<script type="text/javascript">
// It accepts a parameter, 'event' - this is passed from the onclick event.
function addPerson(event){
// By default, clicking a button in a form submits the form to the server.
// Since we're using JavaScript to create the list, we'll prevent that from happening.
event.preventDefault();
// Using querySelectorAll, we get all the input fields within '#person-add'
var person_fields = document.querySelectorAll('#person-add input');
// Here we get the #person-list element we'll be adding the person to.
var person_list = document.getElementById('person-list');
// Create a list item for the person, but don't put it in the list yet.
var person = document.createElement('li');
// Loop through the fields and add their value list item.
for( var field = 0; field < person_fields.length; field++ ) {
// Add the value of the field to the person list item.
person.innerText += person_fields[field].value;
// If the next item isn't the end of the list, we'll add a space.
if( field + 1 !== person_fields.length ){
person.innerText += ' ';
}
}
// Lastly, add the person to the person_list.
person_list.appendChild(person);
}
</script>
Sorting the list by high score:
If you wanted to extend upon this, one thing to do would be to add field names to the input fields, so you could build an array of people and then list them in order of who has the most points.
I'm not going to tell you exactly how to implement this - but here's a few hints to get you started:
Setting field names
<input type="number" name="points"/>
Creating a list of people
// Create an empty list.
var people = [];
Creating an object to respresent a person
// Create an empty object.
var person = {};
Adding values to an object
// Add a property matching the field name with the field value.
person[ person_fields[field].getAttribute('name') ] = person_fields[field].value;
Adding an object to a list
// Add the person to the list of people.
people.push( person );
Draw the list in order of highest points to lowest
Check out Mozilla docs for a breakdown of JavaScript for array sorting.
function updateList(){
// Here we get the #person-list element we'll be adding the person to.
var person_list = document.getElementById('person-list');
// Empty the person_list as we're redrawing it in order.
person_list.innerHTML = '';
// Sort the people list by highest points.
people.sort( function( person1, person2 ) {
return person2.points - person1.points;
} );
// Loop through the fields and add their value list item.
for( var position in people ) {
// Create a list item for the person, but don't put it in the list yet.
var list_item = document.createElement('li');
// Get the person.
var person = people[position];
// Add the value of the field to the person list item.
list_item.innerText += person.firstname + ' ' + person.lastname;
list_item.innerText += ' ( ' + person.points + ' points )';
// Add the list item to the person_list.
person_list.appendChild(list_item);
}
}
Hope this helps!
The code looks like this:
<div id="list">
<input type="checkbox" id="1">
<input type="checkbox" id="2">
<input type="checkbox" id="3">
</div>
In another html pane (a separate template), I want to store all those checkbox (checked/unchecked) booleans into an array. What I did looks like:
var array = [];
var checkboxli = document.getElementsByTagName("input");
for (var i = 0; i < checkboxli.length; i++)
{
array.push($("#input.prop('checked')"));
}
However, this doesn't work. I have other templates using tag name "input", so I need to limit the tag name to the ones under "#list" id (some sort of css selector perhaps). Currently, both document.getElementsByTagName("input") and $("#input.prop('checked')") won't work. There might be other syntax problems. Please help me resolve. Thanks.
EDIT: It seems like I didn't communicate my intention well. Here is what I want to get out of the list:
An array that looks like
[true, false, true, true, true...]
in which each boolean value represents whether the corresponding input checkbox is checked or not.
Since your are already using jquery, you can go like this:
Assuming this HTML
<div id="list">
<input type="checkbox" id="1" checked="checked">
<input type="checkbox" id="2">
<input type="checkbox" id="3" checked="checked">
</div>
And this script:
var array = [];
$("input[type='checkbox']","#list").each(function(){
array.push($(this).is(":checked"));
});
You would get something like this:
array = [ true, false, true ];
Instead of:
var checkboxli = document.getElementsByTagName("input");
you can use:
var checkboxli = document.querySelectorAll("#list>input[type=checkbox]"); //array of checkboxes
now you have all of the checkboxes under the list element.
if you want only the checked checkboxes you can use:
var checkboxli = document.querySelectorAll("#list>input[type=checkbox][checked]");
Try below code. It retrieves all IDs from all checked check-boxes, stores in an array and then stores in local-storage as an string:
var itemsChecked = [] ;
$('input[type=checkbox]:checked').each(function(index, item){
itemsChecked.push($(item).attr('id'));
})
localStorage.setItem('selectedItems', JSON.stringify(itemsChecked));
Later, to retrieved data from localstorage, use the following:
var items = JSON.parse(localStorage.getItem('selectedItems'));
// returns array of IDs
A more suitable approach would be to capture the XPath of each element starting from the body. You could use a getPath jQuery plugin, Thus you won't be dependent upon a specific string like the List.
jQuery.fn.extend({
getPath: function( path ) {
// The first time this function is called, path won't be defined.
if ( typeof path == 'undefined' ) path = '';
// If this element is <html> we've reached the end of the path.
if ( this.is('html') )
return 'html' + path;
// Add the element name.
var cur = this.get(0).nodeName.toLowerCase();
// Determine the IDs and path.
var id = this.attr('id'),
class = this.attr('class');
// Add the #id if there is one.
if ( typeof id != 'undefined' )
cur += '#' + id;
// Add any classes.
if ( typeof class != 'undefined' )
cur += '.' + class.split(/[\s\n]+/).join('.');
// Recurse up the DOM.
return this.parent().getPath( ' > ' + cur + path );
}
});
Hello I have a small project in which I want to have perform search from multiple dynamically added text fields.
This is how I add the search fields:
<div class="form-group" ng-repeat="choice in choices">
<button ng-show="showAddChoice(choice)" ng-click="addNewChoice()">Add another choice</button>
<input type="text" ng-model="choice.name" name="" placeholder="Search criteria">
</div>
And later I have a table with ng-repeat and here is that part:
<tr ng-repeat="todo in todos | filter: {filter from all fields}">
.......
</tr>
What I want to do is to have the contents filtered with all dynamically added search fields.
You'll have to create your own filter to handle that. I've gone ahead and gotten you started.
$scope.myFilter = function(input){
for(var key in input){
for(var x = 0; x < $scope.choices.length; x++){
if(input[key] == $scope.choices[x].name){
return true;
}
}
}
return false;
}
Here is the jsFiddle of the output: http://jsfiddle.net/wsPrv/
Rather than using the filter, do the filtering in the controller yourself. Here is the updated fiddle with the solution. In the first textbox, replace choice1 with "some" and you will see the todo with text "Some stuff" being displayed.
See the relevant part below. For details, see the fiddle.
$scope.$watch('choices', function(newValue) {
$scope.DisplayedTodos = [];
// Filter items here and push to DisplayedTodos. Use DisplayedTodos to display todos
}, true);
I have a list of checkboxes in my html page, like so:
<ul id="myList">
<li class="checkboxItem">
<input type="checkbox" name="item1" value="001" id="item-1"/>
<label for="item-1" class="checkboxLabel">Display 1</label>
</li>
<li class="checkboxItem">
<input type="checkbox" name="item2" value="042" id="item-2"/>
<label for="item-2" class="checkboxLabel">Display 42</label>
</li>
</ul>
now I make a call to get some json data, which comes back like so:
[{"name":"002","title":"Display 1"}]
what I want to do is loop the returned json and update the list of checkboxes such that any item not in the returned list is disabled, and those where the title matches a given label, the input value is updated.
so in this example, item2 will be disables and item1 will have its value updates to 002.
here's what I have so far, i'm not quite sure where to go from here, that is, what to do inside the loop. I do have some control over how the json is returned, so if it makes sense to retunr the json in another format, I can do that.
EDIT, updated the function, see below. however, once I get inside the for loop inside the each function, elem is getting a value of "0" rather than a js object such as:
{"name":"002","title":"Display 1"}. clearly data, is being transferred from the outside scope of the function to the inside scope of the each function, but how do I make that happen?
function(data) {
$('#myList').children('li').each(function(i,e) {
for(var elem in data) {
var elemDescr = elem['title'];
var elemName = elem['name'];
if(elemDescr==$(this).find('.checkboxLabel').text()) {
$(this).find('input').attr('value',elemName);
}
}
});
It might be easier to have an outer loop for each checkbox, and an inner loop go through each json element, enabling or disabling based on whether the element/checkboxes have a match.
So an inversion of what you have:
function(data) {
$('#myList').children('li').each(function() {
// loop through your data elements here
});
}
Another option (probably less desirable because it may cause multiple disabled/enabled transitions) is to disable all checkboxes, and enable them as you loop through each element.
I have found my problem. rather than doing:
for(var elem in data) {
var elemDescr = elem['title'];
var elemName = elem['name'];
}
I needed to do:
for(var index in data) {
var elemDescr = data[index].title;
var elemName = data[index].name;
}