Skip to content

Instantly share code, notes, and snippets.

@andrewgremlich
Last active November 6, 2018 18:20
Show Gist options
  • Save andrewgremlich/b89be9c8a03851b1c6bf1d6e51dad1d6 to your computer and use it in GitHub Desktop.
Save andrewgremlich/b89be9c8a03851b1c6bf1d6e51dad1d6 to your computer and use it in GitHub Desktop.
Detailed Dropdown. When some dropdowns aren't just enough, here's a detailed component dropdown for those dropdown needs
class DetailedDropDownStyles {
constructor() {
this.themeRed = '#ef4545';
this.themeRedBorder = '#c13636';
}
setStyles() {
this.searchBar.style.cssText = `
padding: 10px;
font-size: 20px;
height: 40px;
width: 200px;
border-radius: 10px;
border: 1px solid ${this.themeRed};
outline: none;`;
this.searchBar.parentElement.style.cssText = `
display: flex;
flex-direction: row;
align-items: center;`;
this.output.style.cssText = `
display: flex;
flex-wrap: wrap;
padding: 10px;
overflow: scroll;`;
this.aside.style.cssText = `
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
position: absolute;
left: 15%;
background: ${this.themeRed};
border: 1px solid ${this.themeRedBorder};
border-radius: 20px;`;
}
}
export default class DetailedDropDown extends DetailedDropDownStyles {
constructor(inputSelector, src, dataCallback, presetId = undefined) {
super();
this.fetchSrc = src;
this.searchBar = document.getElementById(inputSelector);
this.aside = document.createElement('aside');
this.output = document.createElement('div');
this.madeReferenceCards = [];
this.dataCallback = dataCallback;
this.presetId = presetId;
this.initComponent();
}
initComponent() {
this.setStyles();
this.aside.appendChild(this.output);
this.searchBar.setAttribute('incremental', '')
this.searchBar.setAttribute('type', 'search')
this.searchBar.parentNode.insertBefore(this.aside, this.searchBar.nextSibling);
this.attachEventListeners();
this.presetId && this.fetchPreSelected(this.presetId);
}
getPeopleByName(fetchSrc, name) {
return new Promise(async resolve => {
const data = await fetch(`${fetchSrc.queryAll}${name}`);
const resultNames = await data.json();
resolve(resultNames);
});
}
getSetId(fetchSrc, presetId) {
return new Promise(async resolve => {
const data = await fetch(`${fetchSrc.getOne}${presetId}`);
const resultName = await data.json();
resolve(resultName);
});
}
render() {
const maxWidth = window.innerWidth / 1.5;
const maxHeight = window.innerHeight / 1.4;
this.output.style.maxWidth = maxWidth + 'px';
this.output.style.maxHeight = maxHeight + 'px';
this.madeReferenceCards.forEach(element => {
this.output.appendChild(element);
});
}
fetchPreSelected(presetId) {
this.searchBar.setAttribute('data-form-id', presetId);
this.getSetId(this.fetchSrc, presetId).then(data => {
this.makeReferenceCards(data);
this.render();
});
}
attachEventListeners() {
this.searchBar.addEventListener('search', async () => {
const typed = this.searchBar.value;
this.output.innerHTML = '';
if (typed.length >= 2) {
this.makeReferenceCards(await this.getPeopleByName(this.fetchSrc, typed));
this.render();
} else if (typed.length < 2) {
this.searchBar.setAttribute('data-form-id', '');
}
});
}
attachCard(name) {
return evt => {
let { id } = evt.currentTarget;
this.searchBar.setAttribute('data-form-id', id);
this.searchBar.value = name;
this.output.innerHTML = '';
this.output.appendChild(evt.currentTarget);
};
}
makeReferenceCards(persons) {
this.madeReferenceCards.length = 0;
for (let person of persons) {
this.dataCallback(this.madeReferenceCards, this.attachCard(person.name), person);
}
}
}
import _ from './modules/_.js';
import DetailedDropDown from './modules/DetailedDropDown.js';
/*
#params
1. inputSelector = html ID of input[type="search"]
2. src = remote source URL
queryAll -> base URL for searching which src to get. the search term will be appended.
getOne -> base URL for searching one src. the uuid will be appended.
3. dataCallback = method to handle incoming data from src. give
cards inside the detailed dropdown.
madeCardsStash = where all the made DOM nodes will go.
attachToCard = event function handler.
Attaches a 'data-form-id' attribute to search bar element.
fills in name with name of clicked
clears output div
fills selected person to output
adds selected styling.
4. presetId = UUID of data item that has been already selected.
*/
function makeInteractiveCard(strings) {
let base = `
border-radius: 7.5px;
border: 1px solid #c13636;
margin: 10px;
padding: 10px;
${strings[0]}`;
return base;
}
const detailedDropDown = new DetailedDropDown(
'search',
{
queryAll: 'http://localhost:3000/api/get/peopleByName/',
getOne: 'http://localhost:3000/api/get/personById/'
},
(madeCardsStash, attachToCard, { name, birthDate, deathDate, email, username, profile, uuid }) => {
const referenceDiv = _.create('div'),
nameH2 = _.attachText('h2', name),
birthDateTitle = _.attachText('p', birthDate),
deathDateTitle = _.attachText('p', deathDate),
emailTitle = _.attachText('p', email),
usernameTitle = _.attachText('p', username),
profileImg = _.image(profile);
profileImg.style.cssText = `
border-radius: 7.5px;
float: left;
width: 80px;
margin-right: 10px;
margin-bottom: 5px;`;
referenceDiv.style.cssText = makeInteractiveCard``;
referenceDiv.id = uuid;
referenceDiv.addEventListener('click', attachToCard);
referenceDiv.addEventListener('mouseenter', evt => evt.currentTarget.style.cssText = makeInteractiveCard`cursor: pointer;`);
referenceDiv.addEventListener('mouseleave', evt => evt.currentTarget.style.cssText = makeInteractiveCard`cursor: none;`);
_.appendAll(referenceDiv, [profileImg, nameH2, birthDateTitle, deathDateTitle, emailTitle, usernameTitle]);
madeCardsStash.push(referenceDiv);
},
undefined
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment