2014-12-02 104 views
1

我试图实施一个指令,将使用ng-show$timeout来延迟容器的显示。指令范围使用隐藏父元素的内部元素

这里就是我的指令看起来像:

angular.module('myApp') 
    .directive('delay', function($timeout) { 
     return { 
      template: '<div ng-show="showIt" ng-transclude></div>', 
      replace: false, 
      transclude: true, 
      scope:true, 
      restrict: 'A', 
      link: function postLink(scope, element, attrs) { 
       $timeout(function() { 
         scope.showIt = true; 
       }, attrs.delay); 
      } 
     }; 
    }); 

然后,我会用它在我看来,这样的

<div delay="1000"> 
    <intput type="text" ng-model="myText"/> 
</div> 

到目前为止,延时工作。是的,我很自豪。但是,myText不能从控制器访问,因为它不在父范围内可见。我尝试将范围改为此:

scope: { 
    myText: '=' 
} 

建立一个双向数据绑定...没有任何成功。

什么是最简单的方法来实现我试图实现使用指令?非常感谢!

编辑:金科玉律

由于很多GregL他的回答!

最好的解决方法是简单地将我的ng模型包装在对象中以利用点符号来避免将ng模型绑定到子范围。子范围使用原型继承来查找其值,所以当在子范围中设置该值时,它不再查找父范围。

回答

3

解决这个问题的最好办法是记住我称之为“AngularJS黄金法则”:

在NG始终使用点/句号(。)模型表达式。

这样,您就会将属性写入正确范围的正确对象。

但是,如果您真的想让它正常工作,您可以执行一个指令,使用链接函数的transclude参数对正确的作用域执行手动转换。

sample.directive('delay', function($timeout) { 
    return { 
    template: '<div ng-show="showIt"></div>', 
    replace: false, 
    transclude: true, 
    scope: {}, 
    restrict: 'A', 
    link: function postLink(scope, element, attrs, nullCtrl, transclude) { 
     var transcludeScope = scope.$parent; 
     transclude(transcludeScope, function(clone) { 
     element.find('div[ng-show]').append(clone); 
     }); 
     $timeout(function() { 
     scope.showIt = true; 
     }, attrs.delay); 
    } 
    }; 
}); 

这将的<div ng-show="showIt">内容的范围设置为与delay指令是在元件的范围。它还具有隔离范围的好处,以便您可以随意使用多个实例。

See it in action in a Plunkr

+1

非常感谢,你是一个天才,它完美的作品!这是我的第一个指令,我远未掌握所有方面。当你谈到黄金法则时,你的意思是我应该将模型myText设置为一个对象?然后使用myObject.myText?谢谢@GregL! – 2014-12-02 03:22:18

+0

没关系我找到了我的问题的答案:http://stackoverflow.com/questions/18128323/angularjs-if-you-are-not-using-a-dot-in-your-models-you-are-doing-它-错 – 2014-12-02 03:26:25

0

尝试{scope: false}。你正在用你的delay指令创建你自己的范围。

或者

link: function(scope, element) { 
    var showing = true; 
    $timeout(function() { 
    if (showing) { 
     element.hide(); 
    } else { 
     element.show(); 
    } 
    showing = !showing; 
    }, delay) 
} 
+0

这样做是可以,但你不能在同一范围内使用超过1的这些,你会填充'showIt'财产上的任何范围是您在使用此指令元素活跃。如果你已经在该范围内拥有'showIt'属性会发生什么? – GregL 2014-12-02 02:08:15

+0

您可以使用'$元素。隐藏()'并自己控制可见性。在这种情况下,我不会创建另一个DOM元素(实际上,我可能会使用css和ng-animate来实现相同的效果)。 – orange 2014-12-02 02:11:39

+0

@GregL的确如此。如果我将范围设置为false,然后对2个不同的元素使用2个不同的延迟,则两个元素都会在第一个元素到期后出现。 – 2014-12-02 02:12:44