为什么在加载 knockoutJs 时调用下拉列表的订阅事件?

Why subscribe event of dropdown is being called on load knockoutJs?

这可能是一个基本问题,但我无法得到任何解决方案。

我正在尝试在下拉列表中显示格式列表。我正在使用敲除绑定来这样做。 I want to show a specific value initially.

当用户从下拉列表中选择其他值时,它应该显示所选值(工作正常)。

在选择任何选项时,我想获取选定的值,以便将其发送到服务器。为此,我正在使用 subscribe

下面是我的代码:

var obj = this;
obj.formatArray = ko.observableArray([{'text' : "MM/DD/YYYY"},
  {'text' : "MM-DD-YYYY"},
  {'text' : "MM.DD.YYYY"},
  {'text' : "DD/MM/YYYY"},
  {'text' : "DD-MM-YYYY"},
  {'text' : "DD.MM.YYYY"}]);

var format1 = 'DD-MM-YYYY';

obj.formatArrayDefault = ko.observable({text :format1});

obj.formatArrayDefault.subscribe(function(newValue){
alert("default value " + format1);
alert("new value in subscribe " + newValue.text);
});

ko.applyBindings(obj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<select class="" data-bind="options:formatArray(),optionsText:'text',value:formatArrayDefault"></select>

您可以 运行 上面的代码片段并检查,subscribe 中的 alert 正在加载并将要显示的值更改为 first value in the array

为什么在加载时调用 subscribe 以及为什么将值更改为第一个值?

我做错了什么?

如果问题是重复的,有人可以给 link 解决方案吗(我在这里搜索但找不到任何解决方案)。

如果您只需要任何更改后的下拉列表值。

只需要一个 observable 并将其设置为下拉列表的值,最初它将是空白的,如果下拉列表的值为空,则在您的订阅函数中添加一行比较,不要调用警报函数。

var obj = this;
obj.formatArray = ko.observableArray([{'text' : "MM/DD/YYYY"},
{'text' : "MM-DD-YYYY"},
{'text' : "MM.DD.YYYY"},
{'text' : "DD/MM/YYYY"},
{'text' : "DD-MM-YYYY"},
{'text' : "DD.MM.YYYY"}]);

var format1 = 'DD-MM-YYYY';
obj.initialLoad = true;

obj.formatArrayDefault = ko.observable(format1);

obj.formatArrayDefault.subscribe(function(newValue){

if(obj.initialLoad) {
 obj.initialLoad = false;
 }
 else {
  alert("Hello");   
  }
  });

  ko.applyBindings(obj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<select class="projectUserAccess workflowSetOptions" data-bind="options:formatArray(),optionsText:'text',value:formatArrayDefault"></select>

===编辑===

$(document).ready(function(){
    var model = {
        selectedType: 2 //default Type
    };
    
    var viewModel = {
        selectedType: ko.observable(model.selectedType)
        , availableTypes: ko.observableArray([
            { Label: 'Type1', Code: 1 }
            , { Label: 'Type2', Code: 2 }
            , { Label: 'Type3', Code: 3 }
        ])
    };
                
    ko.applyBindings(viewModel, $("#content")[0]);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content">
    <select data-bind="value: selectedType, options: availableTypes, optionsText: 'Label', optionsValue: 'Code', optionsCaption: 'Please select...'"></select><br/>
    
    You've selected Type: <span data-bind="text: selectedType"></span>
</div>

您的数组包含普通对象。在 javascript 中,对象比较是这样工作的:

var obj1 = { a: 1 };
var obj2 = { a: 1 };

console.log(obj1 === obj2); // false
console.log(obj1 === obj1); // true

它检查变量引用的实际对象实例,而不是它看起来的样子。许多库包含一个 "deepEquals" 函数,您可以使用它来检查两个对象是否实际上 看起来 相似,但 knockout 不使用这种机制。

因此当您设置初始选择时,它的值可能与 formatArray()[0] 处的对象相似,但敲除将无法将两者匹配在一起.即:

obj.formatArrayDefault() === obj.formatArray()[1]; // false

现在,在应用绑定时,knockout 会尝试解决选择和源数据之间的不匹配问题。它找不到与传递给 value 绑定的选择相匹配的 <option> 元素。

它必须呈现一个选定的选项,所以它默认为第一个。这是当您的初始对象被 formatArray()[0] 替换并触发订阅时。

这是一个解决方案:我们在初始值中放置对第一个对象的实际引用!

var obj = this;
obj.formatArray = ko.observableArray([{'text' : "MM/DD/YYYY"},
  {'text' : "MM-DD-YYYY"},
  {'text' : "MM.DD.YYYY"},
  {'text' : "DD/MM/YYYY"},
  {'text' : "DD-MM-YYYY"},
  {'text' : "DD.MM.YYYY"}]);

var format1 = 'DD-MM-YYYY';

obj.formatArrayDefault = ko.observable(obj.formatArray()[1]);

obj.formatArrayDefault.subscribe(function(newValue){
  console.log("default value " + format1);
  console.log("new value in subscribe " + newValue.text);
});

ko.applyBindings(obj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<select class="" data-bind="options:formatArray(),optionsText:'text',value:formatArrayDefault"></select>