45

是否有更短/更简洁的方法来进行 null/undefined 测试?

<select data-bind="options: SelectedBusinessLine() ? SelectedBusinessLine().Clusters() : [],
                               optionsText: 'Title',
                               value: SelectedCluster,
                               optionsCaption: 'Select Cluster..'">
            </select>

代替

data-bind="options: SelectedBusinessLine() ? SelectedBusinessLine().Clusters() : [],

我想

data-bind="options: SelectedBusinessLine().Clusters(),

给予或接受()

或者至少是一个更简单的空运算符检查'??' 选定的业务线 ?? []

或者一个绑定参数来自动检查 null 或静默失败。

如果可能的话,有什么想法吗?

4

6 回答 6

78

此页面提供了几种解决方案。相关部分是这个:

防止空对象

如果您有一个包含对象的可观察对象并且您想绑定到该对象的属性,那么您需要小心它是否有可能为空或未定义。您可以编写您的绑定,如:

<span data-bind="text: selectedItem() ? selectedItem().name() : 'unknown'"></span>

有很多方法可以处理这个问题。首选方法是简单地使用模板绑定:

var viewModel = {
  items: ko.observableArray(),
  selectedItem: ko.observable()
};

<ul data-bind="template: { name: 'editorTmpl', data: selectedItem }"></ul>
<script id="editorTmpl" type="text/html">
  <li>
    <input data-bind="value: name" />
  </li>
</script>

使用此方法,如果selectedItem为 null,则它不会渲染任何内容。因此,您不会像在原始绑定中那样看到未知。但是,它确实具有简化绑定的额外好处,因为您现在可以直接指定属性名称而不是selectedItem().name. 这是最简单的解决方案。

只是为了探索一些选项,这里有一些选择:

你可以使用一个计算的 observable,就像我们之前做的那样。

viewModel.selectedItemName = ko.computed(function() {
  var selected = this.selected();
  return selected ? selected.name() : 'unknown';
}, viewModel);

然而,这再次给我们的视图模型增加了一些我们可能不想要的膨胀,我们可能不得不对许多属性重复这一点。

您可以使用自定义绑定,例如:

<div data-bind="safeText: { value: selectedItem, property: 'name', default: 'unknown' }"></div>

ko.bindingHandlers.safeText = {
  update: function(element, valueAccessor, allBindingsAccessor) {
    var options = ko.utils.unwrapObservable(valueAccessor()),
    value = ko.utils.unwrapObservable(options.value),
    property = ko.utils.unwrapObservable(options.property),
    fallback = ko.utils.unwrapObservable(options.default) || "",
    text;

    text = value ? (options.property ? value[property] : value) : fallback;

    ko.bindingHandlers.text.update(element, function() { return text; });
  }
};

这个比原版好吗?我会说可能不会。它确实避免了我们绑定中的 JavaScript,但它仍然非常冗长。

另一种选择是创建一个增强的 observable,它提供了一种访问属性的安全方法,同时仍然允许实际值为 null。可能看起来像:

ko.safeObservable = function(initialValue) {
  var result = ko.observable(initialValue);
  result.safe = ko.dependentObservable(function() {
    return result() || {};
  });

  return result;
};

因此,这只是一个 observable,它还公开了一个名为 safe 的计算 observable,它总是返回一个空对象,但实际的 observable 可以继续存储 null。

现在,您可以像这样绑定它:

<div data-bind="text: selectedItem.safe().name"></div>

当它为 null 时,您不会看到未知值,但它至少不会在selectedItem为 null 时导致错误。

我确实认为在这种情况下首选的选项是使用模板绑定,特别是如果您有许多这些属性要绑定。

于 2012-07-08T23:52:24.167 回答
63

另一个答案引用的优秀页面中未提及的一种方法是使用with

<div data-bind="with: selecteditem">
    <form>
        <fieldset>
            <div>
                <label>first name</label>
                <input data-bind="value: firstname"></input>
            </div>
            <div>
                <label>lasst name</label>
                <input data-bind="value: lastname"></input>
            </div>
        </fieldset>
        <div>
            <a href="#" data-bind="click: $root.savechanges">Save</a>
        </div>
    </form>
</div>

如果selecteditem为 null,则整个 UI 将消失。

于 2013-04-26T20:51:25.953 回答
4

“With”有效(可能其他人也有效......)

但是使用“With”,即使里面有条件,角色 UI 也会消失/出现......例如......我需要设置一个状态(真/假)按钮,但前提是状态不为空。 .

<!-- ko ifnot: Status() == null -->
<span data-bind="if: Status">
    <a class="rk-button rk-red-action" data-bind="click: changeStatus"><i class="rk-ico rk-ico-save"></i>Desativar</a>
</span>
<span data-bind="ifnot: Status">
    <a class="rk-button rk-black-action" data-bind="click: changeStatus"><i class="rk-ico rk-ico-save"></i>Ativar</a>
</span>
<!-- /ko -->

这行得通。在这种情况下。

但有时就像 Simon_Weaver 所说的那样,只是“With”的作品!

于 2013-07-17T15:17:59.087 回答
1

我更喜欢这种方法

创建自定义绑定

ko.bindingHandlers.safeText = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        try {
            var tryGetValue = valueAccessor()();
            ko.bindingHandlers.text.update(element, valueAccessor());
        } catch (e) {
            ko.bindingHandlers.text.update(element, function () { return ""; });
        }
    }
};

用法

data-bind="safeText: function() { return my().nested.object.property; }

您需要添加的唯一额外内容是使用 'function() { return ... }' 包装原始值

但是,这将停止值调用下方的所有错误。您可以通过仅查找“未定义”异常来改进自定义绑定。您可能还想通过添加默认文本选项来改进此绑定。

于 2013-03-06T11:32:28.537 回答
1

这些解决方案中的大多数在我设置属性的特定情况下都不起作用:

<div role="combobox" data-bind="attr: {
  'aria-activedescendant': activedescendant() ? activedescendant().id : null
}">
  ...
</div>

templateand绑定在with这里不起作用,因为如果我没有活跃的后代,那么我的 div 将是空的。对于我的解决方案,我创建了一个可观察的方法:

ko.observable.fn.get = function (propertyName, defaultValue) {
    var
    self = this(),
    propertyValue;

    if (self != null) {
        propertyValue = ko.unwrap(self[propertyName]);
    }

    return propertyValue || defaultValue;
}

这使我可以将绑定更改为此:

<div role="combobox" data-bind="attr: {
  'aria-activedescendant': activedescendant.get('id')}">
  ...
</div>
于 2013-09-18T23:03:23.833 回答
1

上述大多数解决方案对我来说都不是开箱即用的,因为我只想将它应用于 a 中的单个元素,foreach所以我稍微修改了接受答案的方法:

<span data-bind="text: ((typeof info).localeCompare('undefined')) ? info : ''"></span>
于 2015-01-19T16:09:15.200 回答