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?? []
Или параметр привязки для автоматической проверки на отказ или молчание.
Любые идеи, если это возможно?
Ответы
Ответ 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>