angularjs bindToController无法调用方法

时间:2017-05-26 14:48:24

标签: javascript angularjs

我有一个这样的指令设置:

$(document).ready(function(){
            $(window).on('scroll', function(){
                ready = true;
            });
            //Scroll function
            $(window).on('scrollstop', function(){
                $(window).off('scroll');
                if(ready){
                    ready = false;
                }
                else{
                    return;
                }
                var doc = document.documentElement;
                var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
                if(top < 45){
                    $("html, body").stop().animate({scrollTop: 0}, 100, 'swing');
                }
                else if(top <= 100){
                    $("html, body").stop().animate({scrollTop: 100}, 200, 'swing');
                }
                if(top > 100){
                    $("#mobileHeaderDivision").fadeOut("slow");
                    $("#mobileMenu").fadeOut("slow");
                    $("#mobileHeaderDivision").css({"position": "fixed", "top": "0", "left": "0"});
                    $("#mobileMenu").css({"position": "fixed", "top": "2px", "left": "0"});
                    $("#mobileHeaderDivision").fadeIn("slow");
                    $("#mobileMenu").fadeIn("slow");
                }
                else{
                    $("#mobileHeaderDivision").fadeOut("slow");
                    $("#mobileMenu").fadeOut("slow");
                    $("#mobileHeaderDivision").css({"position": "relative", "top": "", "left": ""});
                    $("#mobileMenu").css({"position": "relative", "top": "", "left": ""});
                    $("#mobileHeaderDivision").fadeIn("slow");
                    $("#mobileMenu").fadeIn("slow");
                }
                $(window).on('scroll', function(){
                    ready = true;
                });
            });
        });

它的控制器看起来像这样:

angular.module('widget.directives').directive('applePay', applePay);

function applePay() {
    return {
        restrict: 'A',
        controller: 'ApplePayController',
        controllerAs: 'controller',
        scope: {
            onCheckComplete: '&applePay'
        },
        bindToController: true,
        templateUrl: 'app/directives/apple-pay/apple-pay.html',
        link: function (scope, element, attrs, controller) {
            element.find('button').bind('click', controller.checkout);
        }
    };
};

我的html是这样的:

angular.module('widget.directives').controller('ApplePayController', applePayController);

applePayController.$inject = ['applePayService'];

function applePayController(applePayService) {
    var self = this;

    // Method binding
    self.checkout = checkout;

    init();

    //////////////////////////////////////////////////

    function init() {
        applePayService.checkAvailability(setAvailability);
    };

    function setAvailability(available) {
        self.available = available === true;
        console.log(self);
        self.onCheckComplete({ available: self.available });
    };

    function checkout(e) {
        applePayService.checkout(e, onComplete, onError);
    };

    function onComplete(result, completion) {
        console.log(result, completion);
    };

    function onError(error) {
        self.error = error;
    };
};

当指令加载时,我收到一个错误:

  

TypeError:self.onCheckComplete不是函数

有谁知道为什么? 我有一个类似的指令,工作正常。

2 个答案:

答案 0 :(得分:0)

这是因为 Controller 有一个init方法,在实例化控制器时调用该方法。问题在于范围尚未受到限制。所以我不得不将控制器更改为:

angular.module('widget.directives').controller('ApplePayController', applePayController);

applePayController.$inject = ['applePayService'];

function applePayController(applePayService) {
    var self = this;

    // Method binding
    self.init = init;
    self.checkout = checkout;

    //////////////////////////////////////////////////

    function init() {
        applePayService.checkAvailability(setAvailability);
    };

    function setAvailability(available) {
        self.available = available === true;
        console.log(self);
        self.onCheckComplete({ available: self.available });
    };

    function checkout(e) {
        applePayService.checkout(e, onComplete, onError);
    };

    function onComplete(result, completion) {
        console.log(result, completion);
    };

    function onError(error) {
        self.error = error;
    };
};

然后将init方法添加到指令的链接函数中。

angular.module('widget.directives').directive('applePay', applePay);

function applePay() {
    return {
        restrict: 'A',
        templateUrl: 'app/directives/apple-pay/apple-pay.html',
        controller: 'ApplePayController',
        controllerAs: 'controller',
        bindToController: true,
        scope: {
            onCheckComplete: '&applePay'
        },
        link: function (scope, element, attrs, controller) {
            element.find('button').bind('click', controller.checkout);
            controller.init();
        }
    };
};

上面的唯一区别是在控制器上添加init方法作为公共方法,然后从指令调用controller.init()。这确保了范围在启动之前受到约束。

答案 1 :(得分:0)

我发现这很奇怪,因为我有一些1.5x代码执行完全相同的事情没有问题。在得知你是1.6x之后,我做了一些挖掘以了解发生了什么。影响事物的变化是针对名为preAssignBindingsEnabled的属性。这个重大变化记录在gitHub post中。它也是迁移document here

的一部分

在迁移文档中有一个很棒的代码片段,我认为您会发现它对您的情况有帮助,允许您保持link()函数的所有DOM操作,而不必担心调用控制器。核心:服务 - &gt;迁移文档的$ compile部分,它显示了一个带有控制器声明的指令,使用1.5x $onInit()挂钩语法来确保在控制器初始化之前存在绑定。

我根据你的情况调整了这个:

function applePayController(applePayService) {
  var self = this;

  // Method binding
  self.checkout = checkout;

  //**Hook below to ensure bindings are set when preAssignBindingsEnabled is 
  //false (default setting with 1.6x**)

  self.$onInit = init;

  //init();

  function init() {
    applePayService.checkAvailability(setAvailability);
  };

  .
  .
  .
 };

一旦绑定全部设置,控制器的$ onInit将自动被Angular调用,并且该函数正常执行。希望这提供了一些额外的选择!