Подтвердить что ты не робот

KnockoutJS, когда источник равен null/undefined

Есть ли более короткий/более чистый способ выполнить тестирование 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(),

введите или возьмите()

Или, по крайней мере, более простая проверка нулевого оператора '??' ВыбраннаяBusinessLine?? []

Или параметр привязки для автоматической проверки на отказ или молчание.

Любые идеи, если это возможно?

4b9b3361

Ответ 1

Эта страница содержит несколько решений. Соответствующая часть такова:

Защита от нулевых объектов

Если у вас есть наблюдаемый, который содержит объект, и вы хотите привязываться к свойствам этого объекта, тогда вам нужно быть осторожным, если есть вероятность, что он может быть нулевым или undefined. Вы можете написать свою привязку, например:

<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. Это самое простое решение.

Просто для изучения некоторых вариантов, вот несколько альтернатив:

Вы можете использовать вычисленное наблюдаемое, как это было раньше.

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 в нашей привязке, но он все еще довольно многословный.

Еще один вариант - создать расширенный наблюдаемый, который обеспечивает безопасный способ доступа к свойствам, сохраняя при этом фактическое значение null. Может выглядеть так:

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

  return result;
};

Итак, это просто наблюдаемое, которое также предоставляет вычисленный наблюдаемый именованный сейф, который всегда будет возвращать пустой объект, но фактический наблюдаемый может продолжать хранить нуль.

Теперь вы можете привязать к нему, как:

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

Вы не увидите неизвестное значение, когда оно равно null, но оно по крайней мере не вызовет ошибку, если selectedItem имеет значение null.

Я думаю, что предпочтительным вариантом будет использование привязки шаблона в этом случае, особенно если у вас есть много этих свойств для привязки.

Ответ 2

Один из способов, не упомянутых в в противном случае отличной странице, на который ссылается другой ответ, заключается в использовании 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.

Ответ 3

Работы "С" (возможно, другие тоже работают...)

Но с "С" роль UI исчезает/появляется даже при наличии условий внутри... Например... Мне нужно установить кнопку состояния (true/false), но только если статус не является нуль...

<!-- 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 -->

Это работает. В этом случае.

Но иногда просто "С" работает, как говорит Симон_Вивер!

Ответ 4

Я предпочитаю этот метод

Создать пользовательскую привязку

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; }

Единственным дополнительным материалом, который вам нужно добавить, является обернуть исходное значение с помощью функции() {return...} '

Это, однако, остановит все ошибки под вызовом значения. Вы можете улучшить пользовательскую привязку, только выбрав "undefined" исключения. Вы также можете улучшить эту привязку, добавив в текстовый вариант по умолчанию.

Ответ 5

Большинство из этих решений не работают в определенном случае для меня, где я устанавливаю атрибут:

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

Связи template и 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>

Ответ 6

Большинство из вышеперечисленных решений не работало для меня совершенно из коробки, так как я только хотел применить это к одному элементу в foreach, поэтому немного изменил принятый подход ответа:

<span data-bind="text: ((typeof info).localeCompare('undefined')) ? info : ''"></span>