How can I extract image id from an API in javascript? - javascript

So I have an app which uses Google Books API, and I have a div with image poster.
Thus i need to get image id from image url in Google API to change posters of books in these divs.
Javascript code:
const IMG_URL = "http://books.google.com/books/content?id="; //after "id=" I need to insert a particular image id
Function for showing books:
function showBooks(data){
data.forEach(book => {
const {title, authors, description} = book;
const bookEl = document.createElement('div');
bookEl.classList.add('book');
bookEl.innerHTML = `
<div class="border"></div>
<img src="${IMG_URL + }"> //here I should concatenate url with book id
<div class="book_info">
<h3>Book title</h3>
<p>Author</p>
</div>
<div class="overview">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris mi augue, ultricies vitae nisi vitae,
suscipit elementum risus. Suspendisse vitae porta tellus, a finibus lorem. </p>
</div>
`
});
}
What it looks like in the API:
"thumbnail": "http://books.google.com/books/content?id=WvfgAAAAMAAJ&printsec=frontcover&img=1&zoom=1&source=gbs_api"

I would construct a URL object and then extract the id parameter
const url = new URL(yourImageUrl)
const id = url.searchParams.get("id")
Read more about the URL class here: https://developer.mozilla.org/de/docs/Web/API/URL

Related

JS. How to Break selection/range into fragments per containing blocks and remove inline element formatting?

Lets say we have a div
<div id="my-div">
<p>Lorem ipsum dolor sit <strong>amet |consequat pharetra auctor </strong>condimentum lacus purus tortor habitasse molestie.</p>
<p>Auctor luctus lacus imperdiet <strong>pharetra| consequat</strong> egestas faucibus.</p>
</div>
And user selects a portion similar the one between "|".
function getSelectionPortion(){
const div = document.getElementById('my-div');
const selection = document.getSelection().getRangeAt(0).cloneContents(); // or extractContents();
return selection;
}
getSelectionPortion() will return the following:
<p><strong>consequat pharetra auctor </strong>condimentum lacus purus tortor habitasse molestie.</p>
<p>Auctor luctus lacus imperdiet <strong>pharetra</strong></p>
now we can get portions of the range by paragraphs, simply by e.g. fragment.querySelectorAll('p').
And if we extract the range contents and loop over each portion, we can take each strong inside each p and replace with its innerHTML
let blocks = getSelectionPortion().querySelectorAll('p');
for (let block of blocks){
let inlines = block.querySelectorAll('strong');
for (let inline of inlines){
inline.replaceWith(inline.innerHTML);
}
}
However, this outputs with additional paragraphs, because extracted fragment closes the paragraph tags. So we end up with
<div id="my-div">
<p>Lorem ipsum dolor sit <strong>amet</strong></p>
<p>consequat pharetra auctor condimentum lacus purus tortor habitasse molestie.</p>
<p>Auctor luctus lacus imperdiet pharetra</p>
<p><strong>consequat</strong> egestas faucibus.</p>
</div>
How do you remove the inline tag from the selection without creating additional block level elements with fragment? Is there a way to divide the range into peaces instead of its extract?

How to query for the content inside a h3 tag

I am using the following jQuery code to try to get the text inside the element and add it to my variable:
<script>
var title = $('h3').html();
alert(title);
</script>
However, my browser is alerting me 'undefined' instead of the value inside the tag. Any idea what I am doing wrong?
Here is the html section for reference:
<article>
<div class="row">
<div class="columns large-6 large-centered medium-8 medium-centered small-12">
<h3>This is the post title</h3>
<h4>written by <b>Myself</b></h4>
<section>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla lacinia urna sit amet convallis dictum. Curabitur non sodales orci. Praesent vel gravida felis. Cras ultricies velit mi, eget efficitur ipsum tempus nec.</p>
</section>
</div>
</div>
</article>
Thanks,
This is the solution using plain JavaScript; you don't actually need jQuery here.
var h3element = document.getElementsByTagName("h3")[0];
This returns an array of all h3 elements in the document, of which you'll take the 0th index. Then, simply access the innerHTML property:
var h3content = h3element.innerHTML;
A complete solution would look something like:
<script>
var title = document.getElementsByTagName("h3")[0].innerHTML;
alert(title);
</script>
Try to wait for your document to trigger the ready event, if your code is beyond your tag, for example in the header. And if you only need the text, use the text function in jQuery.
<script>
$(function() {
var title = $('h3').text();
alert(title);
});
</script>
Do something like:
alert(document.getElementsByTagName('h3')[0].innerHTML)

Multiple event handlers only firing on first element, not the target

So I am trying to make a more/less content toggle feature, it worked just fine until I started adding more boxes to be toggled. I read up on using multiple event handlers and the suggestion was to use document.getElementsByClassName(); and iterate through them, but the second button when clicked does not show/hide the correct content, only the first one.
Any help is appreciated. The simpler way would be to use jQuery or assign different IDs to the buttons and call the function on each one but I'm sure it must be possible to just create/call the event listener once and have it work on every subsequently added element.
Here is my code:
HTML
<div class="card">
<div class="cardLessContent">
<h1>Here is a card</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent auctor mi sollicitudin, tristique tortor eget, tempus elit. Vestibulum ante leo, aliquam ac dapibus at, auctor vitae ligula.</p>
</div>
<div id="cardMoreContent" class="cardMoreContent">
<p> Nam finibus nec augue at semper. Quisque sit amet ex eu augue rutrum aliquet. Suspendisse dui enim, gravida quis turpis a, auctor pellentesque velit.</p>
</div>
<button id="toggleContent" class="toggleContent toggledOff">More</button>
</div>
<div class="card">
<div class="cardLessContent">
<h1>Here is a card</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent auctor mi sollicitudin, tristique tortor eget, tempus elit. Vestibulum ante leo, aliquam ac dapibus at, auctor vitae ligula.</p>
</div>
<div id="cardMoreContent" class="cardMoreContent">
<p> Nam finibus nec augue at semper. Quisque sit amet ex eu augue rutrum aliquet. Suspendisse dui enim, gravida quis turpis a, auctor pellentesque velit.</p>
</div>
<button id="toggleContent" class="toggleContent toggledOff">More</button>
</div>
JavaScript
const btnToggleContent = document.getElementsByClassName("toggleContent");
const cardMoreContent = document.getElementById("cardMoreContent");
var toggleContent = function() {
cardMoreContent.classList.toggle("showing");
this.classList.toggle("toggledOff");
if(this.classList.contains("toggledOff")) {
this.innerHTML = "More";
}
else {
this.innerHTML = "Less";
}
}
for (var i = 0; i < btnToggleContent.length; i++) {
btnToggleContent[i].addEventListener("click", toggleContent);
}
JSFiddle: https://jsfiddle.net/jw3qe9xf/6/
Id attribute should be unique in HTML.Otherwise it will only pick the first occurence of that Id.In your case you will always toggle the first cardMoreContent
Here is a simple solution for you by using event.target
Javascript
const btnToggleContent = document.getElementsByClassName("toggleContent");
const cardMoreContent = document.getElementById("cardMoreContent");
var toggleContent = function(e) {
e.target.previousElementSibling.classList.toggle("showing");
this.classList.toggle("toggledOff");
if(this.classList.contains("toggledOff")) {
this.innerHTML = "More";
}
else {
this.innerHTML = "Less";
}
}
for (var i = 0; i < btnToggleContent.length; i++) {
btnToggleContent[i].addEventListener("click", toggleContent);
}
JSFiddle : https://jsfiddle.net/c1gdjk25/
Yes , works only for first. This is reason :
you have multiply use ' id="toggleContent" ' same id value for more than one element it is wrong in basic.
Id attribute must be uniq !
Use example from this answer :
How to get child element by class name?
You will need only childNodes and loop trow it.
Count on that you can search child from child element also ...
after you remove all ids attributes change your javascript code to :
const btnToggleContent = document.getElementsByClassName("toggleContent");
var toggleContent = function(e) {
/*e.target will get the clicked element which is the button clicked and parentElement
gives you the parent element of this button which is the card you want to modify*/
var card = e.target.parentElement;
/*when you have the card you can use on its getElementsByClassName to retreive all
elements that have the class (cardMoreContent) in this case theres only one so you take
the first element from the array returned with [0]*/
var cardMoreContent = card.getElementsByClassName("cardMoreContent")[0];
//then rest of the code stays the same
cardMoreContent.classList.toggle("showing");
if(this.classList.contains("toggledOff")) {
this.innerHTML = "More";
}
else {
this.innerHTML = "Less";
}
}
for (var i = 0; i < btnToggleContent.length; i++) {
btnToggleContent[i].addEventListener("click", toggleContent);
}

Can you 'customize' non built-in elements?

In the MDN documentation for using custom elements, they detail an example for customizing built-in elements:
customElements.define('expanding-list', ExpandingList, { extends: "ul" });
Allowing this usage:
<ul is="expanding-list">
...
</ul>
I am wondering if it is possible to customize another custom element in the same way? For example, if I have created an element called custom-element, and I want to have variants of it, I might want to create a new special-custom-element class, and define it in the same way, so as to be able to use it like so:
<custom-element is="special-custom-element">
...
</custom-element>
However, I am prompted with an error stating:
Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': "custom-element" is a valid custom element name
When attempting to run the following:
customElements.define('special-custom-element', SpecialCustomElement, { extends: 'custom-element' });
Is this something I am doing wrong, or is this behaviour strictly limited to built-in elements? I'm finding it rather difficult to find any information about this behaviour other than what is on the page I linked to, so I was hoping for some advice from someone who knows the specs better.
You can not do it in the sense that you want since:
There are two types of custom elements you can create:
Autonomous custom element: Standalone elements; they don't inherit from built-in HTML elements.
Customized built-in element: These elements inherit from — and extend — built-in HTML elements.
customElements.define('word-count2', WordCount2, {extends: 'p'});
Is for extending the built-in elements.
You have to go the Autonomous custom element route as per the docs
Here is an idea:
// Create a class for the element
class MyElement extends HTMLElement {
constructor(text) {
// Always call super first in constructor
super();
// Create a shadow root
var shadow = this.attachShadow({
mode: 'open'
});
// Create the span
var wrapper = document.createElement('span');
wrapper.textContent = !!text ? text : 'foo';
shadow.appendChild(wrapper);
}
}
class MyElement2 extends MyElement {
constructor() {
// Always call super first in constructor
super('bar');
}
}
// Define the new element
customElements.define('my-element', MyElement);
customElements.define('my-element2', MyElement2);
<div>
<my-element text="">
</div>
<div>
<my-element2 text="">
</div>
Now you still could extend your class (and do customization of a build-in element) and access the output of the super so that might be useful to you and to some extend might allow you to get what you need:
// Create a class for the element
class WordCount extends HTMLParagraphElement {
constructor() {
// Always call super first in constructor
super();
// count words in element's parent element
const wcParent = this.parentNode;
function countWords(node) {
const text = node.innerText || node.textContent;
return text.split(/\s+/g).length;
}
const count = `Words: ${countWords(wcParent)}`;
// Create a shadow root
const shadow = this.attachShadow({
mode: 'open'
});
// Create text node and add word count to it
const text = document.createElement('span');
text.textContent = count;
// Append it to the shadow root
shadow.appendChild(text);
// Update count when element content changes
text.textContent = count;
}
}
class WordCount2 extends WordCount {
constructor() {
// Always call super first in constructor
super();
console.log(this.shadowRoot.textContent)
}
}
// Define the new element
customElements.define('word-count', WordCount, {
extends: 'p'
});
customElements.define('word-count2', WordCount2, {
extends: 'p'
});
<div>
<h2>Sample heading</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc pulvinar sed justo sed viverra. Aliquam ac scelerisque tellus. Vivamus porttitor nunc vel nibh rutrum hendrerit. Donec viverra vestibulum pretium. Mauris at eros vitae ante pellentesque bibendum.
Etiam et blandit purus, nec aliquam libero. Etiam leo felis, pulvinar et diam id, sagittis pulvinar diam. Nunc pellentesque rutrum sapien, sed faucibus urna sodales in. Sed tortor nisl, egestas nec egestas luctus, faucibus vitae purus. Ut elit nunc,
pretium eget fermentum id, accumsan et velit. Sed mattis velit diam, a elementum nunc facilisis sit amet.</p>
<p is="word-count"></p>
</div>
<div>
<h3>Sample heading</h3>
<p>Lorem ipsum dolor sit amet, consec Sed tortor nisl, egestas nec egestas luctus, faucibus vitae purus. Ut elit nunc, pretium eget fermentum id, accumsan et velit. Sed mattis velit diam, a elementum nunc facilisis sit amet.</p>
<p is="word-count2"></p>
</div>
You can also do this
class SpecialCustomElement extends CustomElement
{
...
}
customElements.define('special-custom-element', SpecialCustomElement, { extends: 'ul' });
and can use it as
...

Adding View Details Button with JS

I'm trying to add a view details button to each product using JS. I want it to look for each instance of the class "clsItemBlock" and then append the html inside of clsItemPublished" The code below is adding multiple buttons on the first product, instead of one one each.
In a PERFECT world, since I know there are only 15 products per page, I could have it only check 15 times to prevent it from looping constantly.
MY JS:
var divs = document.getElementsByClassName('clsItemBlock');
for (var i = 0; i < divs.length; i++)
{
var iDiv = document.createElement('div');
iDiv.id = 'detail_button';
document.getElementsByClassName('clsItemPublished')[0].appendChild(iDiv);
iDiv.innerHTML = 'View Details';
}
FIDDLE:
http://jsfiddle.net/ptc6ws9o/1/
Or, if it is appropriate you can just use details and summary tags: http://jsfiddle.net/dorgLr71/
<details>
<summary>View Details</summary>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin
dapibus porttitor libero, eget rutrum nibh laoreet et.
Pellentesque porttitor erat ligula, id elementum est egestas
eget. Mauris gravida dui ut leo tempor, nec placerat tortor
hendrerit.
</p>
</details>
GOT IT!
var divs = document.getElementsByClassName('clsItemBlock');
for (var i = 0; i < divs.length; i++)
{
var iDiv = document.createElement('div');
iDiv.id = 'detail_button';
document.getElementsByClassName('clsItemPublished')[i].appendChild(iDiv);
iDiv.innerHTML = 'View Details';
}

Categories

Resources