【问题标题】:controllerAs, bindToController and watchescontrollerAs、bindToController 和手表
【发布时间】:2017-08-05 03:18:28
【问题描述】:

我有这个指令,它有一个控制器。它看起来像这样:

.directive('pkSlider', ['$timeout', function ($timeout) {
    return {
        restrict: 'A',
        scope: {
            question: '=pkSlider',
            options: '=',
            onSelect: '&'
        },
        controller: 'PKSliderController',
        templateUrl: function (element, attrs) {
            if (attrs.type === 'image')
                return 'assets/templates/directives/pk-image.html';

            return 'assets/templates/directives/pk-slider.html';
        },
        link: function (scope, element, attrs, controller) {

            // Get our visible answers
            scope.answers = controller.getVisibleAnswers(scope.question.answers);

            // Increase the answers if they are less than the slides to show
            if (scope.answers.length <= scope.options.slidesToShow)
                scope.answers = scope.answers.concat(scope.answers);

            // Watch our answers
            scope.$watch('answers', function (answers) {

                // When we have our answers
                if (answers.length) {

                    // Extend our options
                    angular.extend(scope.options, {
                        event: {

                            // Set our first slide and sort/filter our products
                            init: function (event, slick) {

                                // Get the actual index stored in the answer
                                var index = scope.answers[slick.currentSlide].index;

                                // Set our current slide to the physical current slide, this is for the images to be shown
                                scope.currentSlide = slick.currentSlide;

                                // Invoke our methods using the answer index
                                controller.afterChange(scope.question, index);
                                scope.onSelect({ index: index, direction: slick.direction });
                            },

                            // Set our current slide and sort/filter our products
                            afterChange: function (event, slick, currentSlide) {

                                // Get the actual index stored in the answer
                                var index = scope.answers[currentSlide].index;
                                // Set our current slide to the physical current slide, this is for the images to be shown
                                scope.currentSlide = currentSlide;

                                // Invoke our methods using the answer index
                                controller.afterChange(scope.question, index);
                                scope.onSelect({ index: index, direction: slick.direction });
                            }
                        }
                    });

                    // We have loaded
                    scope.loaded = true;
                }
            });
        }
    };
}]);

控制器看起来像这样:

.controller('PKSliderController', ['$timeout', '$interval', 'TrackingProvider', 'AnswerProvider', function ($timeout, $interval, tracking, provider) {
    var self = this,
        timer,
        setActiveImage = function (answers, activeIndex) {

            // If we have a current timer running, cancel it
            if (timer)
                $timeout.cancel(timer);

            // For each answer
            answers.forEach(function (answer, index) {

                // Get our images
                var images = answer.images;

                // If we have an image
                if (images) {

                    // Get our image
                    var image = images[0];

                    // If we are active
                    if (index === activeIndex) {

                        // For each text
                        image.imageText.forEach(function (text) {
                            text.active = false;

                            // Activate our text after the delay
                            $interval(function () {
                                text.active = true;
                            }, text.delay, 1);
                        });
                    }
                }
            });
        };

    // Get our answers
    self.getVisibleAnswers = provider.getVisible;

    // Updates the question with your selected answer
    self.afterChange = function (question, answerIndex) {

        // Get our answer
        var answers = question.answers,
            answer = answers[answerIndex];

        // Set our active image
        setActiveImage(answers, answerIndex);

        // This is for the last step, because some options might not actually be available
        if (answer) {

            // Set our selected answer
            question.radioChoice = answer.text;
        }
    };
}])

我一直在根据angular style guide 转换我的代码,并为我没有意识到存在的指令找到了一个新选项,称为bindToController。所以我正在尝试实现这一点。 我已将我的指令转换为:

(function () {
    'use strict';

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

    pkSlider.$inject = ['$timeout'];

    function pkSlider($timeout) {
        return {
            restrict: 'A',
            scope: {
                question: '=pkSlider',
                options: '=',
                onSelect: '&'
            },  
            controller: 'PKSliderController',
            controllerAs: 'controller',
            bindToController: true,
            templateUrl: getTemplate
        };

        function getTemplate(element, attrs) {
            if (attrs.type === 'image')
                return 'app/directives/pkImage.html';

            return 'app/directives/pkSlider.html';
        };
    }
})();

这已经干净多了。 然后我尝试转换我的控制器:

(function () {
    'use strict';

    angular.module('widget.directives').controller('PKSliderController', PKSliderController);

    PKSliderController.$inject = ['$scope', '$timeout', '$interval', 'answerProvider'];

    function PKSliderController($scope, $timeout, $interval, answerProvider) {
        var self = this,
            timer;

        // Bindings
        self.afterChange = afterChange;
        $scope.$watch('controller.answers', watchAnswers);

        // Init
        init();

        function init() {

            // Get our answersw
            self.answers = answerProvider.getVisible(self.question.answers);

            // Increase the answers if they are less than the slides to show
            if (self.answers.length <= self.options.slidesToShow)
                self.answers = self.answers.concat(self.answers);
        };

        // Watches the answers for any changes
        function watchAnswers(answers) {

            // When we have our answers
            if (answers.length) {

                // Extend our options
                self.options = angular.merge(self.options, {
                    event: {

                        // Set our first slide and sort/filter our products
                        init: function (event, slick) {

                            // Get the actual index stored in the answer
                            var index = self.answers[slick.currentSlide].index;

                            // Set our current slide to the physical current slide, this is for the images to be shown
                            self.currentSlide = slick.currentSlide;

                            // Invoke our methods using the answer index
                            controller.afterChange(self.question, index);
                            self.onSelect({ index: index, direction: slick.direction });
                        },

                        // Set our current slide and sort/filter our products
                        afterChange: function (event, slick, currentSlide) {

                            // Get the actual index stored in the answer
                            var index = self.answers[currentSlide].index;
                            // Set our current slide to the physical current slide, this is for the images to be shown
                            self.currentSlide = currentSlide;

                            // Invoke our methods using the answer index
                            controller.afterChange(self.question, index);
                            self.onSelect({ index: index, direction: slick.direction });
                        }
                    }
                });

                // We have loaded
                self.loaded = true;
            }
        };

        // Updates the question with your selected answer
        function afterChange(question, answerIndex) {

            console.log('we are changing');

            // Get our answer
            var answers = question.answers,
                answer = answers[answerIndex];

            // Set our active image
            setActiveImage(answers, answerIndex);

            // This is for the last step, because some options might not actually be available
            if (answer) {

                // Set our selected answer
                question.radioChoice = answer.text;
            }
        };

        // Sets the active image
        function setActiveImage(answers, activeIndex) {

            // If we have a current timer running, cancel it
            if (timer)
                $timeout.cancel(timer);

            // For each answer
            answers.forEach(function (answer, index) {

                // Get our images
                var images = answer.images;

                // If we have an image
                if (images) {

                    // Get our image
                    var image = images[0];

                    // If we are active
                    if (index === activeIndex) {

                        // For each text
                        image.imageText.forEach(function (text) {
                            text.active = false;

                            // Activate our text after the delay
                            $interval(function () {
                                text.active = true;
                            }, text.delay, 1);
                        });
                    }
                }
            });
        };
    };
})();

但是我的手表有问题。它似乎没有改变选项。我已将选项添加到我的视图中,它会返回:

{"slidesToShow":1,"centerPadding":0,"event":{}}

这很有趣,因为我只通过这个:

{ slidesToShow: 1, centerPadding: 0 }

所以它正在更新一点,但实际上并没有将方法绑定到事件对象。有谁知道为什么甚至如何让它发挥作用?

【问题讨论】:

  • 请检查以下答案,是否解决了您的问题?

标签: angularjs angularjs-controlleras


【解决方案1】:

您只需关注self.answers,因为它可以通过绑定thisself 直接在控制器实例上使用,如下所示:

$scope.$watch(angular.bind(self, function () {
  return self.answers;
}), watchAnswers);

【讨论】:

  • 我不这么认为。我在if (answers.length) 后面放了一个控制台日志,然后就到了。
  • 如果使用只是观看controller.answers 看起来可以在$scope.controller.answers 上观看。所以需要绑定上下文
【解决方案2】:

这是我的错,它正确地创建了所有内容。我没有将它绑定到视图中的“控制器”。

【讨论】:

    猜你喜欢
    • 2016-06-22
    • 2017-10-01
    • 2015-07-29
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 2015-10-29
    • 2015-10-03
    • 2016-04-30
    相关资源
    最近更新 更多