在挖掘和durandal的揭示原型模式中对“this”的困惑

时间:2013-10-23 17:01:49

标签: javascript knockout.js revealing-prototype

我正在尝试为我的应用程序创建基本视图模型,但我正在努力访问基本视图模型的上下文。

这是我的基本视图模型:

define(["config", 'services/logger'], function (config, logger) {
    'use strict';
    var
    app = require('durandal/app'),
    baseViewModel = function () {
        this.items = ko.observableArray();
        this.title = ko.observable();
        this.selectedItem = ko.observable();
    };
    baseViewModel.prototype = (function () {
        var
        populateCollection = function (initialData, model) {
            var self = this;
            if (_.isEmpty(self.items())) {
                ko.utils.arrayForEach(initialData, function (item) {
                    // self here works for all extending modules such as users
                    self.items.push(new model(item));
                });
            }
        },
        deleteItem = function (item) {
            // "this" here same as prototype gives me window object :(
            // so removing never happes
            this.items.remove(item);
            logger.log(config.messages.userMessages.confirmDeleted(item.Name()), {}, '', true);
        },
        confirmDelete = function (item) {
            var
            userMessage = config.messages.userMessages.confirmDelete(item.Type(), item.Name()),
            negation = config.confirmationModalOptions.negation,
            affirmation = config.confirmationModalOptions.affirmation;

            app.showMessage(userMessage, 'Deleting ' + item.Type(), [affirmation, negation]).then(
                function (dialogResult) {
                    dialogResult === affirmation ? deleteItem(item) : false;
                });
        };
        return {
            populateCollection: populateCollection,
            confirmDelete: confirmDelete,
            deleteItem: deleteItem
        }
    })();
    return baseViewModel;
});

以及我使用这种非工作事物的例子是:

define(['services/logger', 'models/user', 'viewmodels/baseviewmodel', 'services/dataservice'], function (logger, user, baseviewmodel, dataservice) {
    var
    users = new baseviewmodel();
    users.title('Users')
    users.searchTerm = ko.observable().extend({ persist: users.title() + '-searchterm' });
    users.activate = function () {
        this.populateCollection(dataservice.getUsers, user.model);
    }
    return users;
});

使用populateCollection正确填充项目。 confirmDelete也在模板中正确绑定,这可能是由于不需要上下文 但deleteItem需要上下文,因此可以访问items并在其上调用remove

  

如何正确访问this作为baseViewModel的上下文   所以我可以用这种模式轻松地在我的方法中引用它?

非常感谢

1 个答案:

答案 0 :(得分:1)

编辑:看起来好像this未在deleteItem中正确绑定,因为它是在confirmDelete内部的回调中调用的。因此,请在原始模型上尝试此片段

    confirmDelete = function (item) {
        var self=this,
        userMessage = config.messages.userMessages.confirmDelete(item.Type(), item.Name()),
        negation = config.confirmationModalOptions.negation,
        affirmation = config.confirmationModalOptions.affirmation;

        app.showMessage(userMessage, 'Deleting ' + item.Type(), [affirmation, negation]).then(
            function (dialogResult) {
                dialogResult === affirmation ? self.deleteItem.call(self,item) : false;
            });
    };
orrr,我的另一种解决方案。

我之前从未使用过'揭示原型模式',所以这里是如何做到这一点而不遵守我们都不理解的模式:)

我将所有内容声明为我的viewmodel的属性并使用var self = this,这样我的所有代码都非常明确。这是你的baseviewmodel,重写。如果所有viewmodel逻辑都封装在viewmodel中,并且viewmodel在构造函数/函数定义中声明其依赖项,则通常很有帮助。

baseViewModel = function (dataService,userModel) {
    var self = this;
    self.items = ko.observableArray();
    self.title = ko.observable();
    self.searchTerm = ko.observable().extend({ persist: self.title() + '-searchterm' });
    self.selectedItem = ko.observable();

    self.populateCollection = function (initialData, model) {
        if (_.isEmpty(self.items())) {
            ko.utils.arrayForEach(initialData, function (item) {
                // self here works for all extending modules such as users
                self.items.push(new model(item));
            });
        }
    };

    self.activate = function () {
        this.populateCollection(dataservice.getUsers, userModel);
    }

    self.deleteItem = function (item) {
        // "this" here same as prototype gives me window object :(
        // so removing never happes
        self.items.remove(item);
        logger.log(config.messages.userMessages.confirmDeleted(item.Name()), {}, '', true);
    };

    self.confirmDelete = function (item) {
        var
        userMessage = config.messages.userMessages.confirmDelete(item.Type(), item.Name()),
        negation = config.confirmationModalOptions.negation,
        affirmation = config.confirmationModalOptions.affirmation;

        app.showMessage(userMessage, 'Deleting ' + item.Type(), [affirmation, negation]).then(
            function (dialogResult) {
                dialogResult === affirmation ? self.deleteItem(item) : false;
            });
    };
};

请注意,因为我还将您的依赖项移动到viewmodel构造函数中,现在您的初始化代码如下所示:

define(['services/logger', 'models/user', 'viewmodels/baseviewmodel', 'services/dataservice'], function (logger, user, baseviewmodel, dataservice) {
    var users = new baseviewmodel(dataservice,user.model);
    users.title('Users')
    return users;
});