以编程方式设置时,HTML组合框显示的项目不正确

时间:2018-02-12 17:21:01

标签: javascript knockout.js

在开始之前,我可以断言我不是网络开发人员。我正在尝试修复我们的小型Web应用程序(用于配置嵌入式设备)中的以下错误,因为编写它的网络流畅的开发人员不再需要指针。我会尽力解释我能做些什么。

此特定网页设置为允许用户配置和监控音频处理设备上的值。当用户更改页面上的值时,页面会向设备发送RPC请求以在其中设置值。当通过其他方式(例如,通过输入屏幕手动)更改设备上的值时,将向网页发送JSON通知,并通过JavaScript更新相关控件。该网页使用Bootstrap作为UI,并使用Knockout确保每当值(我们称之为"参数"在设备上)发生更改时,相关控件都会更新。

我遇到的问题是组合框(即通过HTML中的<select><option>标记构建的控件)有时在通过JavaScript更改时不会显示相应的值。如果用户选择组合框中的项目,并且稍后在设备上更改相应的值(并通过JavaScript传播回网页),则组合框将不再能够显示用户最初选择的项目 - 而是,它将显示第一个项目。

例如,使用包含项目A,B,C,D和E的组合框:

用户选择:D。

从设备向网页发送值时:

  • 项目A显示为A
  • 项目B显示为B
  • 项目C显示为C
  • 项目D显示为A
  • 项目E显示为E

如果用户没有与组合框进行交互,则不会发生这种情况 - 在这种情况下,设备通知页面的任何值都将正确显示。

我没有足够的经验知道所有血腥细节如何在幕后工作,但我已经进行了足够深入的研究以了解以下内容:

  • 当通过JavaScript更改值时,组合框响应Knockout可观察的更改。我并非100%确定这一切是如何连接起来的,但在Knockout在组合框中需要的data-bind属性中,foreach设置为$data.widgetData.options等等。我不知道这是否相关。
  • 在所有情况下,对应于组合框的Knockout observable上设置的值与所需组合框选项的value属性完全匹配。我通过创建Knockout observable的另一个手动订阅并在更改时注销该值来确认这一点。
  • 更改Knockout可观察值时,会在正确的组合框选项上设置selected属性,并从之前选择的任何选项中删除。在两种情况下都会正确发生这种情况(当组合框显示正确的当前值时,以及当它没有时)。当用户通过用户界面选择项目时,这也会正确发生,这让我相信它不是问题的原因。

简而言之:一旦用户选择了一个项目至少一次,并且以编程方式对组合框进行了进一步更改,所有与HTML相关的修改出现与以前完全相同 - 除了组合框没有显示用户选择的一个项目的正确内容。

当页面上出现组合框时,HTML最终会看起来像这样:

<select
  class="form-control"
  data-bind="
    attr: { 
      'data-panelid': panelData.__hierarchyId,
      'data-paramtrigger': widgetData.paramTrigger,
      'data-widgetref': widgetData.ref,
      'data-menuRef': widgetData.menuRef,
      'data-widgetNotifyType': widgetData.notifyType
    },
    disable: ($data.widgetData.disabled ? $data.widgetData.disabled : false), 
    foreach: $data.widgetData.options
  "
  data-panelid="system-1-mpx-1"
  data-widgetref="dspx.enum.8"
>
  <option data-bind="
    attr: {
      'data-paramtrigger': $parents[0].widgetData.paramTrigger,
      'value': $data.name,
      'selected': ($root.remoteParameterObservables[$parents[0].widgetData.ref]() == $data.name ? 'selected' : null),
      'data-notifyType': $parents[0].widgetData.notifyType
    },
    text: ($data.webName ? webName : ($data.displayName ? displayName : name))
  "
  value="none">none</option>
  <!-- ... etc ... -->
</select>

(为了便于阅读,添加了空格/换行符。)

同样,我并不是100%确定这个具体对我们的设置有多少,以及Knockout需要多少是一部分。

组合框可能有这样的表现吗?很可能我们的Javascript代码中存在导致问题的东西,但由于我不熟悉这些类型的Web技术,我想首先看看原因是否可能是某些原因更明显。

修改

对于上下文,这是Javascript的精简版本,用于处理来自设备的值更改通知:

// Called when a notification is received from the device.
var onNotify = function(data)
{
    // If we have a KO observable for the parameter on the device with this name
    // (eg. "system.param.1"):
    if (remoteViewModel.remoteParameterObservables.hasOwnProperty(data.name))
    {
        try
        {
            // Set the value of the observable.
            remoteViewModel.remoteParameterObservables[data.name](data.value);
        }
        catch (e)
        {
            console.debug('Param `' + param + '` on remoteViewModel.remoteParameterObservables is not a knockout observable');
        }
    }
}

// ...

// Elsewhere, when creating KO observables, I inserted this for debugging purposes.
// This function always prints out the value I expect, whenever the observable is changed.
if ( parameterName === "param.im.testing.with" )
{
    observableForThisParam.subscribe(function(newValue)
    {
        console.log("Parameter was updated with a new value:", newValue);
    });
}

0 个答案:

没有答案