我试图使元素的文本根据是否被选择而变化,但是我很难弄清楚如何引用父对象来确定选择哪个对象。

我正在尝试的简化示例:



function Model(items){
    this.items = ko.observableArray(items);
    this.selectedItem = ko.observable();
    this.dropDownText = function(item){
        if(this.selectedItem()===item){
            return item.name;
        }else{
            return item.dropDownText;
        }
    }
}

function Item(name, price){
    this.name=name;
    this.price=price;
    this.dropDownText=name + ' ($' + price + ')';
    this.dropDownTextFunction = function(item){
        return item.name + ' ($' + item.price + ')';
    }
}

var m = new Model([new Item('hammer', 5), new Item('nail', 0.03), new Item('tooth', 0.6)]);
m.selectedItem(m.items()[1]);
ko.applyBindings(m);

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

<select data-bind="options: items(), value: selectedItem, optionsText: 'dropDownText'"></select>
<span data-bind="text: selectedItem().price"></span>





价格不应显示在所选元素中,而应显示在其他元素中。

我试过的


'dropDownText'-非函数变量可以正常工作,但这不能解决问题
'dropDownTextFunction'-在下拉列表中显示函数的代码,也无法获取父对象
'dropDownTextFunction()'-结果为空的选项文本,再次无法获取父对象
'$ parent.dropDownText'-也导致空选项文本

最佳答案

这是一种解决方案,但不是我希望在我的ko应用程序中实现的一种解决方案。



function Model(items){
    var self = this;
    self.items = ko.observableArray(items);
    self.selectedItem = ko.observable();

    self.selectedItem.subscribe(function() {
      console.log('Selected');
      items.forEach(function(it) {
        if (it === self.selectedItem()) {
          it.dropDownText(it.name);
        } else {
          it.dropDownText(it.name + ' ($' + it.price + ')');
        }
      });
    });


    return self;
}

function Item(name, price){
    this.name=name;
    this.price=price;
    this.dropDownText= ko.observable(name + ' ($' + price + ')');
}

var m = new Model([new Item('hammer', 5), new Item('nail', 0.03), new Item('tooth', 0.6)]);
m.selectedItem(m.items()[1]);
ko.applyBindings(m);

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

<select data-bind="options: items(), value: selectedItem, optionsText: 'dropDownText'"></select>
<span data-bind="text: selectedItem().price"></span>





完全必要的一件事是dropDownText是可观察的,以便显示的文本在更改时可以更新。您的原始代码中缺少该代码。

我不喜欢的部分是,每当选定值更改时,就必须计算整个列表的可观察值。

一种替代方法是修改item对象和订阅,这使它更加简洁:

function Model(items){
    var self = this;
    self.items = ko.observableArray(items);
    self.selectedItem = ko.observable();
    self.selectedItem.subscribe(function() {
      items.forEach(function(it) {
        it.selected(it === self.selectedItem())
      });
    });
    return self;
}

function Item(name, price){
    var self = this;
    self.name = name;
    self.price = price;
    self.selected = ko.observable(false);
    self.dropDownText = ko.computed(function() {
      return this.selected()
          ? this.name : this.name + ' ($' + this.price + ')';
    },self);
    return self;
}


但是我真正希望的是让ViewModel处理项目的整个创建和管理。您可以使用可以像model.addItem(name,price)这样的函数调用的模型,也可以像这样的additems([{name: '', price:1}, ...])那样调用函数。如果您尝试使用此路径,您会发现实现视图模型非常清晰和容易,因为该模型需要注意自身及其所有组件。如果您想在其他代码中使用cosntructor,也可以在模型中公开它。

注意:var self=this模式简化了在模型的其他函数中使用this的工作,例如计算出的可观测值

09-25 16:03