Javascript: Iterate through ID -> cannot set property 'onclick' of null javascript - javascript

I'm trying to code a modal with a slideshow. It works fine for the first picture when I type '1' instead of 'i' in the for loop. When I use 'i' in the for loop I get the error message "cannot set property 'onclick' of null javascript"
I know that this is some very beginner stuff... but I'm sitting here now for hours to find a solution...
Thank you for your help!
window.onload = function() {
var modal;
var prefixModal = 'myModal';
var img;
var prefixmyImg = 'myImg';
var modalImg;
var prefixmodalImg = 'img';
for (var i = 0; i <= 6; i++) {
modal = document.getElementById(prefixModal + i);
img = document.getElementById(prefixmyImg + i);
modalImg = document.getElementById(prefixmodalImg + i);
}
var closey = document.getElementsByClassName('close');
img.onclick = function(){
modal.style.display = "block";
modalImg.src = this.src;
}
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
};
.container_slideshow {
white-space: nowrap;
overflow-y: hidden;
overflow-x: scroll;
display: block;
height: 8rem;
margin-top: 1rem;
min-width: 100%;
}
.content_slideshow {
display: inline-block;
height: 100%;
width: 40vw;
background-color: darkgray;
margin-left: 0;
margin-right: .5rem;
}
.content_slideshow:last-child {
margin: 0;
}
}
/* Style the Image Used to Trigger the Modal */
#myImg {
border-radius: 5px;
cursor: pointer;
transition: 0.3s;
}
#myImg:hover {opacity: 0.7;}
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 50%; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: scroll; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(57,61,69,0.6); /* Black w/ opacity */
}
/* Modal Content (Image) */
.modal-content {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
}
/* Caption of Modal Image (Image Text) - Same Width as the Image */
#caption {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
text-align: center;
color: #ccc;
padding: 10px 0;
height: 150px;
}
/* Add Animation - Zoom in the Modal */
.modal-content, #caption {
animation-name: zoom;
animation-duration: 0.6s;
}
#keyframes zoom {
from {transform:scale(0)}
to {transform:scale(1)}
}
/* The Close Button */
.close2 {
display: none;
position: absolute;
color: #f1f1f1;
transition: 0.3s;
width: 100%;
height: 100%;
}
.close:hover,
.close:focus {
color: #bbb;
text-decoration: none;
cursor: pointer;
}
HTML:
<div class="container_slideshow">
<div class="content_slideshow">
<!-- Trigger the Modal -->
<img class="slider" id="myImg1" src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/SilburyHill_gobeirne.jpg/1200px-SilburyHill_gobeirne.jpg" alt="">
<!-- The Modal -->
<a class="close">
<div id="myModal1" class="modal">
<!-- Modal Content (The Image) -->
<img class="modal-content" id="img1">
<!-- Modal Caption (Image Text) -->
<div id="caption"></div>
</div>
</a>
</div>
<div class="content_slideshow">
<!-- Trigger the Modal -->
<img class="slider" id="myImg2" src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/SilburyHill_gobeirne.jpg/1200px-SilburyHill_gobeirne.jpg" alt="">
<!-- The Modal -->
<a class="close">
<div id="myModal2" class="modal">
<!-- Modal Content (The Image) -->
<img class="modal-content" id="img2">
<!-- Modal Caption (Image Text) -->
<div id="caption"></div>
</div>
</a>
</div>
</div>

The reason is for (var i = 0; i <= 6; i++) {. The count starts from 0 and it will try to find a dom element with id myModal6.
Change the for loop to
for (var i = 0; i < 6; i++) {

After a very rough look I'd say the DOM node with id "myModal0" doesn't exist (which is most likely true for your other prefixes as well it just happens to be the first you try to get the DOM node of.
Keep in mind that your loop starts at 0 not 1.
Also keep in mind that each node you are trying to assign must exist beforehand! So you either have to have each element in your html file or create them on the fly with JS.
If you wanted to start at 1 you could do:
for (let i=1; i<x; i++) {
// do smth ...
}

It looks like this code:
for (var i = 0; i <= 6; i++) {
modal = document.getElementById(prefixModal + i);
img = document.getElementById(prefixmyImg + i);
modalImg = document.getElementById(prefixmodalImg + i);
// NOTE: put the code that does something IN HERE,
// right now it's outside the loop
}
is iterating through all elements in the HTML document that have ids from "myModal0" through "myModal6", and the same for the other two prefixes "myImg" and "img".
I don't see all these elements in your HTML document. I only see "myModal1" and "myModal2" (as well as elements 1 and 2 of "myImg" and "img".
It looks like you either need to reduce the size of the loop so it only iterates through the elements you actually have, or you need to fill out the rest of the HTML and put in the rest of the elements (all the way from 0 through (and including) 6.
Oh and there's another thing to remember here too, none of your actual code that is causing the error, is inside the loop. All you do in the loop is setting the names of the variables. So the later code is always using "myModal6", because that is the last thing the loop sets the names to.

Related

Why do i have to click twice to open a modal?

I am trying to make a button on which if we click a popup opens(modal) and it is working but only problem is i need to click it twice to open it and i don't see how can i solve it.
// Get the modal
function modal1() {
var modal = document.getElementById("myModal");
// Get the button that opens the modal
var btn = document.getElementById("myBtn");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks the button, open the modal
btn.onclick = function() {
modal.style.display = "block";
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
}
/* The Modal (background) */
.modal {
display: none;
/* Hidden by default */
position: fixed;
/* Stay in place */
z-index: 1;
/* Sit on top */
padding-top: 100px;
/* Location of the box */
left: 0;
top: 0;
width: 100%;
/* Full width */
height: 100%;
/* Full height */
overflow: auto;
/* Enable scroll if needed */
background-color: rgb(0, 0, 0);
/* Fallback color */
background-color: rgba(0, 0, 0, 0.4);
/* Black w/ opacity */
}
/* Modal Content */
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
/* The Close Button */
.close {
color: #aaaaaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
<!-- Trigger/Open The Modal -->
<button id="myBtn" onclick="modal1()">Open Modal</button>
<!-- The Modal -->
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<p>Some text in the Modal..</p>
</div>
</div>
Thank you in advance :)
ps: I am leaning in very early stage js (beginner)
It's fairly straightforward if you read your code in order.
When you click the button, it runs the modal1() function.
This function, among other things, adds a btn.onclick listener, waiting for a click.
That's it.
So now, you have to click a second time in order to trigger the listener you just created.
The new onclick listener you create, for that matter, overrides the current onclick on the button, and I'm not sure why you do this.
The simple solution is to put modal.style.display = "block" directly in modal1(). Why override the onclick function?
function modal1() {
modal.style.display = "block";
}

Javscript: For every image click show modal with image zoom

I'm currently working on a simple image modal that should show only an image zoom with a close button.
I have a markup generated from my CMS in which the a tag can be configurated to have an extra class "lightbox" as an attribute which should then trigger the lightbox script.
However, currently it seems to only work for the first image that's loaded. When I click on another image it shows the same image source from the first one and I'm not sure how to fix it. Do all the images need to be looped over first?
My CMS generates a markupa for the images like this in the DOM (image is a placeholder):
<a href="image1.png" class="lightbox">
<img class="image-embed-item" src="image" >
</a>
<a href="image1.png" class="lightbox">
<img class="image-embed-item" src="image" >
</a>
<a href="image1.png" class="lightbox">
<img class="image-embed-item" src="image" >
</a>
In my default layout I then add the markup for the lightbox modal:
<div id="imagemodal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<div class="close">×</div>
<img src="" id="imagepreview" style="width: 100%;" >
</div>
</div>
This is the javascript code:
window.addEventListener('DOMContentLoaded', function () {
// add imageresource id to loaded image
$(".image-embed-item").attr("id", "imageresource");
// add data-toggle class to all lightbox elements
$(".lightbox").attr("data-toggle", "lightbox");
// click event for data toggle
$(document).on('click', '[data-toggle="lightbox"]', function (event) {
event.preventDefault();
// use image source from clicked image
$('#imagepreview').attr('src', $('#imageresource').attr('src'));
$('.modal').css('display', 'block');
});
$(document).on('click', $('.closeModal'), function (event) {
// close function
});
});
Here is my css:
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1000; /* Sit on top */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* Modal Content/Box */
.modal-content {
background-color: #fefefe;
margin: 15% auto; /* 15% from the top and centered */
padding: 20px;
border: 1px solid #888;
width: 80%; /* Could be more or less, depending on screen size */
}
/* The Close Button */
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
You are using the same id for all .image-embed-item in:
$(".image-embed-item").attr("id", "imageresource");
And then use $('#imageresource').attr('src') to set the preview.
That's why it always show the first image in the modal. You can solve it by changing $('#imageresource').attr('src') to $(this).find('img').attr('src'). Something like this:
window.addEventListener('DOMContentLoaded', function () {
// add data-toggle class to all lightbox elements
$(".lightbox").attr("data-toggle", "lightbox");
// click event for data toggle
$(document).on('click', '[data-toggle="lightbox"]', function (event) {
event.preventDefault();
// use image source from clicked image
$('#imagepreview').attr('src', $(this).find('img').attr('src'));
$('.modal').css('display', 'block');
});
$(document).on('click', $('.closeModal'), function (event) {
// close function
});
});

How do I set the active state for image buttons instead of just focused state with my current code?

First time posting here and new to programming with just 3 days of experience.
I'm having some trouble getting my default button to be active instead of just focused. I've attempted to read other posts about this, but my lack of experience makes it hard for me to put 2 and 2 together.
The page is going into squarespace so I'm trying to do it all in one code block. I don't want the buttons to deactivate when the user clicks on other parts of the website, which it currently happens. (Even if they click on blank areas).
Thank you very much for any advice you can give me.
/* Change Button Size/Border/BG Color And Align To Middle */
.services {
width: 210px;
height: 135px;
padding: 0px;
border: 0px;
outline: 0px;
cursor: pointer;
color: #999999;
font-size: 20px;
text-align: center;
background: url("https://i.ibb.co/G5mn9nY/Services-Buttons-Combined-Big.png") no-repeat;
/* As all link share the same background-image */
}
/* Set Mouseover Button Text and Current/Active Color */
.services:focus,
.services:hover,
.services:active {
color: black;
}
/* Position Button Text*/
divtext {
position: relative;
top: 90px;
}
/* Div Wrapper to format button areas. */
.servicesbuttonwrapper {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
}
/* Div Wrapper to format revealed description text. */
.servicestextwrapper {
text-align: left;
margin-left: 100px;
margin-right: 32px;
top: 50px;
position: relative;
}
/* Change Image rollover position depending On Focus. */
.assets {
background-position: 0 0;
}
.assets:focus,
.assets:hover,
.assets:active {
background-position: 0 -135px;
}
.viz {
background-position: 0 -270px;
}
.viz:focus,
.viz:hover,
.viz:active {
background-position: 0 -405px;
}
.software {
background-position: 0 -540px;
}
.software:focus,
.software:hover,
.software:active {
background-position: 0 -675px;
}
.more {
background-position: 0 -810px;
}
.more:focus,
.more:hover,
.more:active {
background-position: 0 -945px;
}
/* Hides intitial button descriptions. */
#assets,
#viz,
#software,
#more {
display: none;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Services</title>
</head>
<body>
<!--Div wrapper so we can format positioning of buttons in CSS-->
<div class="servicesbuttonwrapper">
<!--Base buttons plus javascript functions for click behavior. This used to be <button class> instead of <a href> but I read somewhere this is better... seems to work ok.-->
<a href="javascript:void(0)" id="defaultstate" onclick="show('software');" class="services software">
<divtext>INTERACTIVE SOFTWARE</divtext>
</a>
<a href="javascript:void(0)" onclick="show('assets');" class="services assets">
<divtext>3D ASSET CREATION</divtext>
</a>
<a href="javascript:void(0)" onclick="show('viz');" class="services viz">
<divtext>3D VISUALIZATION</divtext>
</a>
<a href="javascript:void(0)" onclick="show('more');" class="services more">
<divtext>IMAGE CREATION</divtext>
</a>
</div>
<!--Base description text.-->
<div class="servicestextwrapper">
<div id="assets">3D Assets Description.</div>
<div id="viz">3D Visualization Description.</div>
<div id="software">Interactive Software Description.</div>
<div id="more">And More Description.</div>
</div>
<!--Javascript function to hide/show elements based on button press.-->
<script type="text/javascript">
function show(elementId) {
document.getElementById("assets").style.display = "none";
document.getElementById("viz").style.display = "none";
document.getElementById("software").style.display = "none";
document.getElementById("more").style.display = "none";
document.getElementById(elementId).style.display = "block";
}
</script>
<!--Javascript function to set first button as focus.-->
<script>
window.onload = function() {
document.getElementById("defaultstate").click();
};
var linkToFocus = document.getElementById('defaultstate');
linkToFocus.focus();
</script>
</body>
</html>
Welcome to Stack Overflow.
So first thing to note, the :active pseudo element only applies when the user clicks (mouse-down) on something. You can see it here
The most common method is to apply the css class "active", and have a .active selector on whatever element you want to style.
Right now you have the buttons affected by hover and focus, so when the user clicks outside the button it loses focus.
You can solve this by changing a bit of CSS and javascript. The edited portions are marked by /* EDIT */
I would not recommend the last line where I exploit the fact that your function passes in the element ID, and that element ID matches the class of the button that was used to select it. A better way would to have show take the Javascript event as argument, then use the event.target to get the a tag clicked on, then use a getElementById on something like a data-target="more" attribute. This will allow you to change the CSS class without coupling the class to the implementation of the Javascript
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Services</title>
</head>
<style>/* Change Button Size/Border/BG Color And Align To Middle */
.services {
width:210px;
height:135px;
padding: 0px;
border:0px;
outline:0px;
cursor: pointer;
color: #999999;
font-size: 20px;
text-align: center;
background: url("https://i.ibb.co/G5mn9nY/Services-Buttons-Combined-Big.png") no-repeat; /* As all link share the same background-image */
}
/* Set Mouseover Button Text and Current/Active Color */
/* EDIT */
.services:focus, .services:hover, .services.active {
color: black;
}
/* Position Button Text*/
divtext {
position: relative;
top: 90px;
}
/* Div Wrapper to format button areas. */
.servicesbuttonwrapper {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
}
/* Div Wrapper to format revealed description text. */
.servicestextwrapper {
text-align: left;
margin-left: 100px;
margin-right: 32px;
top: 50px;
position: relative;
}
/* Change Image rollover position depending On Focus. */
.assets {
background-position: 0 0;
}
/* EDIT */
.assets:focus, .assets:hover, .assets.active {
background-position: 0 -135px;
}
.viz {
background-position: 0 -270px;
}
/* EDIT */
.viz:focus, .viz:hover, .viz.active {
background-position: 0 -405px;
}
.software {
background-position: 0 -540px;
}
/* EDIT */
.software:focus, .software:hover, .software.active {
background-position: 0 -675px;
}
.more {
background-position: 0 -810px;
}
/* EDIT */
.more:focus, .more:hover, .more.active {
background-position: 0 -945px;
}
/* Hides intitial button descriptions. */
#assets, #viz, #software, #more {
display: none;
}
</style>
<body>
<!--Div wrapper so we can format positioning of buttons in CSS-->
<div class="servicesbuttonwrapper">
<!--Base buttons plus javascript functions for click behavior. This used to be <button class> instead of <a href> but I read somewhere this is better... seems to work ok.-->
<divtext>INTERACTIVE SOFTWARE</divtext>
<divtext>3D ASSET CREATION</divtext>
<divtext>3D VISUALIZATION</divtext>
<divtext>IMAGE CREATION</divtext>
</div>
<!--Base description text.-->
<div class="servicestextwrapper">
<div id="assets">3D Assets Description.</div>
<div id="viz">3D Visualization Description.</div>
<div id="software">Interactive Software Description.</div>
<div id="more">And More Description.</div>
</div>
<!--Javascript function to hide/show elements based on button press.-->
<script type="text/javascript">
/* EDIT */
function show(elementId) {
document.getElementById("assets").style.display = "none";
document.getElementById("viz").style.display = "none";
document.getElementById("software").style.display = "none";
document.getElementById("more").style.display = "none";
document.getElementById(elementId).style.display = "block";
// get a list of the buttons with ".services" class
const buttons = document.querySelectorAll(".services");
for(let button of buttons) {
// remove ".active" class
button.classList.remove("active");
}
// add the active class to element button specified by argument
document.querySelector("." + elementId).classList.add("active");
}
</script>
<!--Javascript function to set first button as focus.-->
<script>
window.onload=function(){
document.getElementById("defaultstate").click();
};
var linkToFocus = document.getElementById('defaultstate');
linkToFocus.focus();
</script>
</body>
</html>

How can I generalise code which produces a modal image to process multiple images

My end objective is to produce a web page of small images which are clickable. When clicked, a modal image of the small image is displayed.
I copied the following code from the W3Schools site:
// Get the modal
var modal = document.getElementById('myModal');
// Get the image and insert it inside the modal - use its "alt" text as a caption
var img = document.getElementById('myImg');
var modalImg = document.getElementById("img01");
var captionText = document.getElementById("caption");
img.onclick = function(){
modal.style.display = "block";
modalImg.src = this.src;
captionText.innerHTML = this.alt;
}
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
/* Style the Image Used to Trigger the Modal */
#myImg {
border-radius: 5px;
cursor: pointer;
transition: 0.3s;
}
#myImg:hover {opacity: 0.7;}
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.9); /* Black w/ opacity */
}
/* Modal Content (Image) */
.modal-content {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
}
/* Caption of Modal Image (Image Text) - Same Width as the Image */
#caption {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
text-align: center;
color: #ccc;
padding: 10px 0;
height: 150px;
}
/* Add Animation - Zoom in the Modal */
.modal-content, #caption {
-webkit-animation-name: zoom;
-webkit-animation-duration: 0.6s;
animation-name: zoom;
animation-duration: 0.6s;
}
#-webkit-keyframes zoom {
from {-webkit-transform:scale(0)}
to {-webkit-transform:scale(1)}
}
#keyframes zoom {
from {transform:scale(0)}
to {transform:scale(1)}
}
/* The Close Button */
.close {
position: absolute;
top: 15px;
right: 35px;
color: #f1f1f1;
font-size: 40px;
font-weight: bold;
transition: 0.3s;
}
.close:hover,
.close:focus {
color: #bbb;
text-decoration: none;
cursor: pointer;
}
/* 100% Image Width on Smaller Screens */
#media only screen and (max-width: 700px){
.modal-content {
width: 100%;
}
}
<!-- Trigger the Modal -->
<img id="myImg" src="img_fjords.jpg" alt="Trolltunga, Norway" width="300" height="200">
<!-- The Modal -->
<div id="myModal" class="modal">
<!-- The Close Button -->
<span class="close" onclick="document.getElementById('myModal').style.display='none'">×</span>
<!-- Modal Content (The Image) -->
<img class="modal-content" id="img01">
<!-- Modal Caption (Image Text) -->
<div id="caption"></div>
</div>
I can see that the code is hard-coded to one image and I think the easiest way to achieve my goal is pass the id of the image to the js script. So I've begun modifying the html thus:
<!-- Trigger the Modal -->
<img class="images" id="img_1" src="images/Cairns1-041-3-Water-Safari.gif" alt="Water Travellers" width="300" height="200">
<img class="images" id="img_2" src="images/Cairns1-047-2-Handle-With-Care.gif" alt="Manhandle" width="300" height="200">
<!-- img_3 etc -->
Am I on the right track and if so, how do I pass the image id to the script? Part of my objective is to understand the code as much as possible rather than to just copy a plug-in.
Here's a JSfiddle I've made that shows how my answer can be merged with the question. Hopefully, it can help anyone else that's using w3schools. https://jsfiddle.net/bdneyq4s/1/
Yes, you're on the right track, although ID's aren't necessary if you set up an event observer.
You need to add the data that's needed to show the big version of the image in the modal. (If you're using the same image for the modal + the thumbnail, then don't worry about using the extra attribute)
For example, you can have something like:
<img class="modal-image" src="path/to/thumbnail.jpg" alt="Caption to show" data-bigImage="path/to/big-image.jpg" />
Then you can create an event observer that'll listen to an on-click event on all elements that use the modal-image class. From there you can grab the data-bigImage and alt attributes from the clicked on element and populate the modal's content with it.
You said you didn't want to copy and paste code so I didn't write out the Javascript that'll do it, but if you need me to, I'll edit my answer to show some examples on how it can be done.
EDIT: I've added the following snippet to show a very basic example of how it can be done. I've made an event observer for each image with the modal-image class and replace the image in the modal with the new image attributes. (You can click on the little thumbnails to see it work)
// Select all images that have the class modal-image
var image = document.getElementsByClassName("modal-image");
// to set an event observer on each element
for( var i=0; i<image.length; i++ ){
image[i].onclick = function() {
// get the two values we need from the image
// i'm using the alt as the caption
var
bigImage = this.getAttribute('data-bigImage'),
caption = this.getAttribute('alt');
replaceModalImage( bigImage, caption );
}
}
/*
* Replace the modal image's source in order to display the new image
*
* #param src Source of the new image
* #param caption Caption to show with the modal
*/
function replaceModalImage( src, caption ){
var
img = document.getElementById('big-image'),
captionContainer = document.getElementById('caption');
img.setAttribute('src', src);
img.setAttribute('alt', caption);
captionContainer.innerHTML = caption;
}
.modal-image{
/* this is just to make it small like a thumbnail, use a small image in production */
width: 100px;
}
img{
max-width: 100%;
}
#modal{
background: #999;
width: 600px;
padding: 20px;
}
<!-- thumbnail container -->
<div class="thumbnails">
<!-- src = small image, data-bigImage = big image src -->
<img class="modal-image" src="http://vignette4.wikia.nocookie.net/geometry-dash/images/4/4b/GearSawblade01.png" alt="Caption to show" data-bigImage="http://simpleicon.com/wp-content/uploads/gear-8.png" />
<img class="modal-image" src="https://ak1.ostkcdn.com/images/products/6626651/6626651/Cottage-Oak-Dining-Table-P14192779.jpg" alt="Caption to show" data-bigImage="http://www.ikea.com/PIAimages/0106117_PE253936_S5.JPG" />
</div>
<!-- modal html -->
<div id="modal">
<div id="image"><img id="big-image" src="" alt="" /></div>
<div id="caption"></div>
</div>

bxslider with dynamic html

I am using bxslider in a modal and since the modal should present images depending on the user selection, I am writing the html within the slider dynamically.
Here is my modal code:
<div class="modal fade" id="figure_carousel" role="dialog">
<div class="modal-dialog" style="width: 80%; height: 100%;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<br>
</div>
<div class="modal-body">
<ul class="bxslider" id="elements">
</ul>
</div>
<div class="modal-footer">
<input class="btn btn-default" type="button" data-dismiss="modal" value="Close" />
</div>
</div>
</div>
</div>
when an image is clicked I run the following script
<script>
$(document).on("click",".paper_img",function(event){
var modalview = get_html()
document.getElementById('elements').innerHTML = ""
$('#figure_carousel').modal('show');
$('.bxslider').append(modalview.innerHTML);
var slider = $('.bxslider').bxSlider({mode: 'horizontal'});
slider.reloadSlider();
});
</script>
which gets some html (using the get_html function), writes it in the id=elements ul in the modal and launches the modal. Lets assume the html code which comes back from the get_html function looks like this
<li><img src="/static/sourcefiles/image.png" alt="figure"/></li>
When the modal is opened, the size of the images is wrong. If I resize the browser window manually, the slides become correct. Somehow bxslider cannot deal with me writing html code dynamically. How can I load the bxslider after writing the html code or any other way to solve this?
thanks
carl
EDIT: Here is my problem in an example
http://plnkr.co/edit/sHVq6cggMfVVS4QywQNs?p=preview
your are calling the bxSlider() when the bootstrap modal is hidden. May be the reason bxSlider couldn't detect the height of the images.
var bx;
$('#myModal1').on('shown.bs.modal', function () {
if(bx === undefined){
bx= $('.bxslider').bxSlider();
} else {
bx.reloadSlider();
}
});
'shown.bs.modal' it the bootstrap event fires when the model is made visible to user. then we call the bxSlider(), and everytime we add images we are calling bx.reloadSlider();
example : http://plnkr.co/edit/LTMCuDUc3vUm9VnmmvzG?p=preview
Try this:
CSS
.bx-viewport { min-height: 90vh !important; }
If that doesn't work or only works once, then try:
CSS
.bx-viewport.extend { min-height: 90vh !important; }
jQuery
Add this option:
onBeforeSlide: extendVP;
Add this to above the </body> end tag:
function extendVP($ele, from, to) {
var vp = $('.bx-viewport');
vp.addClass('extend');
}
UPDATE 1
If images are not scaling with the proper aspect ratio or not even scaling, here's 2 suggestions:
CSS
Simple
img { width: 100%; height: auto; }
Better
This procedure involves using a background image:
Place a <div> in a slide (<li> for your markup), give it a class (like imgFrame)
Then place an inline style attribute on it. Assign the image to imgFrame as follows:
<div class="imgFrame" style="background-image: url('path/to/img.jpg')"></div>
Next add this to your CSS:
.imgFrame {
width: 100%;
height: auto;
background-repeat: no-repeat;
background-size: contain;
}
UPDATE 2
The modifications done to this bxSlider demo is not to show it works, because it doesn't have the height issue in the first place. It's purpose is to show the source and explain what it does. While making this demo, I created a function adaptiveWidth(), it's optional. What it does is on page load it has an overlay, once it's clicked, it'll enter full screen mode then quickly exit full screen as the overlay fades away. Hopefully that'll wake up bxSlider from it's stupor.
CodePen
CSS
<link href="https://cdn.jsdelivr.net/bxslider/4.2.5/jquery.bxslider.css" rel="stylesheet"/>
/* Default Style ____________________________________________________*/
html, body { box-sizing: border-box; }
html { height: 100vh; width: 100vw; overflow-x: hidden; overflow-y: auto; }
body { height: 100%; width: 100%; position: relative; }
*, *:before, *:after { box-sizing: inherit; margin: 0; padding: 0; border: 0; }
/* Aesthetics [Optional]_____________________________________________*/
html { font: 400 16px/1.45 'Source Code Pro'; }
body { background: #000; color: #FFF; font-variant: small-caps; }
h1 { font-size: 3rem; font-weight: 700; }
/* jquery.bxslider.css jsDelvr.com Image Override ___________________*/
.bx-wrapper .bx-loading { background: url('https://cdn.jsdelivr.net/bxslider/4.2.5/images/bx_loader.gif') center center no-repeat #ffffff; }
.bx-wrapper .bx-prev { background: url('https://cdn.jsdelivr.net/bxslider/4.2.5/images/controls.png') no-repeat 0 -32px; }
.bx-wrapper .bx-next { background: url('https://cdn.jsdelivr.net/bxslider/4.2.5/images/controls.png') no-repeat -43px -32px; }
.bx-wrapper .bx-controls-auto .bx-start { background: url('https://cdn.jsdelivr.net/bxslider/4.2.5/images/controls.png') -86px -11px no-repeat; }
.bx-wrapper .bx-controls-auto .bx-stop { background: url('https://cdn.jsdelivr.net/bxslider/4.2.5/images/controls.png') -86px -44px no-repeat; }
/* bxSlider init Style ___________________________________________*/
#overlay { position: fixed; top: 0; bottom: 0; left: 0; right: 0; z-index: 999999999; height: 101%; width: 101%; overflow: hidden; cursor: pointer; pointer-events: auto; background-color: black; opacity: .5; }
.ext { max-width: -moz-fit-content; max-width: -webkit-fit-content; max-width: fit-content; width: auto; height: auto; padding: 25%; } /* adaptiveWidth Style [Optional] */
HTML
<body class="expand">
<div id="overlay"><h1>Click anywhere to start</h1></div>
<div class="ext"> <!-- adaptiveWidth Wrapper [Optional] -->
<ul class='bxslider'>
<li>
<img src="http://dummyimage.com/500X16:9/000/FFF.png&text=1"/>
</li>
<li>
<img src="http://dummyimage.com/500X4:3/07C/FC0.png&text=2"/>
</li>
<li>
<img src="http://dummyimage.com/4:3X400/D06/0FF.png&text=3"/>
</li>
<li>
<img src="http://dummyimage.com/640X16:9/765/cee.png&text=4"/>
</li>
<li>
<img src="http://dummyimage.com/210X16:9/B40/6F3.png&text=5"/>
</li>
<li>
<img src="http://dummyimage.com/16:9X420/E2F/FC9.png&text=6"/>
</li>
</ul>
</div>
jQ/JS
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js"></script>
<!-- [Suggestion] Don't use the minified version: jquery.bxslider.min.js, it's buggy -->
<script src="https://cdn.jsdelivr.net/bxslider/4.2.5/jquery.bxslider.js"></script>
/* Page loads #overlay */
$(document).ready(function() { // jQ DocReady
$("#overlay").one('click', function(event) { // User clicks #overlay
event.stopImmediatePropagation(); // Isolate Event
var tgt = document.querySelector('.expand'),// Target <body>
that = this; // Establish this as that
enterFS(tgt); // Enter full screen to wakeup bxSlider!
exitFS(); // Exit full screen
$(that).fadeOut(1000, function() { // #overlay fades...
$(that).remove(); // #overlay is gone
});
});
/* Adaptive bxSlider */
var bx = $('.bxslider').bxSlider({
adaptiveHeight: true, // http://bxslider.com/options#adaptiveHeight
onSlideBefore: adaptiveWidth // Callback [optional]
});
});
/* adaptiveHeight [Optional] */
function adaptiveWidth($ele, from, to) {
var imgWidth = $ele.find('img').width();
var bxWidth = $('.bx-wrapper').width(imgWidth);
}
/* Enter Full Screen */
function enterFS(element) {
if(element.requestFullscreen) {
element.requestFullscreen();
}
else if(element.mozRequestFullScreen) {
element.mozRequestFullScreen();
}
else if(element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
}
else if(element.msRequestFullscreen) {
element.msRequestFullscreen();
}
}
/* Exit Full Screen */
function exitFS() {
if(document.exitFullscreen) {
document.exitFullscreen();
}
else if(document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
else if(document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}

Categories

Resources