Возможно ли связывание данных, видимое отрицанию («!») Логического свойства ViewModel?

162

Я хотел бы использовать свойство в моей ViewModel, чтобы переключать отображаемый значок, не создавая отдельное вычисляемое свойство инверсии. Это возможно?

<tbody data-bind="foreach: periods">
  <tr>
    <td>
      <i class="icon-search" data-bind="visible: !charted, click: $parent.pie_it"></i>
      <i class="icon-remove" data-bind="visible: charted, click: $parent.pie_it"></i>
    </td>
  </tr>
</tbody>

Моя ViewModel имеет свойство period, которое представляет собой массив месяцев, например:

var month = function() {
    this.charted = ko.observable(false);
};
agradl
источник
3
@Niko: Это не совсем повторяющийся вопрос. ОП вопроса, на который вы ссылаетесь, уже знал, что можно связать данные отрицанием наблюдаемой, но удивляется, почему его нужно вызывать как функцию. Оператор этого вопроса здесь не знал, как это сделать, и, очевидно, не нашел этот другой вопрос. Я рад, что нашел этот вопрос здесь - в основном благодаря его описательному названию.
Оливер

Ответы:

281

При использовании наблюдаемого в выражении вам нужно обращаться к нему как к функции, например:

visible: !charted()

Р.П. Нимейер
источник
33
Возможно, нам следует сделать скрытую привязку :) У нас есть включение и отключение.
Джон Папа
Не согласна ли с этим документация или я совершенно не понимаю эту страницу: knockoutjs.com/documentation/css-binding.html
Адвокат дьявола,
Не берите в голову, я думаю, «isSevere» не наблюдаемое, а просто старое свойство, таким образом, мое замешательство.
Адвокат дьявола
3
При использовании! Charted вы получаете! [Function]. [Функция] верна,! [Функция] становится ложной и всегда будет ложной, если вы используете этот синтаксис. jsfiddle.net/datashaman/E58u2/3
datashaman
1
Они фактически добавили hiddenпривязку в v3.5.0
Grin
53

Я согласен с комментарием Джона Папы о том, что должна быть встроенная hiddenпривязка. Существует два преимущества выделенной hiddenпривязки:

  1. Более простой синтаксис, т.е. hidden: chartedвместо visible: !charted().
  2. Меньше ресурсов, поскольку нокаут может наблюдать наблюдаемое chartedнапрямую, а не создавать computedдля наблюдения !charted().

Однако создать hiddenпривязку достаточно просто , например так:

ko.bindingHandlers.hidden = {
  update: function(element, valueAccessor) {
    ko.bindingHandlers.visible.update(element, function() {
      return !ko.utils.unwrapObservable(valueAccessor());
    });
  }
};

Вы можете использовать его так же, как встроенную visibleпривязку:

<i class="icon-search" data-bind="hidden: charted, click: $parent.pie_it"></i>
<i class="icon-remove" data-bind="visible: charted, click: $parent.pie_it"></i>
Дейв
источник
9
это не сработало для меня без возвратаreturn !ko.utils.unwrapObservable(valueAccessor());
Мехмет Аташ
Спасибо @ MehmetAtaş - я исправил hiddenпривязку в соответствии с вашим комментарием. (Кстати, я использовал CoffeeScript в своем проекте в то время, когда я публиковал это изначально. Синтаксис CoffeeScript не делает очевидным, когда возврат является преднамеренным.)
Дейв
9

Это немного сбивает с толку, как вы должны сделать

visible:!showMe()

так я и сделал

<span data-bind="visible:showMe">Show</span>
<span data-bind="visible:!showMe()">Hide</span>
<label><input type="checkbox" data-bind="checked:showMe"/>toggle</label>​

моя модель

var myModel={
    showMe:ko.observable(true)
}
ko.applyBindings(myModel);    

Проверьте в скрипке http://jsfiddle.net/khanSharp/bgdbm/

Джанкар Махбуб
источник
4

Вы можете использовать мою привязку switch / case , которая включает case.visibleи casenot.visible.

<tbody data-bind="foreach: periods">
    <tr>
        <td data-bind="switch: true">
        <i class="icon-search" data-bind="case.visible: $else, click: $parent.pie_it"></i>
        <i class="icon-remove" data-bind="case.visible: charted, click: $parent.pie_it"></i>
        </td>
    </tr>
</tbody>

Вы также можете иметь это как

        <i class="icon-search" data-bind="casenot.visible: charted, click: $parent.pie_it"></i>
        <i class="icon-remove" data-bind="case.visible: $else, click: $parent.pie_it"></i>
Майкл Бест
источник
Я только что понял, что это старый вопрос, но надеюсь, что это кому-нибудь пригодится.
Майкл Бест,
1

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

ko.bindingHandlers.hidden = {
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var isCurrentlyHidden = !(element.style.display == "");
        if (value && !isCurrentlyHidden)
            element.style.display = "none";
        else if ((!value) && isCurrentlyHidden)
            element.style.display = "";
    }
};
Йогев Смила
источник
0

Отказ от ответственности: это решение только для развлекательных целей.

ko.extenders.not = function (target) {
    target.not = ko.computed(function () {
        return !target();
    });
};

self.foo = ko.observable(true).extend({ not: null });

<div data-bind="text: foo"></div>     <!-- true -->
<div data-bind="text: foo.not"></div> <!-- false -->

<!-- unfortunately I can't think of a way to be able to use:
    text: foo...not
-->
THX-1138
источник
0

У меня возникла та же проблема о том, как использовать противоположность логической наблюдаемой. Я нашел простое решение:

var ViewModel = function () {
var self = this;

// When program start, this is set to FALSE
self.isSearchContentValid = ko.observable(false);


self.gatherPlacesData = function () {

   // When user click a button, the value become TRUE
   self.isSearchContentValid(true);

};

Теперь на вашем HTML вы должны сделать это

<p data-bind = "visible:isSearchContentValid() === false"> Text 1</p>
<p data-bind = "visible:isSearchContentValid"> Text 2</p>

При запуске программы отображается только «Text1», поскольку «false === false is TRUE», а Text2 не отображается.

Допустим, у нас есть кнопка, которая вызывает collectPlacesData при событии click. Теперь Text1 не будет виден, потому что «true === false is FALSE», а текст 2 будет виден только.

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

ccastanedag
источник
-1

Также можно использовать скрытый, как это:

 <div data-bind="hidden: isString">
                            <input type="text" class="form-control" data-bind="value: settingValue" />
                        </div>
Dev-Systematix
источник