为ui-bootstrap工具提示/弹出窗口动态设置attrs

red*_*ose 3 angularjs angular-ui-bootstrap

我正在尝试以编程方式切换工具提示(如此处提到的:https://stackoverflow.com/a/23377441)并使其完全正常运行,除了一个问题.为了使它工作,我必须具有硬编码的工具提示触发器和工具提示属性,如下所示:

<input type="text" tooltip-trigger="show" tooltip="" field1>
Run Code Online (Sandbox Code Playgroud)

在我的工作指令中,我能够更改工具提示属性并触发工具提示,但是如果我尝试将这两个属性保留并尝试动态设置它们,则ui-bootstrap不会提取它们并且不会显示工具提示.

HTML

<input type="text" field2>
Run Code Online (Sandbox Code Playgroud)

JS

myApp.directive('field2', function($timeout) {
    return {
        scope: true,
        restrict: 'A',
        link: function(scope, element, attrs) {

            scope.$watch('errors', function() {
                var id = "field2";
                if (scope.errors[id]) {
                    $timeout(function(){
                      // these attrs dont take effect...
                        attrs.$set('tooltip-trigger', 'show');
                        attrs.$set('tooltip-placement', 'top');

                        attrs.$set('tooltip', scope.errors[id]);
                        element.triggerHandler('show');
                    });
                    element.bind("click", function(e){
                      element.triggerHandler('hide');
                    });
                }
            });
        },
    };
});
Run Code Online (Sandbox Code Playgroud)

我不想在html中对这些属性进行硬编码,那么我该如何动态设置这些属性并获取ui-bootstrap来获取它们呢?

这是一个具有工作(field1)和非工作(field2)指令的plunker:http://plnkr.co/edit/mP0JD8KHt4ZR3n0vF46e

jme*_*e11 6

你可以做到这一点,但你必须改变你的方法中的一些事情.

Plunker演示

指示

app.directive("errorTooltip", function($compile, $interpolate, $timeout) {
  return {
    scope: true,
    link: function($scope, $element, $attrs) {
      var errorObj = $attrs.errorTooltip;
      var inputName = $attrs.name;
      var startSym = $interpolate.startSymbol();
      var endSym = $interpolate.endSymbol();
      var content = startSym+errorObj+'.'+inputName+endSym;
      $element.attr('tooltip-trigger', 'show');
      $element.attr('tooltip-placement', 'top');
      $element.attr('tooltip', content);
      $element.removeAttr('error-tooltip');
      $compile($element)($scope);

      $scope.$watch(errorObj, function() {
        $timeout(function(){
          $element.triggerHandler('show');
        });
      }, true);

      $element.on('click', function(e){
        $element.triggerHandler('hide');
      });

    }
  };
});
Run Code Online (Sandbox Code Playgroud)

超长的详细说明:

好的,从顶部开始:@Travis是正确的,因为你不能在事后注入属性.您放置在元素上的工具提示属性是指令本身,因此工具提示需要在附加时进行编译.这不是问题,您可以使用$ compile服务来执行此操作,但您只需要为元素执行一次.

此外,您需要将工具提示文本(给予tooltip属性的值)绑定到表达式.我通过传入一个连接的值$interpolate.startSymbol()+你要显示的范围值(在演示中它是错误对象的字段x属性)+ $interpolate.endSymbol().这基本上评估为:{{error.field1}}.我使用$ interpolate服务的开始和结束符号,因为它只是使指令更加组件化,所以你可以在你可能有多个框架的其他项目上使用它,并为你的Angular表达式使用双花括号以外的东西.但这并不是必要的,你可以这样做:'{{'+errorObj+'.'+inputName+'}}'.在这种情况下,您不必将$ interpolate服务添加为依赖项.

正如您所看到的,为了使指令真正可重用,而不是对错误字段进行硬编码,我将指定属性的值设置为将要监视的对象的名称,并使用输入名称值作为对象属性.

您需要记住的主要事情是,在编译之前,您必须从元素中删除error-tooltip属性,因为如果不这样做,您将陷入无限循环并且崩溃!基本上,编译服务将采用指令所附加的元素,并使用指令添加的所有属性对其进行编译,如果保留error-tooltip属性,它将尝试重新编译该指令.

最后,如果工具提示的文本值为空或未定义,则可以利用工具提示不显示的事实(参见第192行).这意味着您只需要查看错误对象而不是与工具提示相关的错误上的单个属性.确保将等于运算符设置$watchtrue,以便在任何对象的属性发生更改时触发:

  $scope.$watch('errors', function() {
    $timeout(function(){
      $element.triggerHandler('show');
    });
  }, true); //<--equality operator
Run Code Online (Sandbox Code Playgroud)

在演示中,您可以看到更改错误对象的效果.如果单击"设置错误"按钮,将显示第一个和第二个输入的工具提示.单击"更改错误值",显示第一个和第三个输入的工具提示.

TL; DR:

通过将值设置为包含所有错误的对象的名称,将指令添加到标记中.确保为该字段指定一个name属性,该属性对应于将包含该输入的错误的对象中的属性键名称,例如:

<input class="form-control" ng-model="demo.field1" name="field1" error-tooltip="errors" />
Run Code Online (Sandbox Code Playgroud)