var app = angular.module('app', ['thegitfather.flabel']);
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>angular-flabel demo</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="angular-flabel.css" />
<script data-require="angular.js@1.5.x" src="https://code.angularjs.org/1.5.3/angular.js" data-semver="1.5.3"></script>
<script src="app.js"></script>
<script src="angular-flabel.js"></script>
</head>
<body>
<div class="panel panel-primary">
<div class="panel-heading">
<h1>angular-flabel demo</h1>
<code>(v0.0.2)</code>
</div>
<div class="panel-body">
<form class="form-vertical" novalidate>
<div class="form-group">
<input id="emailInput" type="email" class="form-control" placeholder="Email address (e.g. peter.smith@example.com)" name="emailInput" required
ng-model="emailInput"
flabel="Your Email" />
</div>
<div class="form-group huge-label-font-size">
<input id="inputHugeLabel" type="text" class="form-control" placeholder="Placeholder..." name="inputHugeLabel" required
ng-model="inputHugeLabel"
flabel="Label with huge font size" />
</div>
<div class="form-group">
<input id="inputLongLabel" type="text" class="form-control" placeholder="A very long label text" name="inputLongLabel" required
ng-model="inputLongLabel"
flabel="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore Duis aute irure dolor in reprehenderit in voluptate velit" />
</div>
<div class="form-group">
<select id="selectFruit" class="form-control" name="selectFruit" required
ng-model="selectFruit"
flabel="Your flavor">
<option value="" disabled>Select your favorite flavor</option>
<option value="1">Banana</option>
<option value="2">Chocolate</option>
<option value="3">Cherry</option>
</select>
</div>
<div class="form-group">
<textarea class="form-control" placeholder="Enter your message here..." id="textarea"
ng-model="textareaMessage"
flabel="Your Message"></textarea>
</div>
<div class="form-group huge-label-font-size">
<input type="text" class="form-control" name="noLabel" required
ng-model="noLabel"
flabel />
</div>
</form>
</div>
</div>
</body>
</html>
'use strict';
angular.module('thegitfather.flabel', [])
.directive('flabel', function() {
return {
scope: {},
require: 'ngModel',
restrict: 'A',
link: function(scope, element, attrs, controller) {
var flabelText = "";
var $flabelContainer = element.parent();
var $flabel = angular.element('<label class="flabel"></label>');
flabelText = getLabelText();
if (!flabelText) {
console.info("no label text found for:", element);
return; // aborting here
}
// set 'for' attribute if element has id
if (attrs.id !== undefined && attrs.id.length) {
$flabel.attr("for", attrs.id);
}
$flabel.text(flabelText);
$flabelContainer.addClass('flabeled');
element.parent().prepend($flabel);
scope.flabelCtrl = controller;
scope.$watch('flabelCtrl.$modelValue', checkValueLength);
scope.$watch('flabelCtrl.$viewValue', checkValueLength);
function toggleFlabel(show) {
if (show) {
if (!$flabelContainer.hasClass('flabel-visible')) {
$flabelContainer.removeClass('flabel-hidden');
$flabelContainer.addClass('flabel-visible');
}
} else {
$flabelContainer.removeClass('flabel-visible');
$flabelContainer.addClass('flabel-hidden');
}
}
function getLabelText() {
if (attrs.flabel.length) {
return attrs.flabel;
} else if (attrs.placeholder !== undefined && attrs.placeholder.length) {
return attrs.placeholder;
} else {
return false;
}
}
function checkValueLength(newValue) {
if (newValue !== undefined && newValue.length > 0) {
toggleFlabel(true);
} else {
toggleFlabel(false);
}
}
}
};
});
body {
padding: 1em;
}
.panel {
max-width: 480px;
min-width: 320px;
margin: 20px auto;
}
form {
padding: 1em 0.5em;
}
.tiny-label-font-size {
font-size: 11px;
}
.huge-label-font-size {
font-size: 28px;
}
label {
color: #555;
font-weight: normal;
}
input[type="text"], input[type="email"], input[type="number"], textarea {
font-family: monospace;
}
.panel-heading {
position: relative;
}
.panel-heading h1 {
margin: 0;
font-size: 16px;
}
.panel-heading code {
position: absolute;
top: 0;
right: 0;
display: inline-block;
font-size: 80%;
color: #fff;
background-color: #659BC9;
}
.flabeled {
position: relative;
}
.flabeled label.flabel {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
padding: 0;
margin: 0;
max-height: 0;
opacity: 0;
line-height: 1em;
position: relative;
z-index: 2;
transition: all ease 0.2s, opacity ease 0.4s;
}
.flabeled input, .flabeled textarea {
position: relative;
z-index: 1;
transition: all ease 0.1s;
}
.flabel-visible label.flabel {
margin-bottom: 4px;
max-height: 100%;
opacity: 1;
-webkit-animation: 0.3s bounceInUp;
animation: 0.3s bounceInUp;
pointer-events: auto;
}
.flabel-hidden label.flabel {
opacity: 0;
pointer-events: none;
}
@-webkit-keyframes bounceInUp {
from, 60%, 75%, 90%, to {
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
from {
-webkit-transform: translate3d(0, 10em, 0);
transform: translate3d(0, 10em, 0);
}
60% {
-webkit-transform: translate3d(0, -0.6em, 0);
transform: translate3d(0, -0.6em, 0);
}
75% {
-webkit-transform: translate3d(0, 0.33em, 0);
transform: translate3d(0, 0.33em, 0);
}
90% {
-webkit-transform: translate3d(0, -0.15em, 0);
transform: translate3d(0, -0.15em, 0);
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
@keyframes bounceInUp {
from, 60%, 75%, 90%, to {
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
from {
-webkit-transform: translate3d(0, 10em, 0);
transform: translate3d(0, 10em, 0);
}
60% {
-webkit-transform: translate3d(0, -0.6em, 0);
transform: translate3d(0, -0.6em, 0);
}
75% {
-webkit-transform: translate3d(0, 0.33em, 0);
transform: translate3d(0, 0.33em, 0);
}
90% {
-webkit-transform: translate3d(0, -0.15em, 0);
transform: translate3d(0, -0.15em, 0);
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}