Regex to validate a date - html

so basically, I am creating a booking form for a practice website. I want to validate the date so that the user can only enter a date in 2017, and cannot proceed without entering a date in 2017. They also cannot proceed without entering a valid name and email. An alert message appears if one of these is not satisfied, and the related text boxes are highlighted.
Here is what I have so far in terms of code:
Any help is appreciated, thank you.
HTML
<html>
<head>
<title> Booking </title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="styles.css">
<script>
function validate{} {
result = true;
contentUsername=booking.username.value;
if (contentUsername=="")
result=false;
}
</script>
<script>
function validate() {
result = true;
contentUsername=booking.username.value;
contentEmail=booking.email.value;
contentDate=booking.date.value;
var email = /^[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/;
var username = /^[A-Za-z]+[A-Za-z\s\.'-]+[A-Za-z]$/;
var date = /^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d).\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d).(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d).\d{2})$/;
var alertMessage="";
if (contentUsername==""){
result=false;
document.getElementById('username').style.background="lightyellow";
document.getElementById('username').style.border="solid firebrick 1px";
}
if (contentEmail=="") {
result=false;
document.getElementById('email').style.background="lightyellow";
document.getElementById('email').style.border="solid firebrick 1px";
}
if (contentDate=="") {
result=false;
document.getElementById('date').style.background"lightyellow";
document.getElementById('date').style.border="solid firebrick 1px";
}
if (!(email.test(contact.email.value)) && contact.email.value != "") {
alertMessage += contact.email.value + ' is not a valid email address.\r\n';
result=false;
}
if (!(username.test(contact.username.value)) && contact.username.value != "") {
alertMessage += contact.username.value + ' is not a valid name.\r\n';
result=false;
}
if (!(date.test(contact.date.value)) && contact.date.value != "") {
alertMessage += contact.date.value + ' is not a valid date. Please select a date in 2017.\r\n';
result=false;
}
if (!result) {
alertMessage += "Please fill out the highlighted fields";
alert(alertMessage);
}
return result;
}
</script>
</head>
<body>
<div id="header">
<div id="branding">
<img src="Images/logo.png">
</div><!-- end of "logo" -->
<div id="tagline">
<p> Welcome to yourday.com - We hope you enjoy your visit!
<br> This is where you can book an appointment with one of our agents!
<br> Please note: Dates for 2016 are fully booked. Next available appointments are in 2017. We apologies for any inconvenience caused.</p>
</div><!-- end of "tagline" -->
</div><!-- end of "header" -->
<div id="bodycontent4">
<form action="http://www.rebol.com/cgi-bin/test-cgi.cgi" method="post" class="booking" id="booking" onsubmit="return validate()">
<fieldset>
<legend>Booking</legend>
<label for="username">Name: </label>
<input type="text" name="username" id="username"></br>
<label for="email">E-mail:</label>
<input type="text" name="email" id="email"></br>
<label for="date">Date:</label>
<input type="date" name="date" id="date"></br>
<label for="location">Location:</label>
<select>
<option value="manor">Uppercourt Manor</option>
<option value="killruddery">Killrudderry</option>
<option value="carriage">The Carriage Rooms</option>
<option value="coolclogher">Coolclogher House</option>
</select>
</fieldset>
<input type="submit" value="Submit">
</form>
</div><!--end of "bodycontent" -->
<div id="navigation">
<ul class="topnav" id="TopNav">
<li>Home</li>
<li>Locations</li>
<li>Booking</li>
<li>Testimonials</li>
<li>Contact Us</li>
<li>About</li>
</li>
</ul>
</div> <!--end of "navigation" -->
<div id="footer" style = "position: absolute; top: 550px;">
<p>Created by: Calvin Leong</p>
<p>Contact information: calvin.leong#CLDesign.com</p>
</div>
</body>
</html>
CSS
/* Booking Form */
form.booking label {
display: block;
width: 100px;
float: left;
font-weight: bold;
font-size: small;
color: black;
line-height: 150%
}
form.booking fieldset {
border: 2px solid red;
padding: 10px;
}
form.booking legend {
font-weight: bold;
font-size: small;
color: black;
padding: 5px;
}
#bodycontent4 {
position: absolute;
top: 270px;
width: 25%;
left: 500px;
}
#div {
margin: 0 auto;
}

You could do like this:
var date = new Date("01/01/2017");
var year = date.getFullYear();
if(year == 2017){
alert(year);
}else{
alert("crap");
}

Here is your regex for date:
var date = /^2017-\d{2}-\d{2}$/;
And, here is the working link: http://jsbin.com/getunisagi

Related

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

How to make the text following text Bold?

So I was adding the blinking text widget in the sidebar of my website.
I am using the following code to do it,
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Blink Text using JavaScript</title></style>
<script language="javascript">
setInterval(blinktext, 500);
var txt = "";
var count = 0;
function blinktext() {
var cntrl = document.getElementById("txtblinkingtext");
if (count == 0)
txt = cntrl.value;
if (count % 2 == 0)
cntrl.value = "";
else
cntrl.value = txt;
count++;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div style="margin: auto; text-align: center;">
<input type="text" id="txtblinkingtext" name="txtblinkingtext" value="NEWS STREAM"
readonly="readonly" style="height: 20px; width: 300px; background-color: #E64946;
color: White; border: 0px none; text-align: center;">
</div>
</form>
</body>
</html>
I just wanted to know how to use Bold or Strong method on "NEWS STREAM" text value
You have a </style> tag hanging, remove it.
In your input style, add font-weight:bold. But, you'd rather have a CSS file with that rather than style in the HTML like this, it's not too pretty.

Footer covers my content when using w3.css

I am trying out w3.css for styling, along with knockout, and when I use a footer, it covers the content near the bottom of the page.
I have a button at the bottom of my content. When the page resizes or is small enough, the footer covers the button.
See codepen, or the code below
function setting(color) {
this.color = ko.observable(color);
this.colorClassName = ko.computed(function() {
return "w3-hover-" + this.color();
}, this);
}
function myInput() {
this.data = ko.observable("");
this.nameValid = ko.computed(function() {
return !(this.data() == null || this.data().length == 0);
}, this);
this.error = ko.computed(function() {
//if (this.data() == null || this.data().length == 0)
if (this.nameValid() == false) {
return "Enter name";
} else {
return "";
}
}, this);
this.display = ko.computed(function() {
if (this.nameValid() == false) {
return "block";
} else {
return "none";
}
}, this);
this.ageData = ko.observable();
this.ageValid = ko.computed(function() {
var age = this.ageData() + "";
var patt = new RegExp(/^[0-9]+$/g); /// ^-from start, $-to end, [0-9] - 0 to 9 numbers only
var res = patt.test(age);
if (isNaN(age) == true || res == false) {
return false;
} else {
return true;
}
}, this);
this.ageError = ko.computed(function() {
if (this.ageValid() == false) {
return "Enter a valid age";
} else {
return "";
}
}, this);
this.ageDisplay = ko.computed(function() {
if (this.ageValid() == true) {
return "none";
} else {
return "block";
}
}, this);
this.phone = ko.observable('http://digitalbush.com/projects/masked-input-plugin/');
this.allValid = ko.computed(function() {
return this.ageValid() && this.nameValid();
}, this);
}
function myModel() {
this.name = "Ice-Cream";
this.items = [{
name: "Chocolate",
price: 10
}, {
name: "Vanilla",
price: 12
}];
this.style = new setting('pale-green');
this.input = new myInput();
this.changeColor = function() {
if (this.style.color().indexOf('blue') == -1) {
this.style.color('pale-blue');
} else {
this.style.color('pale-green');
}
};
}
ko.applyBindings(new myModel());
<script type='text/javascript' src='http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js'></script>
<link href="http://www.w3schools.com/lib/w3.css" rel="stylesheet" type="text/css">
<body class="w3-content w3-pale-blue" style="max-width:100%">
<header class="w3-container w3-pale-green w3-border">
<h1>Hello</h1>
</header>
<div class="w3-container w3-pale-yellow w3-border w3-padding-hor-16 w3-content" style="max-width:100%">
W3.CSS
<p>
The item is <span data-bind="text: name"></span> today.
<br />Available flavours are:
</p>
<div class="w3-container">
<ul data-bind="foreach: items" class="w3-ul w3-left w3-border w3-border-red">
<li class="w3-ul w3-hoverable w3-border-red " data-bind="css: $parent.style.colorClassName()">
<span data-bind="text: name"></span> is $<span data-bind="text:price" />
</li>
</ul>
</div>
<label class="w3-label w3-text-blue w3-xlarge">Name</label>
<input class="w3-input w3-border" type="text" data-bind="textInput: input.data">
<label class="w3-label w3-text-red w3-large" data-bind="text: input.error(), style: { display: input.display()}"></label>
<br />
<label class="w3-label w3-text-blue w3-xlarge">Age</label>
<input class="w3-input w3-border" type="text" data-bind="textInput: input.ageData">
<label class="w3-label w3-text-red w3-large" data-bind="text: input.ageError(), style: { display: input.ageDisplay()}"></label>
<br />
<label class="w3-label w3-text-blue w3-xlarge">Phone</label>
<input class="w3-input w3-border" type="text" data-bind="textInput: input.phone">
<!--<label class="w3-label w3-text-red w3-large" data-bind="text: input.phoneError(), style: { display: input.phoneDisplay()}"></label>-->
<br />
<button class="w3-btn w3-border w3-border-teal w3-round w3-teal" data-bind="click: changeColor, enable: input.allValid()">Test</button>
</div>
<footer class="w3-light-grey w3-bottom">
<div class="w3-container">
<p>This is my footer</p>
</div>
</footer>
My solution was to add another div element with the same content as my footer, but make it invisible. This way it will fill the space behind the real footer.
In the code i above i will add the following
<div class="w3-container" style="opacity:0">
<p>This is my footer</p>
</div>
The updated codepen shows the solution.
The elements .w3-top, .w3-bottom have a position of :fixed, so they're always going to stick to the page.
Remove this from their stylesheet or add an alternative to your own.
E.g.
.w3-bottom {
position: static;
}
The class of your footer is w3-bottom, and by defaut, its position is fixed, so you need to change it to relative:
.w3-bottom {
position: relative !important;
}
Another way could be to place the "button" in its own "div" to better control its attributes, remove the "div" from the footer and the bottom class. Something like:
<div class="w3-container w3-padding-bottom-32">
<button class="w3-btn w3-border w3-border-teal w3-round w3-teal" data-bind="click: changeColor, enable: input.allValid()">Test</button>
</div>
<footer class="w3-container w3-light-grey">
<p>This is my footer</p>
</footer>
Please let me know if it works for you.
Kindly, Edwin
Try to use the styles from Sticky footer example from the bootstrap.
But this method have one disadvantage: footer have fixed height :(
Example:
/* Sticky footer styles
-------------------------------------------------- */
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 80px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
overflow: hidden;
/* Set the fixed height of the footer here */
height: 80px;
background-color: #f5f5f5;
}
<!DOCTYPE html>
<html>
<title>W3.CSS</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://www.w3schools.com/lib/w3.css">
<body>
<div class="w3-container w3-teal">
<h1>Header</h1>
</div>
<div class="w3-container">
<p>The w3-container class can be used to display headers.</p>
</div>
<div class="footer w3-container w3-teal">
<h5>Footer</h5>
<p>Footer information goes here</p>
</div>
</body>
</html>

CSS won't work on label

As my title says I have no clue why the CSS will work on everything but the label tag.
Here is my code for file register:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
<center> <b> Registration Page </b> </center>
</head>
<br>
<body>
<img src = "website_demo_pic_1.jpg" />
<ul class = "SiteMap">
<li> <a href = "index.html" >Home Page</a>
<br>
<li><a href = "register.html" >Register</a>
<br>
<li><a href = "login.html" >Log In</a>
<br>
</ul>
<form id = "Form1" action = "submit.php" method = "post">
<p class="whitetext"><label for = "username">Username :</label>
<input type = "text" name = "Username" id="username"></p>
<p class="whitetext"><label for = "password">Password :</label>
<input type = "password" name = "Password" id="password"></p>
</form>
</body>
</html>
Here is my code for login:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
<center> <b> Log In Page </b> </center>
</head>
<br>
<body>
<img src = "website_demo_pic_1.jpg" />
<ul class = "SiteMap">
<li> <a href = "index.html" >Home Page</a>
<br>
<li><a href = "register.html" >Register</a>
<br>
<li><a href = "login.html" >Log In</a>
<br>
</ul>
<form id = "Form2" action = "submit.php" method = "post">
<label for = "username2">Username :</label>
<input type = "text" name = "Username" id="username2">
<br>
<label for = "password2">Password :</label>
<input type = "password" name = "Password" id="password2">
<br>
</form>
</body>
</html>
Here is my CSS file:
img
{
width: 100%;
}
body
{
background-color: black;
}
label
{
width: 4em;
float: left;
text-align: right;
margin-right: 0.5em;
display: block
}
p.whitetext
{
color: white;
}
ul.SiteMap
{
float: left;
}
As far as I can tell the code is right yet the text boxes wont line up meaning that something weird is going on with label.
Here's a jsFiddle with your code, slightly modified: http://jsfiddle.net/MzsWH/
<img src = "website_demo_pic_1.jpg" />
<ul class = "SiteMap">
<li> <a href = "index.html" >Home Page</a>
<br>
<li><a href = "register.html" >Register</a>
<br>
<li><a href = "login.html" >Log In</a>
<br>
</ul>
<form id = "Form2" action = "submit.php" method = "post">
<label for = "username2">Username :</label>
<input type = "text" name = "Username" id="username2">
<br>
<label for = "password2">Password :</label>
<input type = "password" name = "Password" id="password2">
<br>
</form>
<STYLE>
img{
width: 100%;
border:1px solid #333;
height:40px;
}
body{
background-color: #CCC;
}
label {
/*width: 4em;*/
width:6em;
float: left;
text-align: right;
margin-right: 0.5em;
display: block
}
p.whitetext{
color: white;
}
ul.SiteMap{
float: left;
border:1px solid #666;
}
</STYLE>
The only thing I see regarding your LABEL attribute is that your width for the labels are too small. The text inside the label is longer the width, which is causing it to wrap, and make everything look weird.
All I did was change the width from 4em to 6em.
Second of all, your HTML has some issues. There's a CENTER tag in your HEAD tag, did you mean TITLE? Also, there are line break BR tags between list element (LI) tags. I would recommend as Shaquin said in his comment, run your page through the W3C validator so you can help update your HTML.
I hope that helps!
Cheers!

Change default text in input type="file"?

I want to change default text on button that is "Choose File" when we use input="file".
How can I do this? Also as you can see in image button is on left side of text. How can I put it on right side of text?
Use the for attribute of label for input.
<div>
<label for="files" class="btn">Select Image</label>
<input id="files" style="visibility:hidden;" type="file">
</div>
Below is the code to fetch name of the uploaded file
$("#files").change(function() {
filename = this.files[0].name;
console.log(filename);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<label for="files" class="btn">Select Image</label>
<input id="files" style="visibility:hidden;" type="file">
</div>
I think this is what you want:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button style="display:block;width:120px; height:30px;" onclick="document.getElementById('getFile').click()">Your text here</button>
<input type='file' id="getFile" style="display:none">
</body>
</html>
Each browser has it's own rendition of the control and as such you can't change either the text or the orientation of the control.
There are some "kind of" hacks you may want to try if you want an html/css solution rather than a Flash or silverlightsolution.
http://www.quirksmode.org/dom/inputfile.html
http://www.shauninman.com/archive/2007/09/10/styling_file_inputs_with_css_and_the_dom
Personally, because most users stick to their browser of choice, and therefore are probably used to seeing the control in the default rendition, they'd probably get confused if they saw something different (depending on the types of users you're dealing with).
This might help someone in the future, you can style the label for the input as you like and put anything you want inside it and hide the input with display none.
It works perfectly on cordova with iOS
<link href="https://cdnjs.cloudflare.com/ajax/libs/ratchet/2.0.2/css/ratchet.css" rel="stylesheet"/>
<label for="imageUpload" class="btn btn-primary btn-block btn-outlined">Seleccionar imagenes</label>
<input type="file" id="imageUpload" accept="image/*" style="display: none">
To achieve this, the default input button must be hidden using display:none CSS property and a new button element is added to replace it, so we can customize as we wish.
With Bootstrap
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
Optional text here
<label for="img" class="btn btn-info">Try me</label>
<input type="file" id="img" style="display:none">
With jQuery
In this case the onclick attribute added to the button element is indicating to JavaScript to click on the hidden default input button whenever the visible button is clicked.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Optional text here
<button style="cursor:pointer" onclick="$('#input').click()">Click me</button>
<input type="file" id="input" style="display:none">
Plain JavaScript with event listener
document.getElementById('btn').addEventListener('click', () => {
document.getElementById('input').click();
})
Optional text here
<button style="cursor:pointer" id="btn">Click me</button>
<input type="file" id="input" style="display:none">
It is not possible. Otherwise you may need to use Silverlight or Flash upload control.
$(document).ready(function () {
$('#choose-file').change(function () {
var i = $(this).prev('label').clone();
var file = $('#choose-file')[0].files[0].name;
$(this).prev('label').text(file);
});
});
.custom-file-upload{
background: #f7f7f7;
padding: 8px;
border: 1px solid #e3e3e3;
border-radius: 5px;
border: 1px solid #ccc;
display: inline-block;
padding: 6px 12px;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
can you try this
<label for="choose-file" class="custom-file-upload" id="choose-file-label">
Upload Document
</label>
<input name="uploadDocument" type="file" id="choose-file"
accept=".jpg,.jpeg,.pdf,doc,docx,application/msword,.png" style="display: none;" />
The trick is to trigger a click event on click of the file input and manage the visibility of the default input file via CSS. Here's how you can do it:
jQuery:
$(function() {
$("#labelfile").click(function() {
$("#imageupl").trigger('click');
});
})
css
.file {
position: absolute;
clip: rect(0px, 0px, 0px, 0px);
display: block;
}
.labelfile {
color: #333;
background-color: #fff;
display: inline-block;
margin-bottom: 0;
font-weight: 400;
text-align: center;
vertical-align: middle;
cursor: pointer;
background-image: none;
white-space: nowrap;
padding: 6px 8px;
font-size: 14px;
line-height: 1.42857143;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
HTML code:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>
<input name="imageupl" type="file" id="imageupl" class="file" />
<label class="labelfile" id="labelfile"><i class="icon-download-alt"></i> Browse File</label>
</div>
I made a script and published it at GitHub: get selectFile.js
Easy to use, feel free to clone.
HTML
<input type=file hidden id=choose name=choose>
<input type=button onClick=getFile.simulate() value=getFile>
<label id=selected>Nothing selected</label>
JS
var getFile = new selectFile;
getFile.targets('choose','selected');
DEMO
jsfiddle.net/Thielicious/4oxmsy49/
Update 2017:
I have done research on how this could be achieved. And the best explanation/tutorial is here:
https://tympanus.net/codrops/2015/09/15/styling-customizing-file-inputs-smart-way/
I'll write summary here just in case it becomes unavailable. So you should have HTML:
<input type="file" name="file" id="file" class="inputfile" />
<label for="file">Choose a file</label>
Then hide the input with CSS:
.inputfile {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;}
Then style the label:
.inputfile + label {
font-size: 1.25em;
font-weight: 700;
color: white;
background-color: black;
display: inline-block;
}
Then optionally you can add JS to display the name of the file:
var inputs = document.querySelectorAll( '.inputfile' );
Array.prototype.forEach.call( inputs, function( input )
{
var label = input.nextElementSibling,
labelVal = label.innerHTML;
input.addEventListener( 'change', function( e )
{
var fileName = '';
if( this.files && this.files.length > 1 )
fileName = ( this.getAttribute( 'data-multiple-caption' ) || '' ).replace( '{count}', this.files.length );
else
fileName = e.target.value.split( '\\' ).pop();
if( fileName )
label.querySelector( 'span' ).innerHTML = fileName;
else
label.innerHTML = labelVal;
});
});
But really just read the tutorial and download the demo, it's really good.
This should work:
input.*className*::-webkit-file-upload-button {
*style content..*
}
Here is how its done with bootstrap, only u should put the original input somewhere...idk
in head and delete the < br > if you have it, because its only hidden and its taking space anyway :)
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<label for="file" button type="file" name="image" class="btn btn-secondary">Secondary</button> </label>
<input type="file" id="file" name="image" value="Prebrskaj" style="visibility:hidden;">
<footer>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</footer>
Using Bootstrap you can do this thing like the below code.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.btn-file {
position: relative;
overflow: hidden;
}
.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 100px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
outline: none;
background: white;
cursor: inherit;
display: block;
}
</style>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<span class="btn btn-file">Upload image from here<input type="file">
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button style="display:block;width:120px; height:30px;" onclick="document.getElementById('getFile').click()">Your text here</button>
<input type='file' id="getFile" style="display:none">
</body>
</html>
I'd use a button to trigger the input:
<button onclick="document.getElementById('fileUpload').click()">Open from File...</button>
<input type="file" id="fileUpload" name="files" style="display:none" />
Quick and clean.
You can use this approach, it works even if a lot of files inputs.
const fileBlocks = document.querySelectorAll('.file-block')
const buttons = document.querySelectorAll('.btn-select-file')
;[...buttons].forEach(function (btn) {
btn.onclick = function () {
btn.parentElement.querySelector('input[type="file"]').click()
}
})
;[...fileBlocks].forEach(function (block) {
block.querySelector('input[type="file"]').onchange = function () {
const filename = this.files[0].name
block.querySelector('.btn-select-file').textContent = 'File selected: ' + filename
}
})
.btn-select-file {
border-radius: 20px;
}
input[type="file"] {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="file-block">
<button class="btn-select-file">Select Image 1</button>
<input type="file">
</div>
<br>
<div class="file-block">
<button class="btn-select-file">Select Image 2</button>
<input type="file">
</div>
My solution...
HTML :
<input type="file" id="uploadImages" style="display:none;" multiple>
<input type="button" id="callUploadImages" value="Select">
<input type="button" id="uploadImagesInfo" value="0 file(s)." disabled>
<input type="button" id="uploadProductImages" value="Upload">
Jquery:
$('#callUploadImages').click(function(){
$('#uploadImages').click();
});
$('#uploadImages').change(function(){
var uploadImages = $(this);
$('#uploadImagesInfo').val(uploadImages[0].files.length+" file(s).");
});
This is just evil :D
Ok so very simple pure css way of creating your custom input file.
Use labels, but as you know from previous answers, label doesn't invoke onclick
function in firefox, may be a bug but doesn't matter with the following.
<label for="file" class="custom-file-input"><input type="file" name="file" class="custom-file-input"></input></label>
What you do is style the label to look how you want it to
.custom-file-input {
color: transparent;/* This is to take away the browser text for file uploading*/
/* Carry on with the style you want */
background: url(../img/doc-o.png);
background-size: 100%;
position: absolute;
width: 200px;
height: 200px;
cursor: pointer;
top: 10%;
right: 15%;
}
now simply hide the actual input button, but you cant set it to to visability: hidden
So make in invisible by setting opacity: 0;
input.custom-file-input {
opacity: 0;
position: absolute;/*set position to be exactly over your input*/
left: 0;
top: 0;
}
now as you might have noticed i have the same class on my label as i do my input field, that is because i want the to both have the same styling, thus where ever you click on the label, you are actually clicking on the invisible input field.
I build a script that can be easier to do that.
For example:
<input data-com="fileBtn" placeholder="Select Image">
basically, my script is very similar to this link
Code
Pure javascript, no dependencies needed
<!-- bootstrap.min.css not necessary -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.0/css/bootstrap.min.css">
<input data-com="fileBtn" placeholder="Select Image"> <!-- com: components -->
<input data-com="fileBtn" placeholder="Select File">
<div class="mt-2">
<input id="build-by-myself" placeholder="Select Video" accept="video/mp4, video/webm">
<div>
<script>
// 👇 Test
(()=>{
window.onload = () =>{
// FileButton.className ="btn btn-danger"
FileButton.BuildAll() // auto build all data-com="fileBtn"
// or you can specify the target that you wanted.
new FileButton(document.getElementById("build-by-myself"), "btn btn-danger")
}
})()
// 👇 script begin
class FileButton {
static className = "btn btn-primary"
static BuildAll() {
document.querySelectorAll(`input[data-com="fileBtn"]`).forEach(input=>{
new FileButton(input, FileButton.className)
})
}
/**
* #param {HTMLInputElement} input
* #param {string} btnClsName
* */
constructor(input, btnClsName) {
input.style.display = "none" // [display is better than visibility](https://stackoverflow.com/a/48495293/9935654)
input.type = "file"
const frag = document.createRange().createContextualFragment(`<button class="${btnClsName}">${input.placeholder}</button>`)
const button = frag.querySelector(`button`)
input.parentNode.insertBefore(frag, input)
button.onclick = ()=>{
input.click()
}
input.addEventListener(`change`, (e)=>{
// create a textNode to show the file name.
const file = input.files[0]
if (file === undefined) {
return
}
const textNode = document.createTextNode(file.name)
if (button.textNode) { // create a new attribute to record previous data.
button.textNode.remove()
}
button.textNode = textNode
button.parentNode.insertBefore(textNode, input)
})
}
}
</script>
Reference
What is the difference between visibility:hidden and display:none?
data-*
Below is an example of a stylized upload button that will read an image, compress it, and download the resulting image. It works by hiding the actual input element, and then through some trickery we make it so that when you click on our fake file uploader it uses the actual input element to pop up the window for choosing a file. By using this method we get 100% control over how the file uploader looks since we are using our own element instead of styling the file upload menu. It also makes it easy to add drag and drop functionality in the future if we ever want to do that.
And then I actually created a series of blog posts about this file upload button.
'use strict'
var AMOUNT = 10
var WIDTH = 600
var HEIGHT = 400
var canvas = document.getElementById('canvas')
canvas.width = WIDTH
canvas.height = HEIGHT
//here's how I created the clickable area
//user clicks the clickable area > we send a click event
//to the file opener > the file opener clicks on the open
//file button > the open file dialogue pops up
function clickableAreaListener(e){
let clickEvent = new CustomEvent("click",{"from":"fileOpenerHandler"});
document.getElementById("fileOpener").dispatchEvent(clickEvent);
}
function fileOpenerListener(e) {
document.getElementById("file-btn").click();
e.preventDefault();
}
function fileSelectedListener(e){
readFiles(e.target.files);
}
document.getElementById('file-btn').addEventListener('change', fileSelectedListener);
document.getElementById("clickable-area").addEventListener('click', clickableAreaListener);
document.getElementById("fileOpener").addEventListener("click", fileOpenerListener);
function readFiles(files){
files = [].slice.call(files); //turning files into a normal array
for (var file of files){
var reader = new FileReader();
reader.onload = createOnLoadHandler(file);
reader.onerror = fileErrorHandler;
//there are also reader.onloadstart, reader.onprogress, and reader.onloadend handlers
reader.readAsDataURL(file);
}
}
function fileErrorHandler(e) {
switch(e.target.error.code) {
case e.target.error.NOT_FOUND_ERR:
throw 'Image not found';
break;
case e.target.error.NOT_READABLE_ERR:
throw 'Image is not readable';
break;
case e.target.error.ABORT_ERR:
break;
default:
throw 'An error occurred while reading the Image';
};
}
function createOnLoadHandler(file){
console.log('reading ' + file.name + ' of type ' + file.type) //file.type will be either image/jpeg or image/png
function onLoad(e){
var data = e.target.result
display(data);
var compressedData = compressCanvas(AMOUNT)
download(compressedData)
}
return onLoad
}
function display(data){
var img = document.createElement('img');
img.src = data;
var context = canvas.getContext('2d')
context.clearRect(0, 0, WIDTH, HEIGHT);
context.drawImage(img, 0, 0, WIDTH, HEIGHT);
}
function compressCanvas(){
return canvas.toDataURL('image/jpeg', AMOUNT / 100);
}
function download(data) {
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
var chromeApp = Boolean(chrome && chrome.permissions)
if (chromeApp){
chrome.fileSystem.chooseEntry({type:'openDirectory'}, function(entry) {
chrome.fileSystem.getWritableEntry(entry, function(entry) {
entry.getFile('example.jpg', {create:true}, function(entry) {
entry.createWriter(function(writer){
writer.write(b64toBlob(data.slice(23), 'image/jpg'))
})
})
})
})
} else {
let a = document.createElement("a");
a.href = data;
a.download = 'downloadExample.jpg'
document.body.appendChild(a)
a.click();
window.URL.revokeObjectURL(a.href);
a.remove()
}
}
.fileInput {
display: none;
position: absolute;
top: 0;
right: 0;
font-size: 100px;
}
#clickable-area{
background: #ccc;
width: 500px;
display: flex;
margin-bottom: 50px;
}
#clickable-area-text{
margin: auto;
}
.yellow-button {
cursor: pointer;
color: white;
background: #f1c40f;
height: 30px;
width: 120px;
padding: 30px;
font-size: 22px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
<div id="clickable-area">
<a id='fileOpener'> </a>
<input type="file" class="fileInput" id="file-btn" accept="image/*" multiple/>
<div class="yellow-button"><span>Shrink Image</span>
</div><p id="clickable-area-text">( you can click anywhere in here ) </p>
</div>
<canvas id="canvas"></canvas>
Stack Overflow limitations seem to prevent the code snippet from actually compressing and downloading the file. The exact same code here shows that the full upload/compress/download process does actually work as intended.
With answers from this question, I fixed what many in coments said doesn¨t work for them which is that it's not showing how many files user chose.
<label for="uploadedFiles" class="btn btn-sm btn-outline-primary">Choose files</label>
<input type="file" name="postedFiles" id="uploadedFiles" multiple="multiple" hidden onchange="javascript:updateList()" />
<input class="btn btn-primary mt-2 btn-action" type="submit" value="Send" formmethod="post" formaction="#Url.Action("Create")" /><br />
<span id="selected-count">Selected files: 0</span>
<script>
updateList = function () {
var input = document.getElementById('uploadedFiles');//list of files user uploaded
var output = document.getElementById('selected-count');//element displaying count
output.innerHTML = 'Selected files: ' + input.files.length;
}
</script>
You can easily improve it by showing names of files instead or whatever you wish to do but all I wanted was to inform user that they have already picked files.
You can use a simple button and hide input file
using jquery and bootstrap :
HTML code
<button class="btn btn-white" id="btn-file" type="button"><i class="fa fa-file-pdf"></i> Anexar Documento</button>
<input name="shutdown" id="input-file" type="file" class="form-control hidden" accept="application/pdf, image/png, image/jpeg">
CSS :
.hidden{display:none}
JS :
$("#btn-file").click(function () {
$("#input-file").trigger('click');
});
$("#input-file").change(function () {
var file = $(this)[0].files[0].name;
$("#btn-file").html('<i class="fa fa-file-pdf"></i> ' + file);
});