Textarea ng-bind,其中 value 有前缀和后缀

Posted

技术标签:

【中文标题】Textarea ng-bind,其中 value 有前缀和后缀【英文标题】:Textarea ng-bind, where value has a prefix and suffix 【发布时间】: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 上创建一个例子吗? 【参考方案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://***.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://***.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% 解决问题的方法,所以在接受它之前,我会让它挂起一段时间!为你点赞!

以上是关于Textarea ng-bind,其中 value 有前缀和后缀的主要内容,如果未能解决你的问题,请参考以下文章

ng-model 和 ng-bind 有啥区别

php MySQL 更新表 textarea html

Angular - 用户输入后无法更新文本区域

react使用textarea给value赋值后获取到的是旧

textarea value 到底该怎么赋值

使用 set_value 的 Textarea 未填充 Codeigniter