javascript - AngularJS:在解决 promise 后更新表单字段的代码属于哪里?

标签 javascript angularjs separation-of-concerns angularjs-design-patterns

在我的 AngularJS 应用程序中,我有一个包含 <textarea> 的模板和一个提交按钮。 <div> (它可以很容易地成为一个 <form> )包装了这两个元素并有一个 Controller 。 Controller 使用 $resource服务于POST来自 <textarea> 的值单击提交按钮时发送到 REST API。

模板:

<div ng-controller="MyController as vm">
  <textarea ng-model="vm.text" rows="5"></textarea>
  <button ng-click="vm.save()">Save</button>
</div>

Controller :

angular.module('myApp')
  .controller('MyController', MyController);

MyController.$inject = ['myRestApiResource'];

function MyController(myRestApiResource) {
  var vm = this;
  vm.save = function() {
    var params = [];
    var postData = {text: vm.text};
    myRestApiResource.save(params, postData)
      .then(function(res) { /* success handler */ })
      .catch(function(res) { /* error handler */ });
  };
}

当资源save()方法的 $promise被拒绝,响应数据(在某些情况下)包含 error.position引用在 vm.text 中检测到语法错误的字符串索引的属性.

在那些情况下,我关注 <textarea>元素和 set the selection range来自 error.position到下一个非单词字符。我有一个功能,一切正常。

我的问题是:

应在 <textarea> 上设置选择范围的函数调用(在 promise 被拒绝后)在...中执行

  1. 控制者
  2. 添加到文本区域的自定义指令
  3. 其他地方

...为什么?

这是一个关于关注点分离的问题。

Controller 似乎是最明智的地方,但我的理解是 Controller 不应该执行 DOM 操作......这需要使用 $element服务(或 jQuery)就是为了做到这一点。

自定义指令需要订阅 Controller 广播的事件,然后设置自己的焦点和选择范围。这将问题分开,但根据 Angular Best Practices $broadcast$on应该只用于“在整个应用程序中与全局相关的事件”。

我想 Controller 和指令可以通过另一个服务进行通信,但这似乎是过度工程——这是我臭名昭著的并且在这里努力避免的事情! :-)

提前致谢!


解决方案

为了完整起见,这是我根据@kristin-fritsch 的回答编写的自定义指令:

指令

angular.module('myApp')
  .directive('selectionRange', selectionRangeDirective);

function selectionRangeDirective() {
  return {
    restrict: 'A',
    scope: {
      selectionRange: '='
    },
    link: function(scope, iElement) {
      var element = iElement[0];
      if (element.setSelectionRange && typeof element.setSelectionRange === 'function') {
        scope.$watch('selectionRange', function(range) {
          if (range && typeof range.start === 'number' && range.start > -1 && range.start < iElement.val().length) {
            element.focus();
            element.setSelectionRange(range.start, range.end);
          }
        });
      }
    }
  };
}

为了实现它,我将指令属性添加到我的文本区域:

<textarea ng-model="vm.text" rows="5" selection-range="vm.selection"></textarea>

...并设置 vm.selection 的值到带有 start 的对象和 end当 promise 被拒绝时,我 Controller 中的属性。

myRestApiResource.save(params, postData)
  .then(function(res) { /* success handler */ })
  .catch(function(res) {
    var error = res.data.error;
    if (error && error.position) {
      var start = error.position;
      var end = start + vm.text.substr(start).search(/(\W|$)/);
      vm.selection = {start: start, end: end};
    }
  });

最佳答案

我建议您向文本区域添加一个指令。

<div ng-controller="MyController as vm">
  <textarea ng-model="vm.text" data-error-position="errorPosition" rows="5"></textarea>
  <button ng-click="vm.save()">Save</button>
</div>

然后你可以像这样设置 $promise 被拒绝时的位置

$scope.errorPosition = 50;

并在 errorPosition - 指令中处理 DOM 操作。

关于javascript - AngularJS:在解决 promise 后更新表单字段的代码属于哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34113751/

相关文章:

jquery - 指令中缺少子元素

javascript - AngularJS教程 'checkmark'过滤器,返回值更清晰

java - 如何使用oop和soc实现从数据库读取默认对象设置

javascript - Sapper 不断从客户端收到有关 'this' 关键字的警告?

javascript - 我如何在 Angular4 中设置默认路由?

javascript - Angular 指令不工作 Chrome 打包应用程序

android - GoogleApiClient 和 GooglePlayServicesClient : Can you preserve a separation of concerns?

model-view-controller - EmberJS : Good separation of concerns for Models, 在相当复杂的应用程序中存储、 Controller 、 View ?

javascript - 如何在闭包中连接变量字符串

javascript - 如何在 Javascript 中设置 SVG CSS 属性的样式?