Display pictures based on specific student ID - javascript

So after pulling all the information from my sql tables, I put them into 2 variables called response1 and response2.Shown below are what's currently inside the arrays. My goal is to display the pictures, beside each student. If a picture doesn't exsist, it can just be blank for now. So i've gotten the picture from DB to display by using base64 encode, but i'm only currently doing it for the id:20000001, since i'm not sure how to do it for other ones.
I had an idea to maybe replace
student_image= findItemByID(response2,'20000001');
with
student_image= findItemByID(response2,element.id); ?
but not sure if this is correct logic?
Inside my Object.keys final loop, how should I fix html+='<img src="data:image/jpeg;base64,'+student_image.photo+'">' so that it adds the image of the specific id?
Response1 array of object:
0: {Class_Student_Group: 1, names: "Lastname1, Firstname1", id: 20000001}
1: {Class_Student_Group: 2, names: "Lastname2, Firstname2", id: 20000002}
2: {Class_Student_Group: 3, names: "Lastname3, Firstname3", id: 20000003}
3: {Class_Student_Group: 5, names: "Lastname4, Firstname4", id: 20000004}
4: {Class_Student_Group: 3, names: "Lastname5, Firstname5", id: 20000005}
Response2 array of objects:
0: {student_id: "20000001", photo: ""}
1: {student_id: "20000001", photo: "/9j/4AAQSkZJRgABAQAAAQABAAD/4QB6RXhpZgAASUkqAAgAAA…9a1EtFKAnd09f/rVlwfdFbVw7LPIoOAGNYwjc/SIaxR//2Q=="}
2: {student_id: "20000002", photo: ""}
3: {student_id: "20000003", photo: ""}
final:
1: Array(4)
0: {Class_Student_Group: 1, names: "Lastname1, Firstname1", id: 20000001}
1: {Class_Student_Group: 1, names: "Lastname9, Firstname9", id: 20000009}
2: {Class_Student_Group: 1, names: "Lastname15, Firstname15", id: 20000015}
3: {Class_Student_Group: 1, names: "Lastname19, Firstname19", id: 20000019}
length: 4
__proto__: Array(0)
2: (4) [{…}, {…}, {…}, {…}]
3: (4) [{…}, {…}, {…}, {…}]
output so far:
<script type="text/javascript">
$(document).ready(function() {
var response= <?php echo json_encode($table); ?>;
var response2= <?php echo json_encode($result); ?>;
function findItemByID(arr, id) {
return arr.find((photoObj) => {
return photoObj.photo.trim().length !== 0 && photoObj.student_id === id
})
}
var final = {}
response.forEach(function(element) {
final[element.Class_Student_Group] = final[element.Class_Student_Group] || [];
final[element.Class_Student_Group].push(element);
});
let student_image =''
Object.keys(final).forEach(function(Group) {
let html = '';
//add the table opening tag to the html variable
html += '<table>';
//Append the 'category' header
html += '<tr>';
html += '<td><h1>'+"Group"+ Group+'</h1></td>';
html += '</tr>';
// Loop through the results for this 'category'
student_image= findItemByID(response2,'20000001');
final[Group].forEach(function(element) {
var randomImage = images[Math.floor(Math.random() * images.length)];
var names = element.names;
var id=element.id;
var img = "<img src=' " + randomImage+ " ' />";
html += '<tr>';
html += '<td><p>' + names + '</p></td> ';
html += '<td><p>' + id + '</p></td> ';
html+='<img src="data:image/jpeg;base64,'+student_image.photo+'">'
html += '</tr>';
});
//add the table closing tag to the html variable
html += '</table>';
$('#tables_container').append(html);
});
});
</script>

OK. Quite a few things going on here.
Basically the reason(s) the findItemByID() function wasn't working was because A. (and I have to assume you knew this) you were passing in the same ID every time it was called, B. by putting it before you called final[Group].forEach(function(element) you couldn't pass in the right value for the id, as the id is a property of that element variable, and C. === is a strict equality operator, which means it only returns true if the values are the same and they are the same type. In one array of objects that value is a string and in the other it's a number.
You are doing a lot of things out of order. Take a step back and try to think about what this code is intended to do and write it one step at a time, and break your steps into functions whenever practical like I have done here. Look over the changes I have made to your code, and the comments I added. Generally when writing code you want to use functions to make things more readable, and break them apart so you are dealing with the least amount of complexity as possible at any given time. A table works like table - > row - > column -- write your code that way.
I don't know anything about using Base64 for images in HTML, but a look at this link suggests that the data you have supplied here won't work. Check out the decoder in the accepted answer.
I changed the way you were iterating over your final object. This is probably mostly a matter of taste, but to me it's more readable. You can learn more about it here
Use better names! It's so much easier when you're trying to figure out why something is broken if you aren't also trying to remember what data is in response vs response2. Just call them studentDataArray and imageDataArray or something.
$(document).ready(function () {
loadTable();
});
let array1 = [
{ Class_Student_Group: 1, names: "Lastname1, Firstname1", id: 20000001 }
, { Class_Student_Group: 2, names: "Lastname2, Firstname2", id: 20000002 }
, { Class_Student_Group: 3, names: "Lastname3, Firstname3", id: 20000003 }
, { Class_Student_Group: 5, names: "Lastname4, Firstname4", id: 20000004 }
, { Class_Student_Group: 3, names: "Lastname5, Firstname5", id: 20000005 }
]
let array2 = [{ student_id: "20000001", photo: "" }
, { student_id: "20000001", photo: "/9j/4AAQSkZJRgABAQAAAQABAAD/4QB6RXhpZgAASUkqAAgAAA…9a1EtFKAnd09f/rVlwfdFbVw7LPIoOAGNYwjc/SIaxR//2Q==" }
, { student_id: "20000002", photo: "" }
, { student_id: "20000003", photo: "" }];
function findItemByID(arr, id) {
return arr.find((photoObj) => {
return photoObj.photo.trim().length !== 0 && photoObj.student_id == id // because the id property in the student object is a number and in the photo array it's a string, change this to '==', which evaluates '2' as equal to 2. === only returns true if they are the same type
//also you have been checking for a student_id property here, which doesn't exist on the second array's objects, so this wasn't returning anything
})
}
function getFinalObject(response) {
var final = {}
response.forEach(function (element) {
final[element.Class_Student_Group] = final[element.Class_Student_Group] || [];
final[element.Class_Student_Group].push(element);
});
return final;
}
function appendHtmlToDoc(final, response2, images) {
let html = '';
//add the table opening tag to the html variable
html += '<table>';
for (let Group in final) { //this will loop through final's properties, in this case, the 'groups'
if (final.hasOwnProperty(Group)) { //use hasOwnProperty to make sure you aren't looping through irrevelant properties (https://stackoverflow.com/questions/8312459/iterate-through-object-properties)
//Append the 'category' header
html += '<tr>';
html += '<td><h1>' + "Group" + Group + '</h1></td>';
html += '</tr>';
// Loop through the results for this 'category'
final[Group].forEach(function (element) { //you already have the Group array in the Group variable
let student_image = findItemByID(response2, element.id); //search for the image data using this element's id property
// var randomImage = images[Math.floor(Math.random() * images.length)]; //should pass 'images' into this function, but I don't know where it came from and randomImage/img isn't used in the code you provided, so I removed it
var names = element.names;
var id = element.id;
// var img = "<img src=' " + randomImage + " ' />";
html += '<tr>';
html += '<td><p>' + names + '</p></td> ';
html += '<td><p>' + id + '</p>';
if (student_image) { //check if something was returned when you searched for the photo, otherwise you'll have a blank image here
html += '<td><img src="data:image/jpeg;base64, ' + student_image.photo + '"></td>'; //I don't know anything about using images in HTML with base64, but a look at this link (https://stackoverflow.com/questions/8499633/how-to-display-base64-images-in-html) suggests that what you have provided won't work
}
//I also added a td around your img tag
html += '</tr>';
});
}
}
//add the table closing tag to the html variable
html += '</table>';
//console.log(html)
$('#tables_container').append(html);
}
function loadTable() {
//move your php script calls here
let finalObj = getFinalObject(array1);
appendHtmlToDoc(finalObj, array2);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="tables_container"></div>

Try:
if(!photo.id) {
// There's no image
} else {
// There's an image
}

Related

Compare 'order' to 'products' array and print product names if in the order?

I have an array of products:
const products = {
{
id: item1,
name: 'My product',
price: 100
},
{
id: item2,
name: 'My other product',
price: 200
},
{
id: item3,
name: 'My other other product',
price: 150
}
}
I also have an order state which says which and how many products are in the order. In this instance there is 1 item1 and 2 item2 in the order:
const orderState = {
item1: 1,
item2: 2
}
How can I render the prodcut name and number of times its in the order? Im using React but I think vanilla JS is all thats needed for the solution.
My HTML output needs to be something like:
<ul>
<li>My product x1 = $1</li>
<li>My other product x2 = $4</li>
</ul>
The way you're storing your data is what seems to be giving you difficulty. First, make the array of products an actual array:
const products = [
{
id: item1,
name: 'My product',
price: 100
}, //...
];
Additionally, what is that item1 value? Is that an actual ID of some kind, like an integer? That's what you'll use to identify the products later.
Then for your "order state", create an object which holds an array of references to the products. Something like this:
const orderState = {
products: [
{
productID: item1,
quantity: 1
},
{
productID: item2,
quantity: 2
}
]
}
Now that you have a more sensible data structure, you can more easily operate on that structure. There are a variety of ways to build your output, and how you do it may depend heavily on what other tools you're using (such as template engines and such). But just to demonstrate the logic, let's build a simple string:
var output = '<ul>';
for (var i = 0; i < orderState.products.length; i++) {
var product = {};
for (var j = 0; j < products.length; j++) {
if (products[j].id == orderState.products[i].id) {
product = products[j];
break;
}
}
output += '<li>' + product.name + ' x' + orderState.products[i].quantity + ' = $' + (product.price * orderState.products[i].quantity) + '</li>';
}
output += '</ul>';
From this you can refactor and improve as needed. For example, the logic to find the product based on its id can be extracted into its own function, or perhaps even reduced to a one-liner using built-in JavaScript functionality or framework functionality. (underscore.js is good for functionality like that.)
But the basic idea is to keep the data structures sensibly organized. Then the code which operates on those structures becomes trivial.
With below solution you can get the names of selected products as per your question statement.
let productsOrderedIds = Object.keys(orderState);
let proNames = [];
for(let pro of products) {
if(productsOrderedIds.indexOf(pro.id) !== -1){
proNames.push(pro.name);
}
}
console.log(proNames);

Render each Objects in an array in HTML from JavaScript

I have a JavaScript array of objects taken from a JSON file. Each object in the array represents a product. The following code shows the JavaScript. The console.log displays each element in the console, however the innerHTML only renders the last as this is the last value to be rendered.
/* global $ */
var output = document.getElementById('output');
var products = [];
$.getJSON('/products', function(data){
output.innerHTML = data
for(var keys in data){
console.log(data[keys]);
products.push(data[keys]);
output.innerHTML = data[keys].NAME;
}
// output.innerHTML = products;
//console.log(products)
});
I want each product to be rendered in it's own output div. How would I display each element in the HTML instead of just the last?
Just append the element to your output. Actually you did it.
Change this:
output.innerHTML = data[keys].NAME;
To this:
$('#output').append(`<div>${data[keys].NAME}</div>`);
So:
for(var keys in data){
console.log(data[keys]);
products.push(data[keys]);
$('#output').append(`<div>${data[keys].NAME}</div>`);
}
I would recommend you also to change the for...in with a simple forEach, so to change the loop into this:
data.forEach((el) => {
products.push(el);
$('#output').append(`<div>${el.NAME}</div>`);
});
The error in your code was just that you were overriding the HTML content of your element every time. If you change:
output.innerHTML = data[keys].NAME;
to this:
output.innerHTML += data[keys].NAME;
It should already work
You can use jQuery "append". You dont need to make product object.
Try like this:
for(var keys in data){
$(".productList").append( "<div>"+data[keys].NAME+"</div>" );
}
Basically, your output element should be a wrapper containing other elements repeated for each product. One semantic option is to use a list, such as ul + li.
You should iterate your products and append its piece of HTML to an array. When you are done processing them, you assign that chunk of HTML to the output element.
// Just to keep your code untouched:
const $ = {
getJSON(url, callback) {
callback([{
ID: 1,
NAME: 'Product 1',
PRICE: '2.50',
}, {
ID: 2,
NAME: 'Product 2',
PRICE: '1.25',
}, {
ID: 3,
NAME: 'Product 3',
PRICE: '10.00',
}]);
},
};
const output = document.getElementById('output');
let productsArray = [];
$.getJSON('/products', function(products){
productsArray = products;
output.innerHTML = products.map(product => {
return `<li data-id="${ product.ID }">
<span>${ product.NAME }</span>
<span>${ product.PRICE }</span>
</li>`;
}).join('');
});
<ul id="output"></ul>
$('#output').append(`<div>${data[keys].NAME}</div>`);
In reference to #VK321, you can also use the .map method.
data.map(element => {
$(".productList").append( `<div>${element.NAME}</div>` );
})

Handsontable editing nested array

I am using handsontable and am having trouble getting the "beforeChange" and "afterChange" events to fire consistently, which I'm hoping use to commit updates to the database. I am using the following code (version 0.16.1):
HTML:
<div id="table"></div>
<div id="output"></div>
JavaScript:
var data = [{
id: 5,
name: 'Sedan',
price: 2000,
tags: ['pink', 'purple']
}, {
id: 6,
name: 'Truck',
price: 1500,
tags: ['green', 'blue']
}, {
id: 6,
name: 'SUV',
price: 1500,
tags: null
}];
var writeMessage = function(msg) {
var output = document.getElementById("output");
var div = document.createElement('DIV');
div.innerHTML = msg;
output.insertBefore(div, output.firstChild);
console.log(msg);
};
var tableDiv = document.getElementById("table");
this.table = new Handsontable(tableDiv, {
data: data,
colHeaders: ["id", "name", "price", "tags"],
columns: [{
data: "id"
}, {
data: "name"
}, {
data: "price"
}, {
data: "tags"
}],
beforeChange: function(changes, source) {
writeMessage("beforeChange: " + changes + ": " + source);
},
afterChange: function(changes, source) {
writeMessage("After Change fired: " + changes);
if (!changes) {
return;
}
var i, idx, key, newVal, modelID;
for (i = 0; i < changes.length; i++) {
idx = changes[i][0];
key = changes[i][1];
newVal = changes[i][3];
modelID = this.getDataAtRow(idx)[0];
writeMessage("New value: " + key + ": " + newVal);
}
}
});
http://codepen.io/anon/pen/GjzrdX?editors=0010
The event handlers fire when I'm editing the text and number fields and for the when tags are null, but do not fire for data objects with tag arrays (e.g. pink,purple; green,blue). How do I get the events to fire for the tag cells without modifying the data structure? Any advice would be greatly appreciated!
I believe that you are facing a bug here when trying to put an Array in a Cell but I cannot find anywhere in the handsontable documentation or any thread in their GitHub mentioning this issue... IMO, putting an Array in a Cell is suppose to be use as Source and not Data, which result in a cell that you can't edit (hence the events afterChange/beforeChange not triggered). In your example the third line is working because of the 'null' value which is not an Array.
Anyway, the only workaround I managed to do for you is to modify your data after you define your data structure (in order to respect your condition, but I strongly advice do modify them anyway because you will need to do that eventually).
Assuming that your tags can only contain two values :
var data1 = [];
for (var i=0; i<data.length;i++) {
if (data[i].tags != null) {
var temp = data[i].tags[0];
temp = temp.concat(',');
temp = temp.concat(data[i].tags[1]);
} else var temp = null;
data1.push({ id: data[i].id, name: data[i].name, price: data[i].price, tags: temp });
}
If the length of your Arrays tags can be more than that, just do a second loop to cover it.
See your code here with this solution implemented
You then can use data1 to load your table. If you need to save your data after modification, you can use a similar function to reverse it into your original data structure.

drawing a table from a json structure coming as array using jquery or javascript

I am getting a JSON object. I have to print a tabular structure from that. After debugging , i have found the object is coming as
tableData = {title: "Schema", cellValues: Array[2], id: 1, name: "CSV", type: "table"}
When i do further debugging then i found following result
var tableRows = tableData.cellValues;
tableRows = [Array[4], Array[4]]
If i do a console.log(tableRows) it gives as --> c1,c2,c3,c4,DoubleType,DoubleType,DoubleType,DoubleType
I have to print it in a tabular form as
c1 count c1 count
DoubleType LongType DoubleType LongType
I am not able to understand how should i do that.How to manipulate this to get the table structure. Some help will be really appreciated. thanks..
I might try something like this. I've used three row of data including the heading data to broaden the demo.
var tableData = {
cellValues: [
['c1', 'c2', 'c3', 'c4'],
['DoubleType', 'longType', 'DoubleType', 'longType'],
['Bob', 'Dave', 'Bob', 'Dave']
]
}
Shift the first array in cellValues into headerData. bodyData is what remains.
var headerData = tableData.cellValues.shift();
var bodyData = tableData.cellValues;
Hashmap-based helper function that delivers lines of cells based on type.
function buildCells(data, type) {
return {
header: '<th>' + data.join('</th><th>') + '</th>',
row: '<td>' + data.join('</td><td>') + '</td>'
}[type];
}
Helper function that builds each data row.
function buildRow(data) {
return ['<tr>', buildCells(data, 'row'), '</tr>'].join('');
}
Build the set of row data.
var rows = bodyData.reduce(function(p, c) {
return p.concat(buildRow(c));
}, []);
Pad out the header, body, and finally, table with the appropriate tags
var header = ['<thead>', buildCells(headerData, 'header'), '</thead>'].join('');
var body = ['<tbody>', rows.join(''), '</tbody>'].join('');
var table = ['<table>', header, body, '</table>'].join('');
Now you can do what you like with the HTML. In the example I use insertAdjacentHTML to add it to an element.
DEMO

How to iterate an array of objects and print out one of its properties

I have the following code in a display template in sharepoint, I have an array of objects and I need to have the following result.
Name1
Name2
Name3
So I can replace the default rendering of sharepoint multiple people user field with a tooltip.
However, I dont know how to iterate and then concatenate:
Screenshot:
Code:
// List View - Substring Long String Sample
// Muawiyah Shannak , #MuShannak
(function () {
// Create object that have the context information about the field that we want to change it's output render
var projectTeamContext = {};
projectTeamContext.Templates = {};
projectTeamContext.Templates.Fields = {
// Apply the new rendering for Body field on list view
"Project_x0020_Team": { "View": ProjectTeamTemplate }
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(projectTeamContext);
})();
// This function provides the rendering logic
function ProjectTeamTemplate(ctx) {
var projectTeamValue = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];
//newBodyvalue should have the list of all display names and it will be rendered as a tooltip automaticlaly
return "<span title='" + projectTeamValue + "'>" + newBodyValue + "</span>";
}
You can "map" property values from the projectTeamValue array objects into a new array, then "join" those values together (using ", " as the separator in this example) all in one go:
var newBodyValue = projectTeamValue.map(function(person) {
return person.value;
}).join(", ");
If your projectTeamValue array looked like:
[{ value: "Name1" }, { value: "Name2" }, { value: "Name3" }]
Then newBodyValue would be:
"Name1, Name2, Name3"
jsFiddle Demo
Side note: Array.prototype.map() was not available in IE 8 and below but should work in every other browser.

Categories

Resources