I want to have a <input type="text">
in Angular app that displays an ellipsis, (if not under edit) if the value provided by the user is too long to be displayed in the UI.
The text input will be of dynamic width, having a text label next to it, and input should be taking all available space after the label.
The labels should be one-line regardless of length.
However, I know that HTML text inputs (<input>
) can not have ellipsis, only regular HTML elements like <div>
can.
Can this be somehow achieved?
Have a look at this plunk
There are many things at play:
<span>
(to be able to show ellipsis), and when clicked, the <input>
is displayed instead (controlled by editing
variable)focusMe
directive is used to give focus to the <input>
when it's created to replace the <span>
nonBreaking
filter to make the text label displayed in one lineoverflow
, text-overflow
take care about ellipsiswhite-space: nowrap
and flex-shrink: 0
make sure that text label is not broken into multiple linesflex-grow: 1
makes sure that <input>
takes all extra space availableDrawbacks:
<span>
for the first time, the cursor is put at the beginning of the <input>
, not in the place where the user clicked (if he clicked in the middle)Additional info:
When you add validation, you probably want to keep the <input>
displayed if the model is in invalid state, otherwise the bound value is empty and span will be empty.
To do it:
<input name="{{name}}">
<span ng-show="!editing && form.{{name}}.$valid">
<input ng-show="editing || !form.{{name}}.$valid">
Full code:
HTML:
<!doctype html>
<html ng-app="plunker">
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css">
<script type="text/ng-template" id="InputTextWithEllipsis.html">
<div class="input-text-with-ellipsis-wrapper">
<label class="mylabel" ng-bind-html="mylabel | nonBreaking"></label>
<span class="dual-input-wrapper">
<span
ng-show="!editing"
ng-click="editing = true"
class="static-text-with-ellipsis">{{mymodel}}</span>
<input
ng-show="editing"
ng-focus="editing = true"
ng-blur="editing = false"
focus-me="editing"
ng-model="mymodel"
class="editable-textinput" />
</span>
</div>
</script>
</head>
<body ng-controller="MainCtrl">
<form name="profile">
<input-text-with-ellipsis
mylabel="'Name'"
mymodel="dataModel.name"
></input-text-with-ellipsis>
<input-text-with-ellipsis
mylabel="'Last Name'"
mymodel="dataModel.lastName"
></input-text-with-ellipsis>
<input-text-with-ellipsis
mylabel="'A very long label here'"
mymodel="dataModel.lastName"
></input-text-with-ellipsis>
</form>
</body>
</html>
JS:
var myModule = angular.module('plunker', []);
myModule.filter('nonBreaking', function($sce) {
return function(inputStr) {
var outputStr = inputStr.replace(/\s/g, ' ');
return $sce.trustAsHtml(outputStr);
};
});
/*
* http://stackoverflow.com/a/14837021/245966
*/
myModule.directive('focusMe', function($timeout, $parse) {
return {
link: function(scope, element, attrs) {
var model = $parse(attrs.focusMe);
scope.$watch(model, function(value) {
if (value === true) {
$timeout(function() {
element[0].focus();
});
}
});
}
};
});
myModule.controller('MainCtrl', function($scope) {
$scope.dataModel = {
name: "Fernando",
lastName: "Fernandez Sanchez de la Frontera"
}
});
myModule.directive('inputTextWithEllipsis', function(){
return {
restrict: 'E',
templateUrl: 'InputTextWithEllipsis.html',
require: ['^form'],
scope: {
mylabel: '=',
mymodel: '='
},
link: function(scope, element, attrs, ctrls) {
scope.editing = false;
}
};
});
CSS:
* {
font: 16pt sans-serif;
border: 0;
padding: 0;
margin: 0;
outline: 0;
}
.input-text-with-ellipsis-wrapper {
background-color: linen;
padding: 10px;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
}
.mylabel {
background-color: #ffddcc;
margin-right: 10px;
flex-basis: auto;
flex-shrink: 0;
min-width: 50px;
}
.dual-input-wrapper {
flex-basis: auto;
flex-grow: 1;
overflow: hidden;
white-space: nowrap;
text-align: right;
}
.editable-textinput {
background-color: #ddf;
width: 100%;
text-align: right;
}
.static-text-with-ellipsis {
background-color: #eeccbb;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}