Sort the list of objects by alphabet - javascript

How can i sort the list of elements by alphabet with dividers in Javascript.
I have the json file:
{"response":{"count":4,"items":[{"id":153684554,"first_name":"Adam"},{"id":153684554,"first_name":"Bob"},{"id":153684554,"first_name":"Caleb"},{"id":153684554,"first_name":"Alex"}]}}
and i need to sort the objects like that
A.
A....
B.
B....
B....
C.
.......
In my Jquery mobile plugin:
<ul data-role="listview" data-filter="true" data-inset="true">
<li data-role="list-divider">A</li>
<li>Adam Kinkaid</li>
<li>Alex Wickerham</li>
<li>Avery Johnson</li>
<li data-role="list-divider">B</li>
<li>Bob Cabot</li>
<li data-role="list-divider">C</li>
<li>Caleb Booth</li>
</ul>
How can i implement that with for operator? Thanks in advance and sorry for my English!

You could have something like this:
var json = {"response":{"count":4,"items":[{"id":153684554,"first_name":"Adam"},{"id":153684554,"first_name":"Bob"},{"id":153684554,"first_name":"Caleb"},{"id":153684554,"first_name":"Alex"}]}}
var users = [];
$.each(json.response.items, function( key, user ) {
users.push(user.first_name);
});
users.sort();
var existent_letters = [];
$.each(users, function( key, user ) {
var current_letter = user.charAt(0);
existent_letters.push(current_letter);
});
$.unique(existent_letters);
var return_html = "";
$.each(existent_letters, function( keyLetter, letter ) {
return_html += '<li class="separator">'+letter+'</li>';
$.each(users, function( keyUser, user ) {
if(user.indexOf(letter) == 0) {
return_html += '<li>'+user+'</li>';
}
});
});
$('#listview').html(return_html);
I've put together for you a JSFiddle to illustrate this code.

The easier is to go recursive.
Loop on the items array and compare first_name of index with first_name index+1.
If index+1 doesnt exists you're at the end of array.
If you swap, start from index-1 to verify with previous element.
var json = {"count":4,"items":[{"id":153684554,"first_name":"Adam"},{"id":153684554,"first_name":"Bob"},{"id":153684554,"first_name":"Caleb"},{"id":153684554,"first_name":"Alex"}]};
function sort(json, index) {
if (json.length-1 < index+1)
return json;
if (json[index].first_name > json[index+1].first_name) {
var tmp = json[index];
json[index] = json[index+1];
json[index+1] = tmp;
return sort(json, index-1);
}
return sort(json, index+1);
}
sort(json.items, 0);
Then to create the ul/li set, loop on the sorted json and check if first_name first letter differs from the previous one and add li with data-role attribute.
if (divider != json[i].first_name[0]) {
"<li data-role="+json[i].first_name[0]+">";
divier = json[i].first_name[0]
}

check this fiddle
document.addEventListener('DOMContentLoaded',function(){
var a = {"response": {"count": 4, "items": [
{"id": 153684554, "first_name": "Adam"},
{"id": 153684554, "first_name": "Bob"},
{"id": 153684554, "first_name": "Caleb"},
{"id": 153684554, "first_name": "Alex"}
]}}
var b = a.response.items.sort(function (a, b) {
return a.first_name>b.first_name;
})
var buffer="";
for(i in b){
buffer+="<li data-role='list-divider'>"+b[i].first_name+"</li>";
}
document.getElementsByTagName('ul')[0].innerHTML=buffer;
},false);

Try this:
var data = {"response":{"count":4,"items":[{"id":153684554,"first_name":"Adam"},{"id":153684554,"first_name":"Bob"},{"id":153684554,"first_name":"Caleb"},{"id":153684554,"first_name":"Alex"}]}};
data.response.items.sort(compare);
show(data);
function compare(a,b) {
if (a.first_name < b.first_name)
return -1;
if (a.first_name > b.first_name)
return 1;
return 0;
}
function show(data) {
var len = data.response.items.length;
for (var i = 0; i < len; i++) {
var t = data.response.items[i];
var role = t.first_name.substr(0, 1).toUpperCase();
if ($("body").find("li[data-role='list-divider']:contains(" + role + ")").length < 1){
$("body").append("<li data-role='list-divider'>" + role + "</li>");
}
$("body").append("<li>" + t.first_name + "</li>");
}
}
Fiddle here.

Related

How to handle repeating values in JQuery

I'm trying to dynamically render values I am pulling from SQL that looks like this:
into something that looks like this:
I already have HTML and CSS placed and I am approaching this using $.each but I cant seem to populate the inside of the view tree:
EDIT:
here is my script:
AjaxGet('GetUserAppFeatures', { "uid": userid }, false, true)
.success(function (result) {
$.each(result.model, function (val) {
var li = $('<li></li>');
li.append('<span class="caret">' + result.model[val].AppName + '</span> <input type="checkbox" id="chkApp' + result.model[val].AppId + '">');
var ul = $('<ul class="nested"></ul>');
$.each(result.model[val], function (index) {
ul.append('<li>' + result.model[val].FeatureName[index] + '</li> <input type="checkbox" id="chkApp' + result.model[val].FeatureId[index] + '">');
li.append(ul);
});
treeview.append(li);
});
});
For this type of data you need to group by.
var yourData = [
{Name : "Forms", value : "Request"},
{Name : "Forms", value : "Report"},
{Name : "Forms", value : "Password"},
{Name : "Energy", value : "Report"},
{Name : "Energy", value : "CUstomer Multiplier"},
{Name : "Energy", value : "Product Feedback"},
];
Renderdata();
function Renderdata(){
var data = groupBy(yourData,"Name");
var html = '';
for(var i= 0 ; i < data.length; i++){
html += "<div>"+data[i][0].Name+" </div>"+"<ul>";
for(var j= 0 ; j < data[i].length; j++){
html += "<li>"+data[i][j].value+"</li>";
}
html += "</ul>";
}
$('#div').html(html);
}
function groupBy(collection, property) {
var i = 0, val, index,
values = [], result = [];
for (; i < collection.length; i++) {
val = collection[i][property];
index = values.indexOf(val);
if (index > -1)
result[index].push(collection[i]);
else {
values.push(val);
result.push([collection[i]]);
}
}
return result;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="div"></div>
Perhaps you need an intermediate step where you construct an array modelling the second image you have there. Something like:
// Do this before $.each()
var sql_data = {
Forms: [],
Energy: []
};
// Inside of $.each() do something like this:
sql_data[col_1].push(col_2);
Where "col_1" and "col_2" are respectively the first and second columns in your data. Then you can use that "sql_data" object to create the HTML that you need.

Instantiate the value of an array from one function to a different function in jquery

I want to get the result of a jquery function attached to an id and change e.g
<script>
$('#dateID').change(function(){
var bookday = $(this).val();
$.post('getDates.php',{postbookday:bookday},
function(data){
var array = JSON.parse("[" + data + "]");
var list = [];
var newArray = array.flat([2]);
for (var i = 0; i < newArray.length; i++) {
list.push(newArray[i]);
};
if (list.length>96) {
alert("Sorry, day fully booked!");
}
else{
function selectedTime(list) {
return [a, b, c];
}
var result = selectedTime(list);
var myArray = [];
for (var i=0; i < result[2].length; i++) {
if (result[2][i] === '09:00') {
myArray.push(['09:00','10:00']);
}
if (result[2][i] === '10:00') {
myArray.push(['10:00','11:00']);
// here is myArray
}
}
}
});
});
</script>
and then use it as the input in another different function below:
$('#disableTimeRangesExample').timepicker(
{
'disableTimeRanges': myArray
}
);
How do I get myArray in the next function? considering that it is not static.
You have two options:
1. save the variable in outer scope:
var myArray;
$('#selectedDate').change(function(
...some computations...
myArray = [['1pm', '2pm']];
});
$('#disableTimeRangesExample').timepicker({
'disableTimeRanges': myArray
});
2. save in jQuery data
$('#selectedDate').change(function(
...some computations...
$(this).data('array', [['1pm', '2pm']]);
});
$('#disableTimeRangesExample').timepicker({
'disableTimeRanges': $('#selectedDate').data('array') || []
});
As a side note you will probably also need to update timepicker on each change.
EDIT: to update time picker on change of the input you need to put this inside change event:
$('#dateID').change(function(){
var bookday = $(this).val();
$.post('getDates.php',{postbookday:bookday},
function(data){
var array = JSON.parse("[" + data + "]");
var list = [];
var newArray = array.flat([2]);
for (var i = 0; i < newArray.length; i++) {
list.push(newArray[i]);
};
if (list.length>96) {
alert("Sorry, day fully booked!");
}
else{
function selectedTime(list) {
return [a, b, c];
}
var result = selectedTime(list);
var myArray = [];
for (var i=0; i < result[2].length; i++) {
if (result[2][i] === '09:00') {
myArray.push(['09:00','10:00']);
}
if (result[2][i] === '10:00') {
myArray.push(['10:00','11:00']);
// here is myArray
}
}
$('#disableTimeRangesExample').timepicker(
'option', {'disableTimeRanges': myArray}
);
}
});
});
$('#disableTimeRangesExample').timepicker();

Loop using two related arrays

When a button is clicked i want the results in the array to be listed for example: John Smith 16, Jack Snow 10 etc..
I want to use a loop however the code in my loop is incorrect at the moment as when i click the button all i get is: [object Object].
Can someone provide a possible fix?
function begin() {
listresults();
();
}
var results1 = {name:"John Smith", score:16};
var results2 = {name:"Jack Sow", score:10};
var results3 = {name:"Tessa Flip", score:15};
var results = [results1, results2, results3];
function listresults() {
var text = "";
var total = 0;
var i;
for (i in results) {
text += results[i] + "<br>";
}
document.getElementById('message').innerHTML = text;
}
I would first check that the lengths of the 2 arrays are the same. Then iterate using a for loop:
final int timeLength = TIME.length;
if (timeLength != stat.size()) {
//something may not be right
}
for (int i = 0; i < timeLength; i++) {
System.out.println(time[i]+" "+stat.get(i));
}
You are pushing objects results1, results2, etc in the array 'results'.
So while iterating the array you should access the object properties as shown below:
function listresults() {
var text = "";
var total = 0;
var i;
for (i in results) {
text += results[i]['name'] + ' ' + results[i]['score'] + "<br>";
}
As you are appending objects instead of object values in the filed.
This is the proper way of accessing name and score from object which is returned when you are looping through your array of objects :
function begin() {
listresults();
();
}
var results1 = {name:"John Smith", score:16};
var results2 = {name:"Jack Sow", score:10};
var results3 = {name:"Tessa Flip", score:15};
var results = [results1, results2, results3];
function listresults() {
var text = "";
var total = 0;
for (var i=0; i < results.length; i++) {
text += results[i].name + " " + results[i].score + "<br>";
}
document.getElementById('message').innerHTML = text;
}
Here is an Jsfiddle example
Recommend you to use Array methods(map, join) instead of pure loops
function begin() {
listresults();
}
var results1 = {name:"John Smith", score:16};
var results2 = {name:"Jack Sow", score:10};
var results3 = {name:"Tessa Flip", score:15};
var results = [results1, results2, results3];
function listresults() {
document.getElementById('message').innerHTML =
results.map(function(item) {
return item.name + ' ' + item.score;
}).join('<br>');
document.getElementById('total').innerHTML =
results.map(function(item) {
return item.score;
}).reduce(function(sum, score) {
return sum + score;
}, 0);
}
<button onclick="begin()">begin</button>
<br />
<div id="message"></div>
<div>total: <span id="total">0</span></div>
Use Array.map() and Array.join()
var results1 = {name:"John Smith", score:16};
var results2 = {name:"Jack Sow", score:10};
var results3 = {name:"Tessa Flip", score:15};
var results = [results1, results2, results3];
var res = results.map(item => { return item.name+ " " +item.score });
console.log(res.join(", "));

Using index position to filter an array by values in another array - javascript

I'm working with an extremely large data cube that I need to manipulate for data visualization purposes. I have a multidimensional array contains arrays of every possible combination of objects, with the final object of each array being an associated value.
I'm using multiple inputs (each with id's enumerated based off of the value's index in data) to allow users to filter the results by each object within the array, except for the last object that is displayed as "total available". From those inputs I'm aggregating selections into a variable so that the index of the selections corresponds to the index position of the associated value in data.
var selections = [];
var data = [[val0, val1, val2, 5121231], [val0, val1, val2, 2242], [val0, val1, val2, 72356], [val0, val1, val2, 24122], [val0, val1, val2, 75632]];
$('#fields').change(function(){
for (var i = 0; i < data[0].length; i ++){
selections[i] = $('select#field' + i).val();
}
});
This will create a multidimensional array that looks like this:
selections = [[data[0][0], data[1][0], data[2][0], data[3][0], data[4][0]], [data[0][1], data[1][1], data[2][1], data[3][1], data[4][1]], [data[0][2], data[1][2], data[2][2], data[3][2], data[4][2]], [data[0][3], data[1][3], data[2][3], data[3][3], data[4][3]]]
What I'm attempting to do is filter data such that for ALL selections made, if data[x][i] === any value in selections[i], data[x] is populated into a new array.
Any thoughts?
*****UPDATE*****
A HUGE thanks to Dave for his help! We were able to set up dependent dropdown filters that manipulates a keyless multidimensional array (data cube). If you're working with large data sets in-browser, take a look at the solution. Here's what he/we came up with:
https://jsfiddle.net/JSnoobDC16/yteu6cbb/28/
Since you're using jQuery, this can easily be solved using $.grep() combined with Array.some().
var newArray = $.grep(data, function(item) {
return selections.some(function(selectedValue, i) {
return selectedValue.indexOf(item[i]) >= 0;
});
});
There's a full snippet below and an updated fiddle here: https://jsfiddle.net/gh8fzxLh/
//function to initialize the materialize dropdowns
function pageReady() {
$(document).ready(function() {
$('select').material_select();
});
}
//function to get the sum of object elements
function sum( obj ) {
var sums = 0;
for( var el in obj ) {
if( obj.hasOwnProperty( el ) ) {
sums += parseFloat( obj[el] );
}
}
return sums;
}
//function to return array of all values at a certain index positon
function getFields(matrix, index){
var fields = [];
for (var i = 1; i<matrix.length; i++ ){
fields.push(matrix[i][index]);
}
return fields;
}
//function to return only unique values from array
function unique(arr) {
var hash = {}, uniqueArr = [];
for ( var i = 0, l = arr.length; i < l; ++i ) {
if ( !hash.hasOwnProperty(arr[i]) ) {
hash[ arr[i] ] = true;
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
}
//importing data set
var data = [
["state", "gender", "martial staus", "ethnicity"],
["GA", "null", "null", "Caucasian", 5086317],
["FL", "", "null", "null", 4338099],
["IN", "M", "null", "African-American", 72238],
["GA", "", "married", "Caucasian", 390578],
["MO", "null", "null", "Caucasian", 4165871],
["MO", "", "married", "Caucasian", 344501],
["NY", "null", "null", "African-American", 1204504], ["AR", "M", "single", "Caucasian", 164311],
["CO", "null", "married", "null", 551192],
["OH", "null", "married", "Caucasian", 1017924],
["LA", "M", "null", "East Asian", 3229],
["AZ", "F", "single", "Uncoded", 21302],
["AR", "", "married", "Middle Eastern", 187]
];
var selections = []; //variable to hold all selected values
var valCombos = data[0].length; //establishing number of dropdown selection objects
/* Adding multiselection dropboxes (and soon to be other data inputs)
for each field. */
for (var i = 0; i < valCombos; i ++){
var options = unique(getFields(data, i)).sort();
$('#selectBar').append('<div class="row section params" id="fieldRow' + i + '"><div class="col s12 input-field" id="fieldparams"><select class="fields" id="field' + i + '" multiple><option value="" disabled selected>Select Values</option></select><label>' + data[0][i] + '</label></div></div>');
$.each(options, function (index, value) {
$('#field' + i).append('<option value="' + value + '">' + value + '</option>');
});
}
pageReady();
/*Updating "selections" array as user makes selections.
"Selections" will be used to filter the cube for visualizations. */
$('.fields').change(function(){
for (var i = 0; i < valCombos; i ++) {
selections[i] = $('select#field' + i).val();
}
console.log(selections);
var selectedData = getSelectedData(data, selections);
console.log(selectedData);
$("#count").text(sumData(selectedData));
});
function getSelectedData(data, selections) {
return $.grep(data, function(item) {
return selections.some(function(value, i) {
return value.indexOf(item[i]) >= 0;
});
});
}
function sumData(selectedData) {
return selectedData.reduce(function(prev, current) {
return prev + current[current.length - 1];
}, 0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/js/materialize.min.js"></script>
<div id="count">
Sum of lastIndexOf values displays here
</div>
<div id="selectBar">
</div>

javascript loop form values by name then element id

I have loop going though form values, it is working fine throwing out the values based on the input name. But I would also like to be able to target by specific element id.
This is an example form:
_inputFields: function() {
var rows = [];
for(var i = 1; i <= 12; i++) {
var placeHolder = 'Intro text line ' + i;
var inputID = 'inputIntroText ' + i;
rows.push(<input type="text" className="form-control input-size-lg" name="formInput" id="inputText" placeholder={placeHolder}/>);
rows.push(<input type="text" className="form-control input-size-lg" name="formInput" id="inputTime" placeholder={placeHolder}/>);
}
So I can loop through and grab everything by name i.e. 'formInput' but how can I then grab formInput[inputText] and formInput[inputTime]?
This is my current loop through the values :
// gather form input
var elem = document.getElementsByName('formInput');
console.log(elem);
// Build the object
var obj = {
"DataObject": {
"user": {
"-name": "username"
},
"contentFile": {
"-filename": "Breaking_News",
"lock": {
"-fileIsBeingEdited": "false"
},
"content": {
"line": []
}
}
}
};
var line = obj.DataObject.contentFile.content.line;
for (var i = 0; i < elem.length; i++) {
if (elem[i].value != '') {
line.push({
"-index": i,
"-text": elem[i]['inputText'].value,
"-time": elem[i]['inputTime'].value
});
}
};
If I try:
"-text": elem[i]['inputText'].value,
"-time": elem[i]['inputTime'].value
I get the error: Cannot read property 'value' of undefined
This errors because elem[i]['inputText'] is undefined. This is because you are trying to lookup the inputText property of the element, which doesn't exist.
elem is an array, so I'd recommend using something like filter.
"-text": elem.filter(function(item) {
return item.id === 'inputText';
})[0].value;
Also, you should remove the for loop or you will get a duplicate line.
function getElementById(elems, id){
return elems.filter(function(item) {
return item.id === id;
})[0];
}
var line = obj.DataObject.contentFile.content.line;
line.push({
"-text": getElementById(elem, 'inputText').value,
"-time": getElementById(elem, 'inputTime').value
});
Here's an example jsfiddle.
You can use elem[i].id:
var line = obj.DataObject.contentFile.content.line;
for (var i = 0; i < elem.length; i++) {
if (elem[i].value != '') {
line.push({
"-index": i,
"-text": elem[i].id
// Since you are looping through the inputs, you will get the `inputTime` in the 2nd iteration.
});
}
};

Categories