Используя KnockBack ViewModel, есть ли способ создать вычисляемую наблюдаемую из методов базовой модели Backbone?

Используя KnockBack ViewModel, есть ли способ создать вычисляемую наблюдаемую из методов базовой модели Backbone?

В качестве примера в javascript:

var MyModel = Backbone.model.extend({
        validate: function () {
            return this.get('name').length < 0;
        }
    }),
    baseModel = new MyModel({name: 'foo'}),
    kbViewModel = kb.viewModel(baseModel),
    modelContainer = document.querySelector('#myModel');
ko.applyBindings(kbViewModel, modelContainer);

и в разметке нокаута:

<div id="myModel">
    <div data-bind="css:{'invalid': !validate()}">
        <input type="text" data-bind="value: name" />
    </div>
</div>

Когда я пытаюсь запустить это, я получаю сообщение об ошибке:

Unable to process binding "css: function (){return {'invalid':!validate()} }"
Message: validate is not defined

Я делаю что-то не так, или мне нужно создать наблюдаемую в ViewModel вручную?

var MyModel = Backbone.Model.extend({
        validate: function () {
            return this.get('name').length > 0;
        }
    }),
    MyKBViewModel = kb.ViewModel.extend({
        constructor: function (model) {
            kb.ViewModel.prototype.constructor.call(this, model);
            this.validate = ko.pureComputed(function () {
                return this.name().length > 0;
            }, this);
        }
    }),
    baseModel = new MyModel({name: 'foo', class: 'bar'}),
    kbViewModel = new MyKBViewModel(baseModel),
    modelContainer = document.querySelector('#myModel');

ko.applyBindings(kbViewModel, modelContainer);

jsfiddles: без наблюдаемого, с наблюдаемым

1 ответ

Решение

Небольшая преамбула: Knockback помещает модель в MVVM, где Knockout на самом деле просто VVM. Откат также дает вам некоторую автоматическую синхронизацию между ними, что приятно. Но вам все равно нужно помнить, что модель и модель представления - это две разные части вашего приложения. Модель представления - это не просто нокаут-копия модели Bootstrap. Не помещайте части модели в модель.

Поэтому вам нужно решить, является ли валидация поведением модели представления или поведением модели. Я говорю viewmodel, потому что вы хотите использовать его в представлении. Поэтому удалите его из модели и определите вычисленное.

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

var MyModel = Backbone.Model.extend({
    validate: function() {
      this.set('isValid', this.get('name').length > 0);
    },
    initialize: function() {
      this.validate();
      this.on('change:name', this.validate);
    }
  }),
  baseModel = new MyModel({
    name: 'foo',
    isValid: null
  }),
  kbViewModel = kb.viewModel(baseModel);

kbViewModel.validate = ko.observable();

modelContainer = document.querySelector('#myModel');

ko.applyBindings(kbViewModel, modelContainer);
.invalid {
  background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.2/backbone.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockback/1.0.0/knockback.min.js"></script>
<div id="myModel">
  <div data-bind="css:{'invalid': !isValid()}">
    <input type="text" data-bind="value: name" />
  </div>
</div>

Другие вопросы по тегам