简体   繁体   English

淘汰赛-通过在对象上设置属性来更改对象的“子类”

[英]Knockout - change an object's 'subclass' by setting a property on it

In Knockout, I have an array of Setting entities which may be of different types (ie 'subclasses' of the Setting entity). 在淘汰赛中,我有一组Setting实体,它们可能是不同类型的 (即,设置实体的“子类”)。 These types are dynamic, they may be changed by the user in the UI. 这些类型是动态的,用户可以在UI中更改它们。 Depending on what type the Setting entity is, it requires different object properties, and makes others redundant. 根据设置实体的类型,它需要不同的对象属性,并使其他实体冗余。

What I'm currently doing (which I want to change), is defining one Setting constructor which has all required properties for all setting types; 我当前正在做的(我要更改)是定义一个Setting构造函数,该构造函数具有所有设置类型的所有必需属性; making the constructor quite huge, and containing a lot of unnecessary properties. 使构造函数非常庞大,并包含许多不必要的属性。 When the app data is saved I 'ignore' the properties which shouldn't be on Setting instances according to their types. 保存应用程序数据后,我会“忽略”不应根据其类型设置实例的属性。

I've given it a try in this fiddle , using a subscription on the type property to add/ remove properties on type change. 我给它一个尝试这种小提琴 ,用在订阅type属性添加/移除类型更改属性。 I'd like to know if it is possible in KnockoutJS to reliably change the properties on an object during run-time (ie will the subscription always fire before the template is updated? ) and will this have any [positive] impact on performance? 我想知道在KnockoutJS中是否可以在运行时可靠地更改对象的属性 (即,是否总是在更新模板之前启动订阅?),这会对性能产生[正面]影响吗? . Or is this approach totally wrong and should I replace the entire object with a subclass instance (if so, won't the subscriptions go lost)? 还是这种方法是完全错误的,我应该用子类实例替换整个对象(如果这样,订阅不会丢失)?

EDIT: The dependant properties are actual data (so they should be saved to their models, not only available in the view). 编辑:从属属性是实际数据(因此它们应保存到其模型中,不仅在视图中可用)。 I've tried the component approach but how do I retrieve their properties later? 我尝试了组件方法,但是以后如何检索它们的属性? http://jsfiddle.net/kevinvanlierde/zmx3u4an/1/ http://jsfiddle.net/kevinvanlierde/zmx3u4an/1/

Use components that are bound in your settings editor but owned by each individual subclass instance. 使用在设置编辑器中绑定但由每个单独的子类实例拥有的组件。

<div data-bind="foreach: settings">
    <select data-bind="options: $root.types, value: type"></select>
    <input type="text" data-bind="textInput: value"/>
    <div data-bind="component: { name: componentName, params: componentParams }"></div>
</div>

Example component name/params for the color setting. 颜色设置的示例组件名称/参数。 These properties would be different for different settings subclasses. 对于不同的设置子类,这些属性将有所不同。

this.componentName = 'color-viewer';
this.componentParams = {
    colorText: this.value,
};

With this approach, changing the current setting "type" would require you to replace one settings subclass instance with another. 使用这种方法,更改当前设置“类型”将需要您将一个设置子类实例替换为另一个。 This might be a hassle in a trivial case but there's advantages to keeping your models small with a single responsibility. 在琐碎的情况下这可能会很麻烦,但是将模型缩小到一个单一的职责是有好处的。

To address saving the properties, I reworked the component code. 为了解决保存属性的问题,我重新编写了组件代码。 Some members (mostly computeds) are only for the view, and should not be saved, so I put the save-able stuff in a "data" member: 一些成员(大多数是计算成员)仅用于视图,不应保存,因此我将可保存的内容放入“数据”成员中:

function Setting(params) {
    var self = this;
    // What getData fetches
    self.data = {
        type: ko.observable(params.type),
        value: ko.observable(params.value || '')
    };
    self.data.type.subscribe(function (value) {
        // Give the conversion a little time
        setTimeout(function () {
            console.log("GetData:", self.getData());
        }, 30);
    });
}

Each specialized type is going to add its special members to the base object, and will add a method, toSetting , to revert it back to the base object type. 每个特殊类型都将其特殊成员添加到基础对象,并将添加方法toSetting ,以将其恢复为基础对象类型。 The base type has a do-nothing version of toSetting in its prototype, so it is always safe to call toSetting first thing in the type converter. 基本类型在其原型中具有toSetting版本,因此在类型转换器中首先调用toSetting总是很安全的。

I added a headingSize parameter to the Title type, and made it determine what heading size the text displays in. 我向Title类型添加了headingSize参数,并确定了文本所显示的标题尺寸。

function toTitle(setting) {
    var self = setting;
    var data = setting.data;
    var value = data.value();
    self.toSetting();
    data.headingSize = ko.observable(4);
    self.capitalized = ko.computed(function () {
        return value ? value.slice(0, 1).toUpperCase() + value.slice(1) : '';
    });
    self.headerText = ko.computed(function () {
        return '<h' + data.headingSize() + '>' + self.capitalized() + '</h' + data.headingSize() + '>';
    });
    self.toSetting = function () {
        delete self.data.headingSize;
        delete self.capitalized;
        delete self.toSetting;
    };
    return self;
}

I registered it like this: 我这样注册:

ko.components.register('title', {
    viewModel: toTitle,
    template: '<select data-bind="options:$root.sizes, value: data.headingSize"></select><div data-bind="html:headerText"></div>'
});

And I added a button to "save" the settings, which displays what will be saved at the bottom of the page. 然后,我添加了一个按钮来“保存”设置,该按钮将在页面底部显示要保存的内容。

http://jsfiddle.net/1kfvesq3/3/ http://jsfiddle.net/1kfvesq3/3/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM