Skip to content

Instantly share code, notes, and snippets.

@CarsonMcKinstry
Created July 14, 2017 13:16
Show Gist options
  • Select an option

  • Save CarsonMcKinstry/d55d98a4dc2cdac9635ff3ad74fdc3e4 to your computer and use it in GitHub Desktop.

Select an option

Save CarsonMcKinstry/d55d98a4dc2cdac9635ff3ad74fdc3e4 to your computer and use it in GitHub Desktop.
jwdqmd
<div ng-app="myApp" ng-controller="myController" ng-cloak >
<form autocomplete="off">
<div class="input" ng-click="setFocus()">
<ul class="tokens">
<li arrow-lr class="token" ng-repeat="company in selected | limitTo:screenLimit" ng-click="removeThisCompany(company.id)" ng-keydown="removeFocused(this, $event)" data-tooltip="{{company.name}}" tabindex="-1">{{company.name | myFilter }}</li>
<li arrow-lr ng-if="selected.length > screenLimit" class="leftovers" tabindex="-1">
{{selected.length - screenLimit}} more...
<ul>
<li class="leftover" ng-repeat="company in selected | startFrom: screenLimit" ng-click="removeThisCompany(company.id)">
{{company.name}}
</li>
</ul>
</li>
</ul>
<!-- <p ng-repeat="company in selected | startFrom : screenLimit">{{company.name}}</p> -->
<input type="text" ng-model="companyFilter" ng-change="filterCompanies()" id="company-input" placeholder="Enter a company..." ng-keydown="focusSelected($event)"/>
</div>
<ul class="autocomplete-items">
<li class="autocomplete-item" arrow tabindex="-1" class="autocomplete-item" ng-repeat="company in filteredCompanies | limitTo:5 track by company.id" ng-click="selectThisCompany(company.id)">{{company.name}}</li>
<li class="more" ng-if="more">{{more}} Other companies</li>
</ul>
</form>
</div>
(function() {
function myController($scope) {
// $('#company-input:first-child').focus();
$scope.companyFilter = "";
$scope.screenLimit = 2;
$scope.setFocus = function() {
$('#company-input').focus();
}
var companies = [];
for(var i = 0; i < 100; i++){
companies.push(
{
id:i,
name: faker.company.companyName()
}
);
}
$scope.filterCompanies = function() {
if ($scope.companyFilter.length != "") {
$scope.filteredCompanies =
companies
.filter(sieve)
.sort(function(a, b) {
if (a.name > b.name) {
return 1
}
if (a.name < b.name) {
return -1
}
return 0
});
var leftOver = $scope.filteredCompanies.length - 5;
if (leftOver > 5) {
$scope.more = leftOver;
} else {
$scope.more = undefined;
}
} else {
$scope.filteredCompanies = [];
$scope.more = undefined;
};
function sieve(company) {
return _.contains($scope.companyFilter.toLowerCase())(company.name.toLowerCase());
}
}
$scope.selected = [];
$scope.selectThisCompany = function(id) {
var i = _.findIndex(function(x){return x.id == id})(companies)
$scope.selected.push(companies.splice(i,1)[0]);
$scope.companyFilter = "";
$scope.filterCompanies();
$scope.more = undefined;
$('#company-input').focus();
}
$scope.removeFocused = function(self, e) {
if (e.keyCode === 8 || e.which === 8) {
self.removeThisCompany(self.company.id);
$('#company-input').focus();
}
}
$scope.removeThisCompany = function(id) {
var i = _.findIndex(function(x){return x.id == id},$scope.selected);
console.log(i);
companies.push($scope.selected.splice(i,1)[0]);
$scope.filterCompanies();
}
$scope.focusSelected = function(e) {
if (e.which === 40) {
$('.autocomplete-item:first-child').focus();
} else if (e.which === 37) {
$('.tokens li:last-child').focus();
}
}
}
function filter() {
return function(input) {
if (input.length > 4) {
return input.slice(0,4) + "...";
}
}
}
function arrow() {
return function (scope,element,attrs) {
element.bind("keydown keypress", function(event) {
if (event.which === 38 || event.which === 37) {
var prevNode = element[0].previousElementSibling;
var prev = angular.element(prevNode);
prev[0].focus();
}
else if (event.which === 40 || event.which === 39) {
var target = element.next();
target[0].focus();
}
else if (event.which === 13) {
scope.selectThisCompany(scope.company.id);
}
else {
$('#company-input').focus();
}
});
}
}
function startFrom() {
return function(input,start) {
return input.slice(start);
}
}
function arrowLr() {
return function (scope,element,attrs) {
element.bind("keydown keypress", function(event) {
if (event.which === 37 || event.which === 38) {
var prevNode = element[0].previousElementSibling;
var prev = angular.element(prevNode);
prev[0].focus();
}
else if (event.which === 39 || event.which === 40) {
var target = element.next();
target[0].focus();
}
else {
$('#company-input').focus();
}
});
}
}
angular
.module('myApp', [])
.directive('arrow', arrow)
.directive('arrowLr', arrowLr)
.controller('myController', myController)
.filter('myFilter', filter)
.filter('startFrom', startFrom)
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/Faker/3.1.0/faker.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.11/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash-fp/0.10.4/lodash-fp.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
$tokenBody: #add8eb;
$tokenBorder: #2b89bd;
$tokenText: #777;
$dark: #444;
%tokenStyle {
background-color: $tokenBody;
border: 2px solid $tokenBorder;
color: $tokenText;
padding: 4px;
border-radius:4px;
margin-right: 4px;
font-size: 14px;
cursor: pointer;
&:focus, &:hover {
outline: 0;
background-color: $tokenBorder;
color: #fff;
}
&:after {
content: '\2715';
padding-left: 4px;
font-size: 12px;
vertical-align: center;
}
}
body {
font-family: sans-serif;
background-color: #ddd;
}
* {
box-sizing: border-box;
}
form {
background-color: #fff;
input {
border: 0;
padding-left: 6px;
&:focus {
outline: 0;
}
}
input {
font-size: 16px;
}
}
.token {
@extend %tokenStyle;
display: inline;
position: relative;
&:hover:before, &:focus:before {
background-color: $dark;
content:attr(data-tooltip);
position: absolute;
color: white;
left: 20%;
top: 30px;
width: 200px;
padding: 8px 20px;
border-radius: 8px;
}
}
.tokens, .autocomplete-items {
list-style-type: none;
padding-left: 0;
}
.leftovers {
font-size: .75em;
color: $tokenBorder;
display: inline;
position: relative;
> ul {
list-style: none;
padding-left: 0;
display: none;
background-color: #fff;
padding: 8px 10px;
width: 300px;
text-align: right;
box-shadow: 1px 2px 5px rgba(0,0,0,0.125);
li {
@extend %tokenStyle;
margin-right: 0;
margin-bottom: 4px;
}
}
&:focus {
outline: 0;
}
&:focus > ul, &:hover >ul, >ul:hover, >ul:focus {
display: initial;
position: absolute;
top: 14px;
left: 0;
}
}
.autocomplete-items {
margin-top: 0;
}
.autocomplete-item {
padding: 4px 8px;
cursor: pointer;
&:focus, &:hover {
outline: 0;
background-color: $tokenBorder;
color: #fff;
}
}
.more {
padding: 4px 8px;
border-top: 1px solid $tokenText;
color: $tokenText;
cursor: default;
}
.input {
height: 36px;
padding: 4px;
display: flex;
align-items: center;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment