对于一个小型Angular.js测试平台项目,我设置了以下代码:

My Plunked Plunker

最初,当calendarViewModel直接包含在Angular控制器中时,我具有该测试平台的本地版本。

appControllers.controller('PageController', [
    '$scope', '$http', 'Enums', 'ViewModels',

    function ($scope, $http, Enums, ViewModels) {
        var calendarViewModel = function () {
            var pub = {};

            pub.date = new Date();
            pub.isOpen = false;

            pub.today = function () {
                if(pub.isOpen)
                    pub.date = new Date();
            };

            pub.clear = function () {
                if(pub.isOpen)
                    pub.date = null;
            };

            pub.hide = function () {
                pub.isOpen = false;
            };

            pub.toggle = function ($event) {
                $event.preventDefault();
                $event.stopPropagation();

                $scope.hideCalendars();
                pub.isOpen = !pub.isOpen;
            };

            return pub;
        };

        // Backing model for this 'controller'
        $scope.viewModel = {
            // Properties:
            startCalendar: new calendarViewModel(),
            endCalendar: new calendarViewModel(),

            // data:
            // Generates an object that is sent to the server with $http calls.
            data: function () {
                var object = {
                    startDate: startCalendar.date.toString(),
                    endDate: endCalendar.date.toString()
                };

                return JSON.stringify(object);
            }
        };

        // - Controller-specific functions... ----------------------------------
        $scope.hideCalendars = function () {
            $scope.viewModel.startCalendar.hide();
            $scope.viewModel.endCalendar.hide();
        };

        $scope.clear = function () {
            $scope.viewModel.startCalendar.clear();
            $scope.viewModel.endCalendar.clear();
        };

        $scope.today = function () {
            $scope.viewModel.startCalendar.today();
            $scope.viewModel.endCalendar.today();
        };

        // Restricts certain days from being selected.
        $scope.disableWeekends = function (date, mode) {
            return mode === 'day'
                   && (date.getDay() === Enums.DaysOfTheWeek.Sunday
                      || date.getDay() === Enums.DaysOfTheWeek.Saturday);
        };

        // This is a demonstration scope action.  Pretty much, the pattern
        // I found, is to have a view model expose a method that creates
        // a stringified JSON blob that we can send to the server.  This
        // method is how such a save function would work.
        $scope.save = function () {
            var promise = $http({
                method: 'POST',
                url: '/some/server/url',
                data: $scope.viewModel.data()
            });

            promise.success(function (data) {
                // Do something with the returned data?
            }).error(function (data) {
                // Do something with the error data?
            });
        };
        // - End of Controller-specific functions... ---------------------------

        // Picker-specific options...
        $scope.dateOptions = {
            'starting-day': Enums.DaysOfTheWeek.Monday,
            'format-day': 'dd',
            'format-month': 'MM',
            'format-year': 'yyyy',
            'min-mode': Enums.PickerMode.Day,
            'max-mode': Enums.PickerMode.Year
        };

        $scope.format = 'MM/dd/yyyy';
        $scope.today();
    }
]);


但是,由于我将其重构为ViewModels常量对象,因此我从Angular中收到以下错误:

TypeError: undefined is not a function
at Object.pub.toggle (http://run.plnkr.co/AKUBdEb5M3KT5DM9/app.services.js:31:4)
at http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js:10185:21
at http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js:17835:17
at Scope.$eval (http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js:11936:28)
at Scope.$apply (http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js:12036:23)
at HTMLInputElement.<anonymous> (http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js:17834:21)
at http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js:2613:10
at forEach (http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js:310:20)


之所以这样做,是因为从理论上讲,多个控制器可能需要绑定到calendarViewModels的日历(这就是为什么我首先创建calendarViewModel功能对象的原因。)我想要calendarViewModel构造而不是绑定到特定的控制器,但是,通过这种方式对其进行重构显然已经破坏了它。

我认为我走在正确的道路上,但是无论如何,显然缺少某些东西。我的问题:对我来说,重构我的calendarViewModel的正确方法是什么,它可以工作并且更易于重用?

最佳答案

因此,您的小伙子们有几件事:


不要使用app.constant做工厂。请改用app.factory,例如:


_

appServices.factory('ViewModels', function() {

    var pub = {};

    pub.date = new Date();
    pub.isOpen = false;

    pub.today = function () {
        if(pub.isOpen)
            pub.date = new Date();
    };

    pub.clear = function () {
        if(pub.isOpen)
            pub.date = null;
    };

    pub.hide = function () {
        pub.isOpen = false;
    };

    pub.toggle = function ($event) {
        $event.preventDefault();
        $event.stopPropagation();

        //hideAll();
        pub.isOpen = !pub.isOpen;
    };

    return pub;

});



执行以下操作时,将自动在控制器之间共享工厂:


_

appControllers.controller('FirstController', [ '$scope', 'MyCalendarService', function($scope, MyCalendarService){
  $scope.myCalendarService = MyCalendarService;

}]);

appControllers.controller('SecondController', [ '$scope', 'MyCalendarService', function($scope, MyCalendarService){
  $scope.myCalendarService = MyCalendarService;

}]);


...如果控制器在html中并行定义。如果它们是嵌套的,则只需要在顶层注入服务即可。理想情况下,您只需要在控制器中添加几个服务并将它们分配给作用域即可。

这是否回答你的问题?

PS:hideAll在您的插件中没有定义,我注释掉了它,事情开始起作用。

编辑:此编辑的plnkr应该执行您想要的操作:http://plnkr.co/edit/7VDYDQhK2CDGnwa8qhWf?p=preview

关于javascript - 如何重构CalendarViewModel使其不绑定(bind)到特定 Controller ?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25000886/

10-13 04:12