PhotoSwipe with Polymer misalignment - polymer

I'm trying to make a small web-app using Polymer, based on the Nav + List + Detail-layout example they have provided. For part of my web-app I want to make a photo gallery. Luckily, there's an element for that. Unfortunately, there's no element for that. So I set myself upon the task of making my own custom-element that provides this functionality, based on PhotoSwipe.
So I decided to start simple by just implementing the code they provided as an example (see this CodePen). I simply copied this code into a custom element to see how it works, but unfortunately it doesn't work 100%. Here is the CodePen of the custom element.
For small displays the photo's display correctly, but when the screen is tall the 3rd and 4th photo don't align to the center anymore, but slide to the bottom right corner. The easiest way to see this is by pressing the full screen button when viewing an image. Below is an image where you can clearly see the offset to the bottom-right.
I rechecked and this isn't an issue in their own CodePen, but I can't seem to find if there are overlapping styles or something else is breaking it up. Any ides?
<dom-module id="photo-album">
<link rel="import" type="css" href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.0/photoswipe.css"> <!-- photoswipe/photoswipe.css -->
<link rel="import" type="css" href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.0/default-skin/default-skin.css"> <!-- photoswipe/default-skin/default-skin.css -->
<template>
<style>
:host {
display: block;
}
.my-gallery {
width: 100%;
float: left;
}
.my-gallery img {
width: 100%;
height: auto;
}
.my-gallery figure {
display: block;
float: left;
margin: 0 5px 5px 0;
width: 150px;
}
.my-gallery figcaption {
display: none;
}
</style>
<iron-ajax url="" params="" handle-as="json" last-response="{{photos}}"></iron-ajax>
<!--<template is="dom-repeat" items="{{photos}}">
<iron-image style="width:400px; height:400px; background-color: lightgray;" sizing="cover" preload fade src="{{item}}"></iron-image>
</template>-->
<div class="my-gallery" id="gallery" itemscope itemtype="http://schema.org/ImageGallery">
<figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a href="https://farm3.staticflickr.com/2567/5697107145_a4c2eaa0cd_o.jpg" itemprop="contentUrl" data-size="1024x1024">
<img src="https://farm3.staticflickr.com/2567/5697107145_3c27ff3cd1_m.jpg" itemprop="thumbnail" alt="Image description" />
</a>
</figure>
<figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a href="https://farm2.staticflickr.com/1043/5186867718_06b2e9e551_b.jpg" itemprop="contentUrl" data-size="964x1024">
<img src="https://farm2.staticflickr.com/1043/5186867718_06b2e9e551_m.jpg" itemprop="thumbnail" alt="Image description" />
</a>
</figure>
<figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a href="https://farm7.staticflickr.com/6175/6176698785_7dee72237e_b.jpg" itemprop="contentUrl" data-size="1024x683">
<img src="https://farm7.staticflickr.com/6175/6176698785_7dee72237e_m.jpg" itemprop="thumbnail" alt="Image description" />
</a>
</figure>
<figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a href="https://farm6.staticflickr.com/5023/5578283926_822e5e5791_b.jpg" itemprop="contentUrl" data-size="1024x768">
<img src="https://farm6.staticflickr.com/5023/5578283926_822e5e5791_m.jpg" itemprop="thumbnail" alt="Image description" />
</a>
</figure>
</div>
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
<div class="pswp__bg"></div>
<div class="pswp__scroll-wrap">
<div class="pswp__container">
<div class="pswp__item"></div>
<div class="pswp__item"></div>
<div class="pswp__item"></div>
</div>
<div class="pswp__ui pswp__ui--hidden">
<div class="pswp__top-bar">
<div class="pswp__counter"></div>
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
<div class="pswp__preloader">
<div class="pswp__preloader__icn">
<div class="pswp__preloader__cut">
<div class="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class="pswp__share-tooltip"></div>
</div>
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)"></button>
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)"></button>
<div class="pswp__caption">
<div class="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.0/photoswipe.min.js"></script> <!-- photoswipe/photoswipe.min.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.0/photoswipe-ui-default.min.js"></script> <!-- photoswipe/photoswipe-ui-default.min.js -->
<script>
Polymer({
is: 'photo-album',
properties: {
items: {
type: Array,
notify: true,
}
},
ready: function() {
this.initPhotoSwipeFromDOM();
},
initPhotoSwipeFromDOM: function(){
var gallerySelector = this.$.gallery;
var parseThumbnailElements = function(el) {
var thumbElements = el.childNodes,
numNodes = thumbElements.length,
items = [],
figureEl,
linkEl,
size,
item;
for(var i = 0; i < numNodes; i++) {
figureEl = thumbElements[i]; // <figure> element
// include only element nodes
if(figureEl.nodeType !== 1) {
continue;
}
linkEl = figureEl.children[0]; // <a> element
size = linkEl.getAttribute('data-size').split('x');
// create slide object
item = {
src: linkEl.getAttribute('href'),
w: parseInt(size[0], 10),
h: parseInt(size[1], 10)
};
if(figureEl.children.length > 1) {
// <figcaption> content
item.title = figureEl.children[1].innerHTML;
}
if(linkEl.children.length > 0) {
// <img> thumbnail element, retrieving thumbnail url
item.msrc = linkEl.children[0].getAttribute('src');
}
item.el = figureEl; // save link to element for getThumbBoundsFn
items.push(item);
}
return items;
};
// find nearest parent element
var closest = function closest(el, fn) {
return el && ( fn(el) ? el : closest(el.parentNode, fn) );
};
// triggers when user clicks on thumbnail
var onThumbnailsClick = function(e) {
e = e || window.event;
e.preventDefault ? e.preventDefault() : e.returnValue = false;
var eTarget = e.target || e.srcElement;
// find root element of slide
var clickedListItem = closest(eTarget, function(el) {
return (el.tagName && el.tagName.toUpperCase() === 'FIGURE');
});
if(!clickedListItem) {
return;
}
// find index of clicked item by looping through all child nodes
// alternatively, you may define index via data- attribute
var clickedGallery = clickedListItem.parentNode,
childNodes = clickedListItem.parentNode.childNodes,
numChildNodes = childNodes.length,
nodeIndex = 0,
index;
for (var i = 0; i < numChildNodes; i++) {
if(childNodes[i].nodeType !== 1) {
continue;
}
if(childNodes[i] === clickedListItem) {
index = nodeIndex;
break;
}
nodeIndex++;
}
if(index >= 0) {
// open PhotoSwipe if valid index found
openPhotoSwipe( index, clickedGallery );
}
return false;
};
// parse picture index and gallery index from URL (#&pid=1&gid=2)
var photoswipeParseHash = function() {
var hash = window.location.hash.substring(1),
params = {};
if(hash.length < 5) {
return params;
}
var vars = hash.split('&');
for (var i = 0; i < vars.length; i++) {
if(!vars[i]) {
continue;
}
var pair = vars[i].split('=');
if(pair.length < 2) {
continue;
}
params[pair[0]] = pair[1];
}
if(params.gid) {
params.gid = parseInt(params.gid, 10);
}
return params;
};
var openPhotoSwipe = function(index, galleryElement, disableAnimation, fromURL) {
var pswpElement = document.querySelectorAll('.pswp')[0],
gallery,
options,
items;
items = parseThumbnailElements(galleryElement);
// define options (if needed)
options = {
// define gallery index (for URL)
galleryUID: galleryElement.getAttribute('data-pswp-uid'),
getThumbBoundsFn: function(index) {
// See Options -> getThumbBoundsFn section of documentation for more info
var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail
pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
rect = thumbnail.getBoundingClientRect();
return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
}
};
// PhotoSwipe opened from URL
if(fromURL) {
if(options.galleryPIDs) {
// parse real index when custom PIDs are used
// http://photoswipe.com/documentation/faq.html#custom-pid-in-url
for(var j = 0; j < items.length; j++) {
if(items[j].pid == index) {
options.index = j;
break;
}
}
} else {
// in URL indexes start from 1
options.index = parseInt(index, 10) - 1;
}
} else {
options.index = parseInt(index, 10);
}
// exit if index not found
if( isNaN(options.index) ) {
return;
}
options.showAnimationDuration = 0;
options.hideAnimationDuration = 0;
// Pass data to PhotoSwipe and initialize it
gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options);
gallery.init();
};
// loop through all gallery elements and bind events
var galleryElements = this.$.gallery;
galleryElements.setAttribute('data-pswp-uid', 1);
galleryElements.onclick = onThumbnailsClick;
// Parse URL and open gallery if it contains #&pid=3&gid=1
var hashData = photoswipeParseHash();
if(hashData.pid && hashData.gid) {
openPhotoSwipe( hashData.pid , galleryElements[ hashData.gid - 1 ], true, true );
}
}
});
</script>
</dom-module>

It seems you're missing styles from photoswipe.css.

Related

Why is scroll-behavior not working on my phone?

I added the scroll-behavior property in my CSS but it only works on the google chrome tool that allows me to see my website like if it was on a phone. When I load my website on my actual phone, there is no sliding effect. Any idea?
Here is what the code looks like :
function scrollToSection(event) {
if (supportsSmoothScrolling()) {
return;
}
event.preventDefault();
const scrollToElem = document.getElementById("section");
SmoothVerticalScrolling(scrollToElem, 300, "top");
}
function supportsSmoothScrolling() {
const body = document.body;
const scrollSave = body.style.scrollBehavior;
body.style.scrollBehavior = 'smooth';
const hasSmooth = getComputedStyle(body).scrollBehavior === 'smooth';
body.style.scrollBehavior = scrollSave;
return hasSmooth;
};
function SmoothVerticalScrolling(element, time, position) {
var eTop = element.getBoundingClientRect().top;
var eAmt = eTop / 100;
var curTime = 0;
while (curTime <= time) {
window.setTimeout(SVS_B, curTime, eAmt, position);
curTime += time / 100;
}
}
function SVS_B(eAmt, position) {
if (position == "center" || position == "")
window.scrollBy(0, eAmt / 2);
if (position == "top")
window.scrollBy(0, eAmt);
}
html, body {
scroll-behavior: smooth;
overflow-y: scroll;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="container-fluid h-100 nopadding">
<div class="row h-100 nopadding">
<div class="col-lg-8 black nopadding text-center d-flex flex-column justify-content-center">
<a onclick="scrollToSection(event)" href="#more" class="more">Here is the button</a>
</div>
<div id="more"
class="col-lg-4 white nopadding text-center d-flex flex-column align-self-center justify-content-center">
Here is the section
</div>
</div>
</div>
I didn't add all the page elements but the arrow represent the anchor tag in the code :
As you have noticed, Safari does not support the scroll-behavior CSS property (see this). You'd need some JavaScript to achieve the same effect across different browsers. You may find an example here.
Update:
This is a working code snippet of this answer (which combines the answers of George Daniel and terrymorse).
function scrollToSection(event) {
if (supportsSmoothScrolling()) {
return;
}
event.preventDefault();
const scrollToElem = document.getElementById("section");
SmoothVerticalScrolling(scrollToElem, 300, "top");
}
function supportsSmoothScrolling() {
const body = document.body;
const scrollSave = body.style.scrollBehavior;
body.style.scrollBehavior = 'smooth';
const hasSmooth = getComputedStyle(body).scrollBehavior === 'smooth';
body.style.scrollBehavior = scrollSave;
return hasSmooth;
};
function SmoothVerticalScrolling(element, time, position) {
var eTop = element.getBoundingClientRect().top;
var eAmt = eTop / 100;
var curTime = 0;
while (curTime <= time) {
window.setTimeout(SVS_B, curTime, eAmt, position);
curTime += time / 100;
}
}
function SVS_B(eAmt, position) {
if (position == "center" || position == "")
window.scrollBy(0, eAmt / 2);
if (position == "top")
window.scrollBy(0, eAmt);
}
body {
scroll-behavior: smooth;
height: 1000px;
}
section {
margin-top: 500px;
}
<a onclick="scrollToSection(event)" href="#section">
Redirect On section
</a>
<section id="section">
Section Content
</section>

Material design for web - how to make an autocomplete input

I am using google's material design for web. And I would like to use their select component as an autocomplete component. What I am aiming for is the autocomplete you can see in react mui. I have removed the disabled and readonly input attributes but I still can't write anything to input field.
<div class="mdc-select demo-width-class">
<div class="mdc-select__anchor">
<span class="mdc-select__ripple"></span>
<input type="text" class="mdc-select__selected-text">
<i class="mdc-select__dropdown-icon"></i>
<span class="mdc-floating-label">Pick a Food Group</span>
<span class="mdc-line-ripple"></span>
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface mdc-menu-surface--fullwidth">
<ul class="mdc-list">
<li class="mdc-list-item mdc-list-item--selected" data-value="" aria-selected="true"></li>
<li class="mdc-list-item" data-value="grains">
<span class="mdc-list-item__text">
Bread, Cereal, Rice, and Pasta
</span>
</li>
<li class="mdc-list-item" data-value="vegetables">
<span class="mdc-list-item__text">
Vegetables
</span>
</li>
<li class="mdc-list-item" data-value="fruit">
<span class="mdc-list-item__text">
Fruit
</span>
</li>
</ul>
</div>
</div>
How can I enable the input field for writing into it, so that I can adapt and make an autocomplete input field?
since you have mentioned that you would like to see an answer without using react, thus in plain javascript. I have managed to do just that. I have combined the css and markup from #Sifat Haque's answer and the full working autocomplete logic from w3schools. Though this may seem simple, it was quite a hassle to make this work.
const select = new mdc.select.MDCSelect(document.querySelector('.mdc-select'));
function autocomplete(inp, arr) {
var currentFocus;
inp.addEventListener("input", autocomp);
inp.addEventListener("click", autocomp);
inp.addEventListener("focus", autocomp);
function autocomp(e) {
var a, b, i, val = this.value;
closeAllLists();
currentFocus = -1;
a = document.createElement("ul");
a.setAttribute("id", this.id + "autocomplete-list");
a.setAttribute("class", "autocomplete-items mdc-list");
document.getElementById("autocomp").appendChild(a);
for (i = 0; i < arr.length; i++) {
if (arr[i].substr(0, val.length).toUpperCase() == val.toUpperCase() || (val.trim()).length == 0) {
b = document.createElement("li");
b.setAttribute("class", "mdc-list-item")
b.innerHTML = "<span class='mdc-list-item__text'>" + arr[i] + "</span>";
b.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
b.addEventListener("click", function(e) {
inp.value = this.getElementsByTagName("input")[0].value;
closeAllLists();
});
a.appendChild(b);
}
}
}
inp.addEventListener("keydown", function(e) {
var x = document.getElementById(this.id + "autocomplete-list");
if (x) x = x.getElementsByTagName("li");
if (e.keyCode == 40) {
currentFocus++;
addActive(x);
} else if (e.keyCode == 38) { //up
currentFocus--;
addActive(x);
} else if (e.keyCode == 13) {
e.preventDefault();
if (currentFocus > -1) {
if (x) x[currentFocus].click();
}
}
});
function addActive(x) {
if (!x) return false;
removeActive(x);
if (currentFocus >= x.length) currentFocus = 0;
if (currentFocus < 0) currentFocus = (x.length - 1);
x[currentFocus].classList.add("autocomplete-active");
x[currentFocus].classList.add("mdc-list-item--selected");
}
function removeActive(x) {
for (var i = 0; i < x.length; i++) {
x[i].classList.remove("autocomplete-active");
x[i].classList.remove("mdc-list-item--selected");
}
}
function closeAllLists(elmnt) {
var x = document.getElementsByClassName("autocomplete-items");
for (var i = 0; i < x.length; i++) {
if (elmnt != x[i] && elmnt != inp) {
x[i].parentNode.removeChild(x[i]);
}
}
}
}
/*An array containing all the foods :*/
var foods = ["fruit", "vegetables", "grains", "fries"];
/*initiate the autocomplete function on the "myInput" element, and pass along the foods array as possible autocomplete values:*/
autocomplete(document.getElementById("name-input"), foods);
function makeActive(element) {
document.getElementById("name-input").focus();
element.classList.add("mdc-select--focused");
element.classList.add("mdc-select--activated")
}
* {
box-sizing: border-box;
}
.autocomplete {
position: relative;
display: inline-block;
}
input {
border: 1px solid transparent;
background-color: #f1f1f1;
padding: 10px;
font-size: 16px;
}
input[type=text] {
background-color: transparent;
width: 100%;
margin-left: -200px;
margin-top: 30px;
z-index: -2;
}
input[type=text]:active {
border: none;
}
.autocomplete-items {
position: absolute;
border: 1px solid #d4d4d4;
border-bottom: none;
border-top: none;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
top: 100%;
left: 0;
right: 0;
max-height: 200px;
/*overflow-y: scroll; */
}
.autocomplete-items li {
padding: 10px;
cursor: pointer;
background-color: #fff;
border-bottom: 1px solid #d4d4d4;
}
.mdc-select__menu {
margin-top: -30px;
z-index: 1;
height: 150px;
box-shadow: none;
background-color: transparent;
overflow-x: hidden !important;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link href="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.js"></script>
</head>
<body>
<h2>Autocomplete</h2>
<p>Start typing:</p>
<!--Make sure the form has the autocomplete function switched off:-->
<form autocomplete="off" action="" method="post">
<div class="mdc-select" onclick="makeActive(this)">
<div class="mdc-select__anchor demo-width-class">
<i class="mdc-select__dropdown-icon"></i>
<div class="mdc-select__selected-text"></div>
<span class="mdc-floating-label">Pick a Food Group</span>
<div class="mdc-line-ripple"></div>
<input type="text" id="name-input" name="selectione">
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface">
<div class="autocomplete" id='autocomp' style="width:200px;">
</div>
</div>
</div>
<input type="submit">
</form>
Hope this helps!
edit: added standard selection option
I've created a demo and it somewhat does what you want. The two issues it has are-
User has to click twice(double click) to input values(I can't to make it work on a single click)
The position of the label overlaps the selected value(Even after giving another class or styling it dynamically)
If anybody has any idea about how to go through these issues, their ideas are
welcome. #Leff, you yourself look like a person with experience, can
you solve them? If yes, please do so and please also enlighten us(me).
Also, I've used jquery in this code if you're looking for only vanilla javascript, you might have to do it yourself or find a person who can as I'm no expert in that area but that's the logical part. Your main problem seemed to be of HTML which should be resolved.
Below is the demo, see if it helps you.
// initialize
const select = new mdc.select.MDCSelect(document.querySelector('.mdc-select'));
// stop the original propagation so that input field remains editable
$('#food').on('click', (event) => {
return false;
});
// Demo Data
const foodArr = ['Bread, Cereal, Rice, and Pasta', 'Vegetables', 'Fruit'];
// You'll have to use ajax here to get the data
$('#food').on('keyup', (event) => {
//console.clear();
let $this = $(event.currentTarget);
let currValue = $this.val();
let search = new RegExp(currValue, 'i'); // prepare a regex object // Your custom condition
let matchArr = foodArr.filter(item => search.test(item)); //store the result in an array
let $select = "";
// check if array is empty
if (matchArr.length > 0) {
// map the elements of the array and create option html
matchArr.forEach((item) => {
$select += `<li class="mdc-list-item" data-value="${item}"> ${item}</li>`;
})
} else { // if array is empty, display no match
$select += `<li class="mdc-list-item" id="no_match"> No match found!</li>`;
}
//console.log(matchArr);
// if the data was selected before, unselect it
$('.mdc-list-item--selected:first').attr({'data-value': ''});
$('.mdc-list-item--selected:first').text('');
$('.mdc-list-item--selected:not(:first)').removeClass('mdc-list-item--selected');
// remove all previous option elements
$('.mdc-list-item:not(.mdc-list-item--selected:first)').remove();
// add new option elements
$('.mdc-list-item--selected').after($select);
// start the click function, so that dropdown doesn't close
$this.click();
});
// When any option is selected, show it on input field
$(document).on('click', '.mdc-list-item:not(#no_match)', (event) => {
let $this = $(event.currentTarget);
$this.addClass('mdc-list-item--selected');
$('.mdc-floating-label').addClass('mdc-floating-label--float-above');
$('.mdc-select__anchor').addClass('demo-width-class mdc-ripple-upgraded')
$('.mdc-line-ripple').addClass('mdc-line-ripple--active mdc-line-ripple--deactivating')
$('.mdc-line-ripple').css({'transform-origin': '182px center'})
$('#food').val($this.attr('data-value'));
// return false;
// event.stopImmediatePropagation()
});
// if clicked on no match, value of input field should be empty, alternatively you can also make option disabled
$(document).on('click', '#no_match', (event) => {
$('#food').val('');
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>#sauhardnc</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.js"></script>
</head>
<body>
<div class="mdc-select">
<div class="mdc-select__anchor demo-width-class" style="width: 100%">
<i class="mdc-select__dropdown-icon"></i>
<input type="text" class="mdc-select__selected-text" id="food"></input>
<!-- Give a unique id -->
<!--<div contenteditable="true" class="mdc-select__selected-text" id="fruit"></div>-->
<span class="mdc-floating-label">Pick a Food Group</span>
<div class="mdc-line-ripple"></div>
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface demo-width-class" style="width: 100%">
<ul class="mdc-list">
<li class="mdc-list-item mdc-list-item--selected" data-value="" aria-selected="true"></li>
<li class="mdc-list-item" data-value="Bread, Cereal, Rice, and Pasta">
Bread, Cereal, Rice, and Pasta
</li>
<li class="mdc-list-item" data-value="Vegetables">
Vegetables
</li>
<li class="mdc-list-item" data-value="Fruit">
Fruit
</li>
</ul>
</div>
</div>
</body>
</html>
You need to combine the input fields along with the select to get an input field and then write some javascript to get the autocomplete functionality. You can check my solution.
console.clear();
const select = new mdc.select.MDCSelect(document.querySelector('.mdc-select'));
select.listen('MDCSelect:change', () => {
alert(`Selected option at index ${select.selectedIndex} with value "${select.value}"`);
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<link href="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.js"></script>
</head>
<body>
<div class="mdc-select">
<div class="mdc-select__anchor demo-width-class">
<i class="mdc-select__dropdown-icon"></i>
<div class="mdc-select__selected-text"></div>
<span class="mdc-floating-label">Pick a Food Group</span>
<div class="mdc-line-ripple"></div>
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface demo-width-class">
<ul class="mdc-list">
<input type="text" class="mdc-list-item--selected mdc-text-field__input" id="name-input">
<label for="name-input" class="mdc-floating-label">search....</label>
<li class="mdc-list-item" data-value="grains">
Bread, Cereal, Rice, and Pasta
</li>
<li class="mdc-list-item" data-value="vegetables">
Vegetables
</li>
<li class="mdc-list-item" data-value="fruit">
Fruit
</li>
<input type="hidden" name="input_name" value="input_value" class="my_mdc-select__value" />
</ul>
</div>
</div>
</body>
</html>
This is what I could able to achieve, hope this helps in your implementation. I have not completely implemented the filter logic and all but was able to enter input and display the dropdown simultaneously.
const menuElement = document.querySelector(".mdc-menu");
// const menu = new mdc.menu.MDCMenu(menuElement);
const inputLabel = document.querySelector(".mdc-text-field");
const inputElem = inputLabel.querySelector("input");
const dropdownIcon = document.querySelector(".mdc-select__dropdown-icon");
let isMenuOpen = false;
inputLabel.addEventListener("click", () => {
inputElem.focus();
// menu.open = true;
if (!isMenuOpen) {
menuElement.classList.remove("list-menu-close");
menuElement.classList.add("list-menu-open");
dropdownIcon.classList.add("dropdown-icon-up");
} else {
menuElement.classList.remove("list-menu-open");
menuElement.classList.add("list-menu-close");
dropdownIcon.classList.remove("dropdown-icon-up");
}
isMenuOpen = !isMenuOpen;
});
inputElem.addEventListener("blur", () => {
menuElement.classList.remove("list-menu-open");
menuElement.classList.add("list-menu-close");
dropdownIcon.classList.remove("dropdown-icon-up");
isMenuOpen = false;
});
<div class="dropdown-container">
<label class="mdc-text-field mdc-text-field--filled">
<span class="mdc-text-field__ripple"></span>
<input
class="mdc-text-field__input"
type="text"
aria-labelledby="my-label-id"
/>
<i class="mdc-select__dropdown-icon"></i>
</label>
<div>
<div class="mdc-menu mdc-menu-surface list-menu">
<ul
class="mdc-list"
role="menu"
aria-hidden="true"
aria-orientation="vertical"
tabindex="-1"
>
<li class="mdc-list-item" role="menuitem">
<span class="mdc-list-item__text">A Menu Item</span>
</li>
<li class="mdc-list-item" role="menuitem">
<span class="mdc-list-item__text">Another Menu Item</span>
</li>
</ul>
</div>
</div>
</div>
.dropdown-container {
position: relative;
}
.list-menu {
position: absolute;
top: 60px;
}
.list-menu-open {
display: block;
opacity: 1;
}
.list-menu-close {
display: none;
opacity: 0;
}
.dropdown-icon-up {
transform: rotate(180deg) translateY(-5px);
}
Based on the answers here, I created my own function. Also the Material Design for Web Versions in the answers are quite old. Hope this helps for those looking for something like this.
At first, instead of using MDCSelect, I used MDCTextField and MDCMenu components. I thought everything would be easier this way. It took some time though, but I'm done.
The function that triggers the Menu to open when clicking on the TextField may seem a bit weird. #Zachary Haber explains this,
It appears that the inconsistency is due to a race condition. Clicking
on the menu causes the focus to leave the input which causes the menu
to close. And the menu closing causes focus to move back to the input
making it open again.
The issue is that the menu often closes before the menu has a chance
to send out the selected event.
To review the original answer for MDCMenu click issue: https://stackoverflow.com/a/61965646/5698079
Here is a working example;
const textFields = document.querySelectorAll('.mdc-text-field');
textFields.forEach(field => {
mdc.textField.MDCTextField.attachTo(field);
});
const menuS = document.querySelector("#menu");
const menu = new mdc.menu.MDCMenu(menuS);
const searchFieldS = document.querySelector("#food");
menu.setAnchorCorner(mdc.menuSurface.Corner.BOTTOM_LEFT);
document.querySelectorAll('#menu li').forEach(function(li) {
li.addEventListener('click', function() {
const selectedLi = this.getAttribute("data-value");
if (selectedLi != "notfound") {
// If you are going to post the text field data, I recommend you to get data-value.
searchFieldS.value = selectedLi;
searchFieldS.setAttribute("data-value", selectedLi);
}
});
});
// Open the menu when text field is focused.
(function() {
let menuFocused = false;
searchFieldS.addEventListener("focusin", () => {
if (!menuFocused) menu.open = true;
});
searchFieldS.addEventListener("click", () => {
menu.open = true;
});
menuS.addEventListener("focusin", () => {
menuFocused = true;
});
menuS.addEventListener("focusout", () => {
// This interval is to help make sure that input.focusIn doesn't re-open the menu
setTimeout(() => {
menuFocused = false;
}, 0);
});
searchFieldS.addEventListener("focusout", () => {
setTimeout(() => {
if (!menuFocused) menu.open = false;
}, 0);
});
})();
searchFieldS.addEventListener("keyup", function(e) {
const keyT = event.target.value.toUpperCase();
const menuList = document.querySelectorAll('.mdc-deprecated-list > li > .mdc-deprecated-list-item__text');
const menuLiss = document.querySelectorAll('.mdc-deprecated-list-item');
const noDataEl = document.querySelector("#menuNoData");
//
const arr = [];
menuList.forEach(function(searchItem) {
if (searchItem.parentElement.getAttribute('id') != "menuNoData") {
searchItem.parentElement.dataset.isfound = searchItem.textContent.toUpperCase().includes(keyT) ? "true" : "false";
arr.push(searchItem.parentElement.getAttribute("data-isfound"));
}
});
if (arr.filter(function(countArr) {
return countArr == "true"
}).length == 0) {
noDataEl.classList.remove("hide-none");
} else {
if (!noDataEl.classList.contains("hide-none")) {
noDataEl.classList.add("hide-none");
}
}
});
li[data-isfound="false"] {
display: none;
}
.hide-none {
display: none !important;
}
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script src="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.js"></script>
<link href="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.css" rel="stylesheet">
<div class="mdc-menu-surface--anchor">
<label class="mdc-text-field mdc-text-field--outlined">
<span class="mdc-notched-outline">
<span class="mdc-notched-outline__leading"></span>
<span class="mdc-notched-outline__notch">
<span class="mdc-floating-label" id="my-label-id">Select a fruit..</span>
</span>
<span class="mdc-notched-outline__trailing"></span>
</span>
<input id="food" type="text" class="mdc-text-field__input" aria-labelledby="my-label-id">
</label>
<div id="menu" class="mdc-menu mdc-menu-surface mdc-menu-surface--fullwidth">
<ul class="mdc-deprecated-list" role="listbox" aria-label="Food picker listbox">
<li id="menuNoData" class="mdc-deprecated-list-item mdc-deprecated-list-item--disabled hide-none" aria-selected="false" aria-disabled="true" data-value="notfound" role="option" value="" data-value="">
<span class="mdc-deprecated-list-item__ripple"></span>
<span class="mdc-deprecated-list-item__text">No data found.</span>
</li>
<li class="mdc-deprecated-list-item" aria-selected="false" data-value="grains" role="option">
<span class="mdc-deprecated-list-item__ripple"></span>
<span class="mdc-deprecated-list-item__text">Bread, Cereal, Rice, and Pasta</span>
</li>
<li class="mdc-deprecated-list-item" aria-selected="false" data-value="vegetables" role="option">
<span class="mdc-deprecated-list-item__ripple"></span>
<span class="mdc-deprecated-list-item__text">Vegetables</span>
</li>
<li class="mdc-deprecated-list-item" aria-selected="false" data-value="fruit" role="option">
<span class="mdc-deprecated-list-item__ripple"></span>
<span class="mdc-deprecated-list-item__text">Fruit</span>
</li>
</ul>
</div>
</div>
CodePen: https://codepen.io/lastofdead/pen/bGMZPzO

slider and Ajax with images

I have a slideshow on my page where images are being changed after some time. The slideshow worked great at first until i put in JSON. Now i can see the first image only but they are not changing. Any ideas ?
https://jsfiddle.net/j2qoyk13/
There is a fiddle but as links and everything is on a localhost , it is probably useless.. You can still see the code .
Here it is for the lazy ones :)
[
{
"src" : "./images/slide-1.png",
"alt" : "Slide one"
},
{
"src" : "./images/slide-2.png",
"alt" : "Slide two"
},
{
"src" : "./images/slide-3.png",
"alt" : "Slide three"
},
{
"src" : "./images/slide-4.png",
"alt" : "Slide four"
}
]
//slide show
var slides = $('.sidenav li');
var slideIndex = 0;
var slideTime = animate();
slideTo(slides[0]);
slides.click(function() {
clearInterval(slideTime);
slideTime = animate();
var selectedIndex = $(this).index();
var slide = slides[selectedIndex];
slideTo(slide);
});
function slideTo(slide) {
slides.removeClass("selected");
$(slide).addClass("selected");
slideIndex = jQuery(slide).index();
}
function animate() {
return setInterval(function() {
var slide = slides[slideIndex];
slideTo(slide)
slideIndex++;
if (slideIndex == slides.length) {
slideIndex = 0;
}
}, 500);
}
//Json
var image = $('.sidenav li > img');
$.getJSON('http://localhost:8080/data.json', function(result){
$.each(result, function(i, field){
for (i=0 ; i < image.length ; i++) {
image.attr('src', field.src);
image.attr('alt', field.alt);
}
});
});
<section class="section-slider">
<div class="wrapper">
<div class="content">
<div class="inner-cont">
<div class="title">
<h1 class="black title-section">EXPECT NOTHING ORDINARY</h1>
</div>
<p class="txt black">
Eastern & Oriental Plc is an AIM quoted real estate company, headquartered in the United Kingdom and focused on the development of residential and mixed-use assets in the London and the South East of England.
</p>
<div class="bot-link">
VIEW OUR COMPANY PROFILE<span class="s s-right_arrow"></span>
</div>
<div class="anchor-sign">
<a class="anchor-link" href="#s-three"><span class="s s-download-arrow"></span></a>
</div>
</div>
</div>
<div class="slider">
<ul class="sidenav">
<li class="selected"><img src="" alt="Slide one"></li>
<li><img src="" alt="Slide two"></li>
<li ><img src="" alt="Slide three"></li>
<li><img src="" alt="Slide four"></li>
</ul>
</div>
</div>
</section>
The question is , of course, why are the slides not changing now when I added JSON ?
Update your JSON loop logic to this
$.getJSON('http://localhost:8080/data.json', function(result){
var i = 0;
$('.sidenav li').each(function(e){
$(this).find('img').attr('src',result[i].src);
$(this).find('img').attr('alt',result[i].alt);
i++;
});
});

Boostrap responsive grid issue with different images size

this is my Boostrap grid:
http://i59.tinypic.com/nozn12.png
Each image has different sizes, unfortunately the heightest one wraps the row leaving an empty space.
I should give the same size in each image, but I can't because this isn't a fixed layout.
Is there any fix / solution to this issue? Here's the code
<div class="row">
<div class="col-sm-6 col-md-3">
<div class="thumbnail">
<img src="temp/1.jpg" class="img-responsive">
<h4>4280 / 5PL</h4>
</div>
</div>
<div class="col-sm-6 col-md-3">
ecc.
</div>
<div class="col-sm-6 col-md-3">
ecc.
</div>
</div>
use equal height for <div class="col-sm-6 col-md-3">
$.fn.eqHeights = function(options) {
var defaults = {
child: false
};
var options = $.extend(defaults, options);
var el = $(this);
if (el.length > 0 && !el.data('eqHeights')) {
$(window).bind('resize.eqHeights', function() {
el.eqHeights();
});
el.data('eqHeights', true);
}
if( options.child && options.child.length > 0 ){
var elmtns = $(options.child, this);
} else {
var elmtns = $(this).children();
}
var prevTop = 0;
var max_height = 0;
var elements = [];
elmtns.height('auto').each(function() {
var thisTop = this.offsetTop;
if (prevTop > 0 && prevTop != thisTop) {
$(elements).height(max_height);
max_height = $(this).height();
elements = [];
}
max_height = Math.max(max_height, $(this).height());
prevTop = this.offsetTop;
elements.push(this);
});
$(elements).height(max_height);
};
// run on load so it gets the size:
// can't have the same pattern for some reason or it scans the page and makes all the same height. Each row should be separate but it doesn't work that way.
$(window).load(function() {
//$('[class*="eq-"]').eqHeights();
$('.foo [class*="eq-"]').eqHeights();
$('.foo2 [class*="eq-"]').eqHeights();
});
use <div class="row foo"> for <div class="row">
and add eq-col-sm-6 eq-col-md-3 class to all your divs with col-sm-6 col-md-3
here DEMO

Rotate image interactively

is it possible to rotate an image by mouse-click? So I´m having an image on an empty html-page and want to click and drag the image, so that it rotates around it´s center.
Do you have a code or working example?
Best regards,
Marc
Can be done using java script.Following is just a sample code.
<style type="text/css">
img.primary { display: inline; }
img.secondary { display: none; }
div.foo:hover img.secondary { display: inline; }
div.foo:hover img.primary { display: none; }
</style>
<script type="text/javascript">
function swapImages(container)
{
for(var child in container.childNodes)
{
child = container.childNodes[child];
if(child.nodeName == "IMG")
child.className = child.className == "primary" ?
"secondary" : "primary";
}
}
window.onload = function() {
// Remove the foo class when the page loads, to disable hover
var chartArea = document.getElementById("chartArea");
for(var child in chartArea.childNodes)
{
child = chartArea.childNodes[child];
if(child.nodeName == "DIV" && child.className == "foo")
child.className = "";
}
}
</script>
<div id="chartArea">
<div class="foo" onclick="swapImages(this);">
<img class="primary" src="http://somewhere/piechart1.png" />
<img class="secondary" src="http://somewhere/barchart1.png" />
</div>
<div class="foo" onclick="swapImages(this);">
<img class="primary" ... />
<img class="secondary" ... />
</div>
<div class="foo" ....>
</div>