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.
Related
So I have a select element and I am appending the data I am getting back from my API.
function getHeadData() {
$("#itemSelect").empty();
if (headitemData.length < 1) {
$.getJSON("http://localhost:9000/api/helmets", function (key, value) {
console.log("request helmets");
var item = "";
headitemData = key;
var len = key.length;
for (let i = 0; i < len; i++) {
item += '<option value="' + key + '">' + key[i].Name + '</option>';
}
$('#itemSelect').append(item);
});
}
else {
clearIndex(headitemData);
}
}
That right there returns this
Which is just what I want.
But if I want to get other data like.. the Icon
Let's say I want to log to the console when I select a item from the Select element, how would I do that?
The end goal is to print out the Icon property of the json object when I change item in the Select.
JsonData example
<ItemModel>
<ACrush>+0</ACrush>
<AMagic>-5</AMagic>
<ARange>-2</ARange>
<ASlash>+0</ASlash>
<AStab>+0</AStab>
<DCrush>+43</DCrush>
<DMagic>-3</DMagic>
<DRange>+48</DRange>
<DSlash>+49</DSlash>
<DStab>+47</DStab>
<Icon>
https://vignette.wikia.nocookie.net/2007scape/images/a/a0/3rd_age_full_helmet.png/revision/latest?cb=20141217224936
</Icon>
<MagicDamage>+0%</MagicDamage>
<MeleeStrength>+0</MeleeStrength>
<Name>3rd age full helmet</Name>
<Prayer>+0</Prayer>
<RangedStrength>+0</RangedStrength>
<Slayer>0</Slayer>
<Undead>0</Undead>
</ItemModel>
You can set a data for your option like:
'<option data-icon="'+ key[i].Icon +'"></option>'
And then you can bind a change for your select after create your list:
$('select').on('change', function () {
const _this = $(this).find(':selected');
const icon = _this.attr('data-icon');
console.log(icon);
})
Since you want to use the data in other areas of your code, use a closure to create an environment where your variables don't leak out into the global space. For example, with the callback:
(function () {
var myData;
function test(callback) {
$.getJSON("http://localhost:9000/api/helmets",function (data) {
callback(data);
});
}
test(function (data) {
myData = data;
});
function getHeadData() {
$("#itemSelect").empty();
if (headitemData.length < 1){
console.log("request helmets");
var item = "";
headitemData = myData;
var len = myData.length;
for (let i = 0; i < len; i++) {
item += '<option value="' +myData+ '">' + myData[i].Name + '</option>';
}
$('#itemSelect').append(item);
}
else {
clearIndex(headitemData);
}
}
$("#itemSelect").on("change",function(){
var value = $(this).val();
var newData = myData.filter(item=>{
if(myData.Name==value){
return item;
}
});
console.log(newData.Icon);
});
myData is cached as a global variable specific to that closure. Note the other functions will only be able to use that variable once the callback has completed.
Modified version below:
function getHeadData() {
$("#itemSelect").empty();
if (headitemData.length < 1) {
$.getJSON("http://localhost:9000/api/helmets", function (key, value) {
console.log("request helmets");
var item = "";
headitemData = key;
var len = key.length;
for (let i = 0; i < len; i++) {
var icon=key[i].Icon;
item += '<option data-icon="'+icon+'" value="' + key + '">' + key[i].Name + '</option>';
}
$('#itemSelect').append(item);
});
}
else {
clearIndex(headitemData);
}
}
Simple test to get the Icon from the first option in select:
//Get first option to test output
var test=$("#itemselect option:first");
//Read data-icon
console.log(test.data('icon'));
//To update data-icon
test.data('icon','new icon');
To echo when select is changed
$("#itemselect").change(function(e) {
var optionSelected = $("option:selected", this);
console.log (optionSelected.data('icon'));
});
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.
});
}
};
I'm getting error: setAttribute' on 'Element': 2 arguments required, but only 1 present.
I want to add attributes to an input but i'm avoiding repeats:
//putHolder.setAttribute("placeholder", "Product Name (required)");
//putHolder.setAttribute("ng-model", "vm.product.productName");
//putHolder.setAttribute("ng-minlength", "4");
//putHolder.setAttribute("ng-maxlength", "12");
//putHolder.removeAttribute("size");
I have used the following code but i can't get it right:
var putHolder = document.getElementById('CustomerID');
//var result = '{"placeholder":"Product Name (required)","ng-model":"vm.product.productName","ng-minlength":"4", "ng-maxlength":"12"}';
//$.each($.parseJSON(result), function (k, v) {
// putHolder.setAttribute(k + ' = ' + v);
// });
//or js please i prefer javascript
JSON.parse('{"placeholder":"Product Name (required)","ng-model":"vm.product.productName","ng-minlength":"4", "ng-maxlength":"12"}', function(k, v) {
putHolder.setAttribute(k + ' = ' + v);
});
I've also tried a loop but is just 1 elem like so:
var names = ["size", "value"];
for (var i = 0; i < names.length; i = ++i) {
var cadaUno = names[i];
putHolder.removeAttribute(cadaUno);
}
I hope someone can help thanks.
i have problem to convert array to another array. When i try to push in new array, it just add second index.
Here is my Array :
var emailAddr = [
{
customerID : "C20121121221327_249",
email : "fanjavaid#gmails.com",
files : [
"201409011141106_082895250262",
"201410011171208_082895250262"
]
},
{
customerID : "C20121121221327_300",
email : "fandi.java#gmail.com",
files : [
"201409011141106_xxx",
]
}
];
Here my code to create new array :
var penampungan = [];
for (var i = 0; i < emailAddr.length; i++) {
var data = {
customerID : emailAddr[i].customerID,
email : emailAddr[i].email
};
for (var j = 0; j < emailAddr[i].files.length; j++) {
data['master'] = emailAddr[i].files[j] + ".pdf";
data['detail'] = emailAddr[i].files[j] + "_detail.pdf";
penampungan.push(data);
}
}
console.log(penampungan);
My expected result is like this :
var newArray = [
{
customerID : "C20121121221327_249",
email : "fanjavaid#gmail.com",
master : "201409011141106_082895250262.pdf",
detail : "201409011141106_082895250262_detail.pdf"
},
{
customerID : "C20121121221327_249",
email : "fanjavaid#gmail.com",
master : "201410011171208_082895250262.pdf",
detail : "201410011171208_082895250262_detail.pdf"
},
{
customerID : "C20121121221327_300",
email : "fandi.java#gmail.com",
master : "201409011141106_xxx.pdf",
detail : "201409011141106_xxx_detail.pdf"
}
];
How to create that?
Thank you.
You need to move data creation to the inner loop
var penampungan = [];
for (var i = 0; i < emailAddr.length; i++) {
for (var j = 0; j < emailAddr[i].files.length; j++) {
var data = {
customerID : emailAddr[i].customerID,
email : emailAddr[i].email
};
data['master'] = emailAddr[i].files[j] + ".pdf";
data['detail'] = emailAddr[i].files[j] + "_detail.pdf";
penampungan.push(data);
}
}
Like this:
var penampungan = [];
for (var i = 0; i < emailAddr.length; i++) {
for (var j = 0; j < emailAddr[i].files.length; j++) {
var data = {};
data.customerID = emailAddr[i].customerID,
data.email = emailAddr[i].email
data.master = emailAddr[i].files[j] + ".pdf";
data.detail= emailAddr[i].files[j] + "_detail.pdf";
penampungan.push(data);
}
}
console.log(penampungan);
First of all, why not create a class? It would organize the data in each element of your array for you and reduce the amount of code needed to be parsed. May I suggest something like:
function Info (customerID, email, files) {
this.customerID = customerID;
this.email = email;
this.files = files;
this.penampungan = function () {
var newObjects = new Array (files.length);
for (var i = 0; i < files.length; i++) {
newObjects [i] = {
customerID : this.customerID,
email : this.email,
master : files [i] + ".pdf",
detail : files [i] + "_detail.pdf",
};
}
return newObjects;
}
}
Now make a for statement that takes an Info array and loads the penampungan objects into a new array.
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.