【问题标题】:Textarea ng-bind, where value has a prefix and suffixTextarea ng-bind,其中 value 有前缀和后缀
【发布时间】:2016-10-26 19:59:36
【问题描述】:

在我看来,我正在尝试完成一些应该相当简单的事情。当使用诸如文本输入之类的东西时也是如此。我正在尝试在 textarea 上创建模型绑定,当用户键入时,其中的值显示为带有前缀和后缀。前缀和后缀是引号:

“My awesome quote”

问题是,我目前正在使用 ng-model,我当然不能使用它。我正在考虑绑定到一个变量,保留没有前缀和后缀的值,然后观察该变量。当具有原始值的变量发生变化时,我会将带有前缀和后缀的值写入范围内的另一个变量。当用户键入时,该变量将显示在文本区域中。唯一的问题是,与输入字段不同,textarea 没有 value 属性。

这可能吗?

编辑

如果我在哪里使用输入文本字段来实现这一点,我将创建一个名为 A 的变量,以保存在用户键入时更改的原始值。 当 A 更改时,我将获取原始值,在其周围加上引号并将新值存储在另一个变量中,也在范围内。这个新变量称为 B

然后输入字段将在 A 变量上使用 ng-bind,并使用输入字段值属性显示 B 变量的内容。如下所示:

<input type="text" ng-bind="A" value="{{B}}">

我现在没有时间制作小提琴,但我会在本周晚些时候尝试制作。上面的描述都是理论上的,因为我还没有测试过。

【问题讨论】:

  • 澄清一下,您希望在textarea中添加前缀和后缀而不影响模型值?
  • 是的,完全正确。如果可以的话,我的意思是。如果需要,在发布值之前删除引号没有问题。我现在有办法做到这一点,但问题是光标处于“错误”位置。 “我的报价”(光标在这里)
  • 如果我可以在 textarea 周围加上引号,那就太好了,但是 textarea 没有动态宽度。我当然可以写一些 javascript 来调整你输入的宽度。
  • 使用可编辑的段落标签怎么样?使用内容可编辑。然后用引号括起来
  • 您说使用输入而不是文本区域来实现这种效果非常简单。你能在 jsfiddle 上创建一个例子吗?

标签: javascript html angularjs


【解决方案1】:

您的需求非常有趣,可以分为两个主要功能:

1。在不影响模型值的情况下为视图值添加前缀和后缀

这是使用NgModelController 实现的。我在ngModelController.$viewValue 上创建了一个观察者,每当它发生变化时,如果它不包含前缀或后缀,我就会添加这些值。

2。不允许用户干扰前缀或后缀

这有点棘手,但我发现 a clever way on SO 可以获取和设置输入或文本区域元素的插入符号位置。

这是一个工作示例:

angular
  .module('myApp', [])
  .directive('beautifyText', function() {
    return {
      link: function(scope, iElement, iAttrs, ngModelController) {
        // Adds the prefix and suffix
        (function() {
          var prefix = iAttrs.beautifyTextWithPrefix;
          var suffix = iAttrs.beautifyTextWithSuffix;

          ngModelController.$parsers.push(function(value) {
            if (angular.isString(value)) {
              return value.replace(new RegExp('^' + prefix), '').replace(new RegExp(suffix + '$'), '');
            }

            return '';
          });

          scope.$watch(function() {
            return ngModelController.$viewValue;
          }, function(newValue) {
            if (angular.isString(newValue) && newValue.length > 0) {
              if (angular.isString(ngModelController.$modelValue) && ngModelController.$modelValue.length === 0 && newValue.length === 1) {
                ngModelController.$viewValue = '';
                ngModelController.$render();
                return;
              }

              if (!isBeautifiedWithPrefix(newValue)) {
                ngModelController.$viewValue = prefix + newValue;
              }

              if (!isBeautifiedWithSuffix(newValue)) {
                ngModelController.$viewValue = newValue + suffix;
              }

              ngModelController.$render();
            } else {
              ngModelController.$viewValue = '';
              ngModelController.$render();
            }
          });

          function isBeautifiedWithPrefix(value) {
            return value.match(new RegExp('^' + prefix)) !== null;
          }

          function isBeautifiedWithSuffix(value) {
            return value.match(new RegExp(suffix + '$')) !== null;
          }
        })();

        // Changes the caret position
        (function() {
          var element = iElement[0];

          // https://stackoverflow.com/questions/7745867/how-do-you-get-the-cursor-position-in-a-textarea#answer-7745998
          function getCursorPos() {
            if ("selectionStart" in element && document.activeElement == element) {
              return {
                start: element.selectionStart,
                end: element.selectionEnd
              };
            } else if (element.createTextRange) {
              var sel = document.selection.createRange();
              if (sel.parentElement() === element) {
                var rng = element.createTextRange();
                rng.moveToBookmark(sel.getBookmark());
                for (var len = 0; rng.compareEndPoints("EndToStart", rng) > 0; rng.moveEnd("character", -1)) {
                  len++;
                }
                rng.setEndPoint("StartToStart", element.createTextRange());
                for (var pos = {
                  start: 0,
                  end: len
                }; rng.compareEndPoints("EndToStart", rng) > 0; rng.moveEnd("character", -1)) {
                  pos.start++;
                  pos.end++;
                }
                return pos;
              }
            }
            return -1;
          }

          // https://stackoverflow.com/questions/7745867/how-do-you-get-the-cursor-position-in-a-textarea#answer-7745998
          function setCursorPos(start, end) {
            if (arguments.length < 2) {
              end = start;
            }

            if ("selectionStart" in element) {
              element.selectionStart = start;
              element.selectionEnd = end;
            } else if (element.createTextRange) {
              var rng = element.createTextRange();
              rng.moveStart("character", start);
              rng.collapse();
              rng.moveEnd("character", end - start);
              rng.select();
            }
          }

          iElement.bind('mousedown mouseup keydown keyup', function() {
            if (ngModelController.$viewValue.length > 0) {
              var caretPosition = getCursorPos();

              if (caretPosition.start === 0) {
                setCursorPos(1, caretPosition.end < 1 ? 1 : caretPosition.end);
              }

              if (caretPosition.end === ngModelController.$viewValue.length) {
                setCursorPos(caretPosition.start, ngModelController.$viewValue.length - 1);
              }
            }
          });
        })();
      },
      restrict: 'A',
      require: 'ngModel'
    }
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>

<div ng-app="myApp">
  <textarea ng-model="myVariable" beautify-text beautify-text-with-prefix="“" beautify-text-with-suffix="”"></textarea>
  <p>myVariable: {{ myVariable }}</p>
</div>

【讨论】:

  • 这是一个非常聪明的解决方案!唯一缺少的是在值为空时删除引号。我可能可以自己添加!谢谢!
  • @ThomasTeilmann 这很简单。我已经更新了我的代码。 if (angular.isString(ngModelController.$modelValue) &amp;&amp; ngModelController.$modelValue.length === 0 &amp;&amp; newValue.length === 1) 成功了。
【解决方案2】:

更新

所以我使用 ng focus 和 blur 来删除和添加引号,当他使用 textarea 时它不会生效,但它会工作

angular.module('myApp', [])
  .controller('demoCtrl', ['$scope',
    function($scope) {
      $scope.myModel = '';

      $scope.removeQuotes = function() {
        $scope.myModel = $scope.myModel.replace(/“|”/gm, ''); // remove the quotes
      }

      $scope.addQuotes = function() {
        if ($scope.myModel == '') {
          $scope.myModel = ''; // dont add the quotes for an empty value
          return;
        }


        $scope.myModel = "“" + $scope.myModel + "”" // add the quotes again
      }
    }
  ])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="myApp">
  <div ng-controller="demoCtrl">
    <textarea ng-model="myModel" ng-focus='removeQuotes()' ng-blur='addQuotes()'></textarea>
  </div>

</div>

【讨论】:

  • 您发布的第一个解决方案实际上比这个更好,因为您让用户在 textarea 中输入,这对于我的场景来说是必需的。使用输入字段时,我无法查看您的答案。您的第一个答案的唯一问题是光标位于引号的错误一侧。我想那是不可能的
  • 这实际上是一个非常好的主意。由于它不是 100% 解决问题的方法,所以在接受它之前,我会让它挂起一段时间!为你点赞!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-15
  • 2018-09-08
  • 1970-01-01
相关资源
最近更新 更多