Read JSON and implement it in HTML - javascript

First of all, sorry for my bad English, isn't the best ;)
So I'm new to working with JavaScript, Ajax and, jQuery. Since a young age I've been interested in coding. A friend of mine wants an update on their website I made for them a little while ago. They have a small podcast/radio station.
What I'm trying to do is make an automatic link between the podcasts they post on MixCloud and their website. I followed some tutorials and grave throw the forms on this website, but I can't get the script to work properly and get the information out of the JSON file that MixCloud makes with their API.
This is what I've got so far. I can't figure out what I'm doing wrong since I'm very very new to this. I tried different methods, but this is the closest I've got.
const Http = new XMLHttpRequest();
const url = 'https://api.mixcloud.com/itmotr-radio/cloudcasts/';
Http.open("GET", url);
Http.send();
Http.onreadystatechange = (e) => {
console.log(Http.responseText)
}
function append_json(XMLHttpRequest) {
//Set Up the template
var s = $("#postTemplate")[0].innerHTML.trim();
var holder = document.createElement('div');
holder.innerHTML = s;
var template = holder.childNodes;
var episode = document.getElementById('episodes');
Object.keys(XMLHttpRequest).forEach(function(object) {
//Clone Template
var newEpisode = $(template).clone();
//Populate it
$(newEpisode).find(".data.name").html(object.episodetitle);
var img = $(newItem).find(".data.pictures.320wx320h")
$(img).attr("src", object.coverimg)
//Append it
$(".episodes").append(newEpisode);
});
}
$("document").ready(function() {
append_json(XMLHttpRequest);
});
.episodes {
background: white;
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fit, minmax(320px, 380px));
grid-auto-rows: 370px;
grid-auto-flow: dense;
justify-content: center;
padding-top: 10px;
}
.episode {
background: rgb(255, 255, 255);
border: 1px solid grey;
text-align: center;
}
.episodetitle {
font-size: 20px;
color: red
}
.coverimg {
width: 320px;
max-height: 320px
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="episodes">
<script type="text/template" id="postTemplate">
<div class="episode">
<img class="coverimg" src="">
<p class="episodetitle"></p>
</div>
</script>
</div>
For some reason, I can't get the data out of the JSON file and it won't show in the HTML. I built this script with a lot of help from this article: Populate grid <div> & <p> with JSON data file
Can someone help me out and get it working with me?
The JSON file that needs to be read is:
https://api.mixcloud.com/itmotr-radio/cloudcasts/

There's a few things going on so I will address each individually, and you can put them together as the learning :) Your general structure is OK though, nice going so far!
jquery
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js">/script>
this is an old version, use
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
AJAX
const Http = new XMLHttpRequest();
const url='https://api.mixcloud.com/itmotr-radio/cloudcasts/';
Http.open("GET", url);
Http.send();
Http.onreadystatechange=(e)=>{
console.log(Http.responseText)
}
This is all taken care of within jquery automatically. Have a read of the AJAX documentation. This is a good example to learn with, it's quite simple (lots of defaults you can use).
$.ajax({
url:'https://api.mixcloud.com/itmotr-radio/cloudcasts/',
success:function(data){
//Do stuff with the data here (as JSON, it should be auto parsed into an object)
//for example (psuedo code..)
for(var i = 0; i < data.length;i++){
//Use the data variable passed in with the success function.
createNewElement(data[i]) // do something with each object in the array (see below)
}
})
Create new element
var newEpisode = $(template).clone();
//Populate it
$(newItem).find(".data.name").html(object.episodetitle);
var img = $(newItem).find(".data.pictures.320wx320h")
$(img).attr("src", object.coverimg)
//Append it
$(".episodes").append(newEpisode);
As you have jquery already we can use a lot of the functions easily. The element to append we can build in jquery, or just use a string in javascript containing your HTML. As you are adding in dynamic data, it makes sense to make the elements.
createNewElement(datum){
// This function creates a new element each time it is called and appends it to the
let $para = $('<p></p>') // make new <p> element
.addClass('episodetitle') // add the class property and actual classes
.text(thing.episodetitle) // set the text content of the element
//we have created "<p class='episodetitle'>This is the Title</p>"
//Alernatively we can do it all in one go
let $img = $('<img class="coverimg" src="'+datum.imagesource+'"/>')
// Now we create the container div for these 2 elements
let $newEpisode = $('<div></div>').addClass('episode')
$newEpisode.append($para) // Add the para into our div
.append($img) // append the image element into the div
$(".episodes").append($newEpisode); // append the div to the coagulate div
}

#Tobin
So now I edited my script to this:
$.ajax({
url:'https://api.mixcloud.com/itmotr-radio/cloudcasts/',
success:function(data){
//Do stuff with the data here (as JSON, it should be auto parsed into an object)
var newEpisode = $(template).clone();
//Populate it
$(newItem).find(".data.name").html(object.episodetitle);
var img = $(newItem).find(".data.pictures.320wx320h")
$(img).attr("src", object.coverimg)
let $para = $('<p></p>').addClass('episodetitle').text(thing.episodetitle)
let $newEpisode = $('<div></div>').addClass('episode')
$newEpisode.append($para)
// GETTING A ERROR :28 Uncaught SyntaxError: Identifier '$para' has already been declared. When trying to do the same for the coverimg.
let $para = $('<p></p>').addClass('coverimg').text(thing.coverimg)
let $newEpisode = $('<div></div>').addClass('coverimg')
$newEpisode.append($para)
//Append it
$(".episodes").append(newEpisode);
}
})
But now de second $para gives me an error because it's already declared...
But I made one change in the first script, changed a 'newItem' to 'newEpisode' and now it renders my layout, but none of the information in the JSON file is loaded in. And it makes 5 items, while there are supposed to be 2 'files' in the JSON file. What goes wrong here?

Related

JQuery append image not showing

For this code block
$(document).ready(() => {
for (let i = 0; i < 10; i++) {
$("#main").append(factory());
}
});
this will show the image:
function factory() {
return $('<image class="champ-icon rounded-circle" src="resources/irelia.jpg" />');
}
while this doesn't
function factory() {
let $champIcon = $(document.createElement("image"))
.addClass("champ-icon rounded-circle")
.attr("src", "resources/irelia.jpg");
return $champIcon;
}
I'm using Bootstrap 4 as well.
The page currently is just a static mock up. I want to dynamically build elements from data given to it by a local server.
I literally just messed around with HTML/CSS and jQuery over the weekend so I'm not sure what went wrong here. Shouldn't both function return the same jQuery object?
Thanks!
CSS class
.champ-icon {
width: 100px;
height: 100px;
}
Edit: creating it with normal javascript works as well.
function factory() {
let img = new Image();
img.src = "resources/irelia.jpg";
img.className = "champ-icon rounded-circle";
return img;
That's because you are trying to programmatically create <image> element in html, which... doesn't exist. To insert element on a page you should use <img src="">, not <image...>. Change this line
let $champIcon = $(document.createElement("image"))
to
let $champIcon = $(document.createElement("img"))
And it should work.

how to make fast loading of 1000 divs

I am developing an Adobe CEP panel for Adobe software, and when this "fetch" files from a computer (synchrony), it shows them as list of divs.
The idea is to create a List View that represents the files as a header (h2) in every file of the computer. However, when there are 400 files and more, it becomes very lagging, and after maybe 30 seconds, the whole divs are loaded.
The CEP panel is an HTML file that runs on chromium browser.
Is there any way to make it faster? maybe the idea of creating element in a loop over the files is not efficient?
Just to enlighten those who doesn't familiar with Adobe CEP, the cool idea of the CEP that it actually runs on a different thread of the Adobe software, thus this does not stuck the user from continuing using the software tools...
Any ideas will be useful for me.
here is my code of creating the elements:
filesArray.forEach( element => {
var fileName = element.slice(0,element.length-4)
var fileID = makeFileid();
var div = document.createElement("div");
div.setAttribute("style", "border-bottom: 1px solid #9B9B9B")
div.setAttribute("class", "fonts");
div.classList.add("row");
var div2 = document.createElement("div");
div2.classList.add("column");
var h3 = document.createElement("h3")
h3.setAttribute("class" , "h3");
var h2 = document.createElement("h2");
h2.setAttribute("style" , "margin-right: 10px; font-size: 20px");
h2.setAttribute('id', element)
h2.setAttribute("onclick", "sayWho(this)")
div.appendChild(div2);
div2.appendChild(h3)
div2.appendChild(h2);
fontDiv.appendChild(div);
h3.innerText = fileName;
h2.innerText = 'The files of the computer';
var newStyle = document.createElement('style');
newStyle.appendChild(document.createTextNode('\
#font-face {\
font-family:"Ariel";\
));
document.head.appendChild(newStyle);
});
Thanks,
In my experience, this should be faster than manually creating every single element:
especially if the markup gets to a significant size.
fontDiv.innerHTML = `<style>
#font-face {
font-family: "Ariel";
}
</style>
${filesArray.map(element => {
var fileName = element.slice(0, element.length - 4);
var fileID = makeFileid();
return `<div class="fonts row"
style="border-bottom: 1px solid #9B9B9B">
<div class="column">
<h3 class="h3">${fileName}</h3>
<h2 id="${element}"
style="margin-right: 10px; font-size: 20px"
onclick="sayWho(this)">
The files of the computer
</h2>
</div>
</div>`
}).join("\n")}`
If this doesn't help, you can
a) break the list down into smaller chunks and add them with a small delay in between.
b) check out list virtualization
You can try by using map and that will create an array of html elements. Once the array is formed then use join with comma delimiter.
At the end append all the child once in the head , so you will not access dom multiple time , since accessing dom is a costly process

Javascript – PNG not showing when adding dynamically

I’m a beginner JS coder and I’m struggling with the following – can anyone please help?
I’m trying to add a series of PNGs to a page using a function which will allow the placement of multiple copies of the same image and also assign a unique reference to each copy of the image.
The images are not showing in the page, plus the console.log() shows that the 2 images created by the code below both have the same position on the page.
var imgSrc = 'arrow_red.png';
function generateArrow(numArrows) {
var img = document.createElement('img');
img.src = imgSrc;
for (i = 1; i <= numArrows; i++) {
window['arrow'+i] = img;
}
}
generateArrow(2);
arrow1.style.position = 'absolute';
arrow1.style.top = '50px';
arrow1.style.left = '50px';
arrow2.style.position = 'absolute';
arrow2.style.top = '100px';
arrow2.style.left = '100px';
console.log(arrow1);
console.log(arrow2);
Why are the images not showing in the page and why does the console.log() show that the 2 images created are both using the same positional co-ordinates?
When you create a new element, it only exists in memory - - it hasn't been added to the document that the browser is currently rendering. So, it's not enough to create new elements and configure them. You must then inject them into the DOM with parentElement.appendChild(newChild).
Here's an example:
let newChild = document.createElement("img");
newChild.src = "https://static.scientificamerican.com/sciam/cache/file/D14B1C22-04F8-4FB4-95937D13A0B76545.jpg?w=590&h=393";
let parent = document.querySelector(".parent");
parent.appendChild(newChild); // <-- Now, inject the new element
img { width: 400px; }
<div class="parent"></div>
Now, in your particular case, you've got more issues than just this to work on. You are only creating a new image element one time because your line that does that is not inside of your loop. Also, the way you are referring to arrow1 and arrow2 in your code and with window['arrow' + i] indicates that you have img elements with ids already set up in your HTML, which is not an ideal approach. Next, it's much simpler to set up the CSS you'll want to work with as pre-made classes ahead of time, rather than setting up the CSS as inline styles in the script.
As my answer above indicates, you need to have a parent element that will contain the new element(s) that you create, so your solution would really look something like this:
var imgSrc = 'https://icon2.kisspng.com/20180320/rle/kisspng-arrow-computer-icons-clip-art-red-arrow-line-png-5ab19d059bfa98.5843437015215895096389.jpg';
// You can pick any pre-existing element to be the "parent"
var parent = document.getElementById("parent");
function generateArrow(numArrows) {
for (i = 1; i <= numArrows; i++) {
// The creation of the elementt and it's configuration
// need to be inside of the loop to make several of them
var img = document.createElement('img');
img.classList.add("position" + i); // Add pre-made CSS classes
img.src = imgSrc;
parent.appendChild(img); // Inject the new element inside of the parent
}
}
generateArrow(5);
/*
Instead of setting inline styles, use pre-made CSS classes
that you can just connect or disconnect to/from
*/
/* All the injected images get this: */
#parent > img { width:40px; position:absolute; }
/* These get assigned individually */
.position1 { top:50px; left:50px; }
.position2 { top:100px; left:100px; }
.position3 { top:150px; left:150px; }
.position4 { top:200px; left:200px; }
.position5 { top:250px; left:250px; }
<div id="parent"></div>
You usually add elements to DOM using document.appendChild(element);, or in your case: document.appendChild(img);. (Or any preferred parent instead of document)
Edit: removed second part addressing variable declaration, since I didn't notice the window["arrow" + i] = img.
You need to add the generated element to the DOM using the appendChild() method.
Furhermore you're actually just generating a single instance of the image because it's happening once outside of the for-loop. This is why the console shows identical screen positions for 'both' images because actually you're referring to the same image instance.
Try this:
function generateArrow(numArrows) {
var img;
for (i = 1; i <= numArrows; i++) {
img = document.createElement('img');
img.src = imgSrc;
document.body.appendChild(img);
window['arrow' + i] = img;
}
}

How to print only a selected HTML element?

I am trying to implement a print feature in HTML. I know I can print the whole page with window.print(), but how do I print only a specific page element? For example a particular <DIV>Some text to print</DIV>.
You could use a print specific CSS stylesheet and hide everything but what you want printed.
<div class="no-print">I won't print</div><div class="something-else">I will!</div>
Just the no-print class will be hidden, but anything with a print class will show.
<style type="text/css" media="print">
.no-print { display: none; }
</style>
If you are familiar to jQuery, you can use jQuery Print Element plugin like this:
$('SelectorToPrint').printElement();
Created something generic to use on any HTML element
HTMLElement.prototype.printMe = printMe;
function printMe(query){
var myframe = document.createElement('IFRAME');
myframe.domain = document.domain;
myframe.style.position = "absolute";
myframe.style.top = "-10000px";
document.body.appendChild(myframe);
myframe.contentDocument.write(this.innerHTML) ;
setTimeout(function(){
myframe.focus();
myframe.contentWindow.print();
myframe.parentNode.removeChild(myframe) ;// remove frame
},3000); // wait for images to load inside iframe
window.focus();
}
Usage:
document.getElementById('xyz').printMe();
document.getElementsByClassName('xyz')[0].printMe();
Hope this help
Regards
Gaurav Khurana
Simple html and pure javascript works best. Parameter "this" refers to current id, so that function is universal for all ids. By using "ref.textContent" instead of "ref.innerHTML" you can extract only textual content for printing.
html body:
<div id="monitor" onclick="idElementPrint(this)">element to print
<img src="example.jpg" width="200">
</div>
pure javascript:
/*or:
monitor.textContent = "click me to print content";
const imga = new Image(200); //width
imga.src = "./example.jpg";
monitor.appendChild(imga);
*/
const idElementPrint = ref => {
const iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
const pri = iframe.contentWindow;
pri.document.open();
pri.document.write(ref.innerHTML);
pri.document.close();
pri.focus();
pri.print();
pri.onafterprint = () => { document.body.removeChild(iframe); }
}
If you are using JQuery, you can use clone to do the following:
function printElement(e) {
var ifr = document.createElement('iframe');
ifr.style='height: 0px; width: 0px; position: absolute'
document.body.appendChild(ifr);
$(e).clone().appendTo(ifr.contentDocument.body);
ifr.contentWindow.print();
ifr.parentElement.removeChild(ifr);
}
and use like so:
printElement(document.getElementById('myElementToPrint'))
If I understood you well you can use CSS3 to print your selected HTML element.
#media print {
body.print-element *:not(.print) {
display: none;
}
}
Notice, that you just need a selector. This allows you to easily print an element or the entire page using CSS classes.
Here you can check a working example: https://jsfiddle.net/gengns/d50m8ztu/
If you're using bootstrap, just add classname d-print-none to the elements you don't want to display in print
I found a solution that doesn't have the problems other solutions have. It copies the printed element to the body, and is fairly elegant and general:
CSS:
#media print {
body *:not(.printable, .printable *) {
// hide everything but printable elements and their children
display: none;
}
}
JS:
function printElement(e) {
let cloned = e.cloneNode(true);
document.body.appendChild(cloned);
cloned.classList.add("printable");
window.print();
document.body.removeChild(cloned);
}
The only limitation is that the element loses styles it inherited from its previous parents. But it works on arbitrary elements in the document structure
If you need to print the HTML element with pure JS, you can open a window that contains only the element you want to print (without any HTML-markup).
For instance, you can print the image itself without wrapping it in any HTML by opening this image in a new window as a file.
Note: 'visible=none' doesn't actually make the window invisible, but it allows to open it as a separate window (not a tab).
afterprint event allows us to close the window when the printing dialog is closed. event.target points to the opened window instance.
Note: afterprint MUST be assigned before calling .print(), otherwise it would not be called.
let win = window.open('/absolute/image/path.jpg', '__blank', 'visible=none');
win.addEventListener('afterprint', event => event.target.close() );
win.print();
Printing an Html or a Selected Html is easy using Print.Js
Add Print.Js Library
http://printjs.crabbly.com/
<form method="post" action="#" id="printJS-form">
...
</form>
<button type="button" onclick="printJS('printJS-form', 'html')">
Print Form
</button>
Add this method
function printDiv(divName) {
let specific_element = document.getElementById(divName).innerHTML;
let original_elements = document.body.innerHTML;
document.body.innerHTML = specific_element;
window.print();
document.body.innerHTML = original_elements;
}
This implementation will create and apply an ad-hoc temporary style that hides all the elements on print media except the one that we want to print. After the printing the temporary style is removed, so your document will get back to its initial state.
Feel free to adjust the ad-hoc style (like papar size, margins, etc) to fit your needs.
/**
* #description Print the given element using browser built-in function
* #param {HTMLElement} element
*/
function printElement(element) {
if (!element) {
throw new Error(`Invalid print target element`);
}
const printWrapper = "print-wrapper";
const printElement = "print-element";
const css = `
body.${printWrapper} *:not(.${printElement}) {
visibility:hidden;
}
body.${printWrapper} .${printElement} {
width: 210mm;
height: 297mm;
left:0;
top:0;
position:fixed;
}
body.${printWrapper} .${printElement} * {
visibility:initial;
margin: 0;
}
`;
const head = document.getElementsByTagName("head")[0];
const style = document.createElement("style");
style.setAttribute("type", "text/css");
style.setAttribute("media", "print");
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
document.body.classList.add(printWrapper);
element.classList.add(printElement);
window.print();
document.body.classList.remove(printWrapper);
element.classList.remove(printElement);
head.removeChild(style);
}
The simplest way to do it is:
elem = document.getElementById('elem').outerHTML
orig = document.documentElement.outerHTML
document.documentElement.outerHTML=elem
print()
document.documentElement.outerHTML = orig
function printDomElement(element) {
element.classList.add("printCss");
let printId = "printSvgId";
let name = ".printCss";
let rules = "-webkit-print-color-adjust:exact;height:100%;width:100%;position:fixed;top:0;left:0;margin:0;";
var style = document.createElement('style');
style.id = printId;
style.media = "print";
document.getElementsByTagName('head')[0].appendChild(style);
if (!(style.sheet || {}).insertRule)(style.styleSheet || style.sheet).addRule(name, rules);
else style.sheet.insertRule(name + "{" + rules + "}", 0);
window.print();
setTimeout(() => {
element.classList.remove("printCss");
let elem = document.getElementById(printId);
if (elem) elem.remove();
}, 500);
}
Set the style of the element you want to print to position:fixed,then make it cover the whole page.
Here is another (perhaps a more modern?) solution:
<link rel="stylesheet" media="print" href="print.css">

Google Feed API

I'm having trouble getting Google's load feed to work. Example is supposed to be at www.eslangel.com
I put this code in the header
<script type="text/javascript"
src="https://www.google.com/jsapi?key=ABQIAAAAO2BkRpn5CP_ch4HtkkOcrhQRKBUhIk5KoCHRT6uc9AuUs_-7BhRyoJdFuwAeeqxoUV6mD6bRDZLjSw">
</script>
And then, just to test, I copied and pasted their sample code using a Digg feed into the body of my blog, but there's no result of any kind.
Does anyone have any idea what I might be doing wrong?
/*
* How to load a feed via the Feeds API.
*/
google.load("feeds", "1");
// Our callback function, for when a feed is loaded.
function feedLoaded(result) {
if (!result.error) {
// Grab the container we will put the results into
var container = document.getElementById("content");
container.innerHTML = '';
// Loop through the feeds, putting the titles onto the page.
// Check out the result object for a list of properties returned in each entry.
// http://code.google.com/apis/ajaxfeeds/documentation/reference.html#JSON
for (var i = 0; i < result.feed.entries.length; i++) {
var entry = result.feed.entries[i];
var div = document.createElement("div");
div.appendChild(document.createTextNode(entry.title));
container.appendChild(div);
}
}
}
function OnLoad() {
// Create a feed instance that will grab Digg's feed.
var feed = new google.feeds.Feed("http://www.digg.com/rss/index.xml");
// Calling load sends the request off. It requires a callback function.
feed.load(feedLoaded);
}
google.setOnLoadCallback(OnLoad);​
Well, did you also create a container for the feed? :-)
Try placing
<div id="content"></div>
before the feed loading script.

Categories

Resources