javascript - 如何重构 calendarViewModel 以使其不与特定 Controller 绑定(bind)?

标签 javascript angularjs

对于一个小型 Angular.js 测试床项目,我设置了以下 plunker:

My Plunked Plunker

最初,当 calendarViewModel 直接包含在 Angular Controller 中时,我有一个可以运行的测试台的本地版本。

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)

我这样做的原因是因为理论上多个 Controller 可能需要与calendarViewModels绑定(bind)的日历(这就是我创建calendarViewModel功能对象的原因首先。)我希望 calendarViewModel 构造不绑定(bind)到特定的 Controller ,但是,我显然通过以这种方式重构它来破坏它。

我认为我走在正确的道路上,但无论如何,显然缺少了一些东西。我的问题:重构我的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;

});
  • 执行此操作时,您的工厂会自动在 Controller 之间共享:

_

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

}]);

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

}]);

...如果 Controller 在 html 中并行定义。如果它们是嵌套的,您只需在顶层注入(inject)您的服务即可。理想情况下,您只需要在 Controller 中 DI 几个服务并将它们分配给范围。

这能回答你的问题吗?

PS:hideAll 没有在你的plunker 中定义,我将其注释掉,事情开始工作。

编辑:这个编辑过的plnkr应该做你想要的:http://plnkr.co/edit/7VDYDQhK2CDGnwa8qhWf?p=preview

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

相关文章:

javascript - 无法禁用简单的 a 标签

javascript - Angular ngMessages 对模糊的验证取消了链接/按钮点击

http - 具有 CORS 和自定义 header 的 AngularJS

javascript - 在 Mocha 上循环()

javascript - 使用js代码在SharePoint中隐藏页面标题

JavaScript setTimeout 和更改系统时间会导致问题

javascript - 如何处理 Meteor.js Accounts.registerLoginHandler 中的异步代码

javascript - 垂直或水平页面滚动

angularjs - 从客户端或服务器上传到 S3?

javascript - $http 在 Angular 1.4.8 中使用 Rest Controller