为什么John Papa在正常初始化时使用Object.defineProperty?

时间:2015-08-13 18:40:33

标签: javascript angularjs object properties coding-style

背景:在此示例中,john papa使用Object.defineProperty(vm, 'canSave', {get: canSave});作为禁用和启用按钮的方法。我没有经过测试,但我认为这种禁用会在交易成功之前发生。

问题:为什么他在Object.defineProperty上使用vm初始化canSave属性?此外,我怎样才能或何时应该在我未来的工作中使用这种做法?

控制器:

(function() {
    'use strict';

    angular
        .module('app.speaker')
        .controller('SpeakerDetail', SpeakerDetail);

    SpeakerDetail.$inject = [
        '$location', '$scope', '$routeParams', '$window',
        'common', 'config', 'datacontext', 'model'
    ];

    function SpeakerDetail(
        $location, $scope, $routeParams, $window,
        common, config, datacontext, model) {
        /*jshint validthis: true */
        var vm = this;
        var entityName = model.entityNames.speaker;
        var logger = common.logger;
        var $q = common.$q;
        var wipEntityKey;

        vm.cancel = cancel;
        vm.goBack = goBack;
        vm.hasChanges = false;
        vm.isSaving = false;
        vm.save = save;
        vm.speaker = null;
        vm.speakers = [];

        Object.defineProperty(vm, 'canSave', {get: canSave});

        activate();

        function activate() {
            onDestroy();
            onHasChanges();
//            TODO: Using a resolver on all routes or datacontext.ready in every controller
//            return datacontext.ready([getRequestedSpeaker()]).then(onEveryChange);
            return getRequestedSpeaker().then(onEveryChange);
        }

        function autoStoreWip(immediate) {
            common.debouncedThrottle('speakerdetail', storeWipEntity, 1000, immediate);
        }

        function cancel() {
            datacontext.cancel();
            removeWipEntity();
            common.replaceLocationUrlGuidWithId(vm.speaker.id);
            if (vm.speaker.entityAspect.entityState.isDetached()) {
                gotoSpeakers();
            }
        }

        function canSave() {
            return vm.hasChanges && !vm.isSaving;
        }

        function getRequestedSpeaker() {
            var val = $routeParams.id;
            if (val === 'new') {
                vm.speaker = datacontext.speaker.create();
                return vm.speaker;
            }

            return datacontext.speaker.getEntityByIdOrFromWip(val)
                .then(function(data) {
                    if (data) {
                        // data is either an entity or an {entity, wipKey} pair
                        wipEntityKey = data.key;
                        vm.speaker = data.entity || data;
                    } else {
                        logger.warning('Could not find session id = ' + val);
                        gotoSpeakers();
                    }
                })
                .catch(function(error) {
                    logger.error('Error while getting speaker id = ' + val + '; ' + error);
                    gotoSpeakers();
                });
        }

        function goBack() {
            $window.history.back();
        }

        function gotoSpeakers() {
            $location.path('/speakers');
        }

        function onDestroy() {
            $scope.$on('$destroy', function() {
                autoStoreWip(true);
                datacontext.cancel();
            });
        }

        function onEveryChange() {
            $scope.$on(config.events.entitiesChanged, function(event, data) {
                autoStoreWip();
            });
        }

        function onHasChanges() {
            $scope.$on(config.events.hasChangesChanged,
                function(event, data) {
                    vm.hasChanges = data.hasChanges;
                });
        }

        function removeWipEntity() {
            datacontext.zStorageWip.removeWipEntity(wipEntityKey);
        }

        function save() {
            if (!canSave()) {
                return $q.when(null);
            } // Must return a promise

            vm.isSaving = true;
            return datacontext.save().then(function(saveResult) {
                vm.isSaving = false;
                removeWipEntity();
                common.replaceLocationUrlGuidWithId(vm.speaker.id);
            }).catch(function(error) {
                vm.isSaving = false;
            });
        }

        function storeWipEntity() {
            if (!vm.speaker) {
                return;
            }
            var description = (vm.speaker.fullName || '[New speaker]') + ' ' + vm.speaker.id;
            var routeState = 'speaker';
            wipEntityKey = datacontext.zStorageWip.storeWipEntity(
                vm.speaker, wipEntityKey, entityName, description, routeState);
        }
    }
})();

HTML:

<section id="speaker-view" class="mainbar"
         data-ng-controller="SpeakerDetail as vm">
    <section class="matter">
        <div class="container">
            <div>
                <button class="btn btn-info btn-form-md"
                        data-ng-click="vm.goBack()">
                    <i class="fa fa-hand-o-left"></i>Back
                </button>
                <button class="btn btn-info btn-form-md"
                        data-ng-click="vm.cancel()" data-ng-disabled="!vm.canSave">
                    <i class="fa fa-undo"></i>Cancel
                </button>
                <button class="btn btn-info btn-form-md"
                        data-ng-click="vm.save()" data-ng-disabled="!vm.canSave">
                    <i class="fa fa-save"></i>Save
                </button>

                <!--Need ng-hide for show/hide animations-->
                <span data-ng-show="vm.hasChanges" class="dissolve-animation ng-hide flag-haschanges">
                    <i class="fa fa-asterisk fa fa-asterisk-large" rel="tooltip" title="You have changes"></i>
                </span>
            </div>
            <div class="widget wgreen">
                <div data-cc-widget-header title="Edit {{vm.speaker.fullName || 'New Speaker'}}"></div>
                <div class="widget-content user">
                    <div class="form-group">
                        <label class="control-label">First Name</label>

                        <div>
                            <input class="form-control"
                                   data-ng-model="vm.speaker.firstName"
                                   data-z-validate
                                   placeholder="First Name"/>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label">Last Name</label>

                        <div>
                            <input class="form-control"
                                   data-ng-model="vm.speaker.lastName"
                                   data-z-validate
                                   placeholder="Last Name"/>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label">Email</label>

                        <div>
                            <input class="form-control"
                                   data-ng-model="vm.speaker.email"
                                   data-z-validate
                                   placeholder="Email"/>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label">Blog</label>

                        <div>
                            <input class="form-control"
                                   data-ng-model="vm.speaker.blog"
                                   data-z-validate
                                   placeholder="Blog"/>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label">Twitter</label>

                        <div>
                            <input class="form-control"
                                   data-ng-model="vm.speaker.twitter"
                                   data-z-validate
                                   placeholder="Twitter"/>
                        </div>
                    </div>
                    <div class="form-group">
                        <img data-cc-img-person="{{vm.speaker.imageSource}}" class="img-thumbnail"/>
                    </div>
                    <div class="form-group">
                        <label class="control-label">Bio</label>

                        <div>
                            <textarea class="form-control"
                                      data-ng-model="vm.speaker.bio"
                                      data-z-validate
                                      placeholder="Enter speaker bio"></textarea>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>
</section>

1 个答案:

答案 0 :(得分:0)

John Papa正在使用它来演示您可以直接向viewmodel添加属性,这不是必需的或必需的。它可以像一个功能一样容易地完成。它是一个抽象层,使html中的代码更容易阅读。

最终,它只是html中绑定语法的差异。因此,而不是使数据-ng-disabled =&#34; {{vm.canSave()}}&#34;你可以简单地使用data-ng-disabled =&#34;!vm.canSave&#34;让模型担心实现细节。