如何在 Angular 中实现带有省略号和标签的(动态宽度)文本输入?

How to implement a (dynamic-width) text input with ellipsis and label in Angular?

如果用户提供的值太长而无法在UI.

文本输入将是动态宽度的,旁边有一个文本标签,并且输入应该在标签后使用所有可用的 space。

无论长度如何,标签都应该是一行。

但是,我知道 HTML 文本输入 (<input>) 不能有省略号 ,只有常规 HTML 元素,例如 <div>可以。 这能以某种方式实现吗?

看看this plunk

有很多事情在起作用:

  • 该值显示为常规 <span>(以便能够显示省略号),单击时,显示 <input>(由 editing 变量控制)
  • focusMe 指令用于在创建 <input> 以替换 <span>
  • 时将焦点放在 <input>
  • nonBreaking过滤使文本标签显示在一行
  • 基于flexbox的各种CSS规则控制显示
  • overflow, text-overflow 注意省略号
  • white-space: nowrapflex-shrink: 0 确保文本标签没有分成多行
  • flex-grow: 1 确保 <input> 占用所有额外的 space 可用

缺点:

  • 当用户第一次点击静态 <span> 时,光标放在 <input> 的开头,而不是用户点击的地方(如果他点击中间)
  • 当标签长于视口宽度时,将不会显示文本输入(假设视口宽度总是比标签长度宽得多)

附加信息:

添加验证时,如果模型处于无效状态,您可能希望保持 <input> 显示,否则绑定值为空,跨度将为空。

要做到:

  • 将 "name" 传递给指令并在内部执行 <input name="{{name}}">
  • 改为<span ng-show="!editing && form.{{name}}.$valid">
  • 改为<input ng-show="editing || !form.{{name}}.$valid">

完整代码:

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, '&nbsp;');
    return $sce.trustAsHtml(outputStr);
  };
});

/*
 * 
 */
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;
}