指令中未收到广播

时间:2016-04-27 07:19:40

标签: javascript angularjs angularjs-directive angularjs-scope angularjs-bindings

我的@IBAction func searchcode(sender: UIButton) { //searchcodebtn.addTarget(self, action: "buttonPressed:", forControlEvents: .TouchUpInside) searchCode() } func searchCode(){ let keyword = self.searchcodetxt.text let lowercasekeyword = keyword!.lowercaseString let baseString = webcode.text let baselowercase = baseString!.lowercaseString let attributed = NSMutableAttributedString(string: baseString) var error: NSError? do { let regex = try NSRegularExpression(pattern: lowercasekeyword, options: NSRegularExpressionOptions.CaseInsensitive) let matches = regex.matchesInString(baselowercase, options: [], range: NSMakeRange(0, baselowercase.characters.count)) if let match = matches.first { let range = match.rangeAtIndex(1) if let swiftRange = rangeFromNSRange(range, forString: baselowercase) { attributed.addAttribute(NSBackgroundColorAttributeName, value: UIColor.yellowColor(), range: match.range) } } webcode.attributedText = attributed } catch { // regex was bad! let alertView:UIAlertView = UIAlertView() alertView.title = "Keywords error!" alertView.message = "Please use another keywords" alertView.delegate = self alertView.addButtonWithTitle("OK") alertView.show() // Delay the dismissal by 5 seconds let delay = 5.0 * Double(NSEC_PER_SEC) let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay)) dispatch_after(time, dispatch_get_main_queue(), { alertView.dismissWithClickedButtonIndex(-1, animated: true) }) } } func rangeFromNSRange(nsRange: NSRange, forString str: String) -> Range<String.Index>? { let fromUTF16 = str.utf16.startIndex.advancedBy(nsRange.location, limit: str.utf16.endIndex) let toUTF16 = fromUTF16.advancedBy(nsRange.length, limit: str.utf16.endIndex) if let from = String.Index(fromUTF16, within: str), let to = String.Index(toUTF16, within: str) { return from ..< to } return nil } <main><div>之间存在父子控制器关系:

<my-directive>

在MainController中,我使用:

执行$ broadcast
<main ng-controller="MainController">

    <nav>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
    </nav>

    <div ng-controller="AboutController">

    </div>

    <my-directive></my-directive>

</main>

在AboutController中,我可以通过以下方式成功接收这个$ broadcast:

$scope.$broadcast('shoppingCartReady', msg);

但是,当试图在angular.module('aboutModule', []) .controller('AboutController', require('./about/aboutController')); var AboutController = function ($scope, $rootScope) { $scope.$on('shoppingCartReady', function(event, msg){ console.log(msg); }); }; module.exports = [ '$scope', '$rootScope', AboutController]; 链接功能中接收$ broadcast时,似乎永远不会收到:

<my-directive>

更新

我甚至在我的指令中创建了一个控制器:

angular.module('shopModule', [])
    .directive('shopModuleDirective', require('./shopModuleDirective'))
    .directive('myDirective', require('./myDirective'));

var myDirective = function ($rootScope) {

    function link($scope, element, attrs, baseCtrl) {

        $scope.$on('shoppingCartReady', function (event, msg) {
            console.log(msg);
        });
    }

    return {
        restrict: 'E',
        require: '^shopModuleDirective',
        link: link
    };
};

return ['$rootScope', myDirective];

我可以看到

的日志
angular.module('shopModule', [])
    .directive('shopModuleDirective', require('./shopModuleDirective'))
    .directive('myDirective', require('./myDirective'));

var myDirective = function ($rootScope) {

    var controller = ["$scope", "$element", function ($scope, element) {
        console.log('waiting for .on....');
        $scope.$on('shoppingCartReady', function (event, cache) {
             console.log('shoppingCartReady .on rcvd!');
        });
    }]

    function link($scope, element, attrs, baseCtrl) {

        $scope.$on('shoppingCartReady', function (event, msg) {
            console.log(msg);
        });
    }

    return {
        restrict: 'E',
        require: '^shopModuleDirective',
        link: link
    };
};

return ['$rootScope', myDirective];

但.on从未收到。

更新:

我认为可能的原因是由于范围没有“准备好”。

在MainController的原始console.log('waiting for .on....'); 内,如果我在broadcast之后执行另一个,则会收到所有setTime

MainController:

.on

2 个答案:

答案 0 :(得分:4)

来自Documentation

  

$ broadcast(name,args);

     

将事件名称向下调度到所有子范围(以及他们的   孩子们)通知已注册的$ rootScope.Scope听众。

在你的指令中,你没有创建一个新的范围,我猜你和MainController只是在同一范围内。在这种情况下,您不在MainController的childScope中,因此无法在那里触发事件。我会尝试下列之一:

  1. 始终通过$rootScope.$broadcast广播您的活动。所有其他范围都是$rootScope的孩子,所以只要您注册$scope.$on的活动,您就会收到它。您可能还对Why do we use $rootScope.$broadcast in AngularJS?

  2. 感兴趣
  3. 将您的指令设为隔离的$scope。这将作为MainController的childScope,并且应该也可以。 Isolationg the $scope of a directive

  4. 除了选项1.,您还可以将$rootScope.$emit$rootScope.$on一起使用。有关详细信息,请阅读$rootScope.$broadcast vs. $scope.$emit

  5. 我总是选择选项1.,因为有时你不希望你的指令有一个孤立的范围。

答案 1 :(得分:3)

有竞争条件。

myDirective之后执行

MainController控制器和后链接功能,并在触发shoppingCartReady事件后设置侦听器。

良好的,可测试的指令设计的经验法则是将所有与范围相关的逻辑保留在控制器中,链接函数和$onInit挂钩完全用于那里应该发生的事情而不是其他任何地方,比如操作关于编译的DOM内容。

link不太明显但独特的用例是理想的执行顺序(后连接函数以相反的顺序执行,从子项到父项)。如果MainController成为指令,并且scope.$broadcast('shoppingCartReady', msg)link函数而不是控制器中执行,则可以保证正确的执行顺序。

将控制器代码包装为零$timeout也会推迟代码

$timeout(function(){
    $scope.$broadcast('shoppingCartReady', msg);
});

在子指令中链接函数后执行,但也会指定一些代码味道。这是范围事件不太可取的指令通信方式并且容易出现反模式的原因之一。

处理这种情况的另一种方法取决于shoppingCartReady事件的内容,但在目前的情况下它是多余的:它已经发生在执行子控制器时,它们可以安全地假设'购物车准备好了。

有关此主题的建议阅读材料:Directive Controller And Link Timing In AngularJS