MVVM w JavaScript, knockout.js, część II

W poprzedniej części przedstawiłem bibliotekę knockout.js, ułatwiającą implementację wzorca MVVM w JavaScript. Jest to ciekawa biblioteka, szczególnie dla programistów WPF. W tamtym wpisie, pokazaliśmy jak wiązać dane w dwóch kierunkach: od VM do widoku i odwrotnie. Skończyliśmy na następującym przykładzie:

var personViewModel = {
firstName: ko.observable('poczatkowa wartosc'),
lastName: ko.observable('poczatkowa wartosc') };

ko.applyBindings(personViewModel);

Gdzie widok to:

<p data-bind="text: firstName"></p>
<p data-bind="text: lastName"></p>

<input type="text" data-bind='value: firstName' />
<input type="text" data-bind='value: lastName' />

W WPF bardzo często tworzymy właściwości tylko do odczytu, które zwracają jakieś dane na podstawie innych właściwości. W C# wystarczy stworzyć właściwość wyłącznie z getterem, który używa z kolei jakiś innych właściwości. Oczywiście analogiczny scenariusz możemy zaimplementować w JS. Zaktualizujmy najpierw widok:

<p data-bind="text: firstName"></p>
<p data-bind="text: lastName"></p>
<p data-bind="text: fullName"></p>

<input type="text" data-bind='value: firstName' />
<input type="text" data-bind='value: lastName' />

FullName zatem jest właściwością, która zwraca połączone string’i firstName i LastName:

function PersonViewModel() {
   this.firstName = ko.observable('poczatkowa wartosc');
   this.lastName = ko.observable('poczatkowa wartosc');
   this.fullName = ko.computed(function() { return this.firstName() + ' ' + this.lastName(); }, this);
};

Tak jak to z knockout.js, korzystamy z obiektu ko. W C# wystarczy stworzyć właściwość, niestety w JS nie ma takiej możliwości i należy wywoływać specjalne metody na ko. Proszę zwrócić uwagę, że observable zwraca funkcję, zatem nie jest to zwykłe pole.

Kolejną przydatną rzeczą są komendy (analogiczne do ICommand w WPF). Zacznijmy od widoku:

<button data-bind="click: save">Zapisz</button>

Widzimy tutaj nowy typ wiązania, click. Wcześniej korzystaliśmy z text oraz value.

Następnie musimy zdefiniować handler:

function PersonViewModel() {
   this.firstName = ko.observable('poczatkowa wartosc');
   this.lastName = ko.observable('poczatkowa wartosc');
   this.fullName = ko.computed(function () { return this.firstName() + ' ' + this.lastName(); }, this);
   this.save = function() {
       alert('Save: ' + this.fullName());
   };
};

Możliwe jest również stworzenie czegoś analogicznego do ObservableCollection:

function PersonViewModel() {
   this.firstName = ko.observable('poczatkowa wartosc');
   this.lastName = ko.observable('poczatkowa wartosc');
};

function MainViewModel() {
   this.persons = ko.observableArray();
}

vm = new MainViewModel();

person1 = new PersonViewModel();
person1.firstName('imie1');
person1.lastName('nazwisko');

person2 = new PersonViewModel();
person2.firstName('imie2');
person2.lastName('nazwisko2');

vm.persons.push(person1);
vm.persons.push(person2);

Widok:

<ul data-bind="foreach: persons">
    <li>
        <p data-bind="text: firstName"></p>
        <p data-bind="text: lastName"></p>
    </li>
</ul>

Kolejny typ wiązania to foreach. Służy on oczywiście do powtarzania pewnej części kodu HTML. W WPF jest to nic innego jak ItemsSource oraz ObservableCollection.

Do dyspozycji mamy również zmienną $root, dzięki której możemy wywołać np. komendę z głównego VM:

<ul data-bind="foreach: persons">
    <li>
        <p data-bind="text: firstName"></p>
        <p data-bind="text: lastName"></p>
        <button data-bind="click: $root.save">Zapisz</button>
    </li>
</ul>

Gdzie VM, to:

function MainViewModel() {
   this.persons = ko.observableArray();
   this.save = function() {
       alert('Zapisz');
   };
}

Oczywiście to dopiero początek możliwości knockout. Jeśli kogoś temat zaciekawił to odsyłam do dokumentacji. Na blogu, będę zamieszczał tylko takie krótkie wprowadzania do różnych bibliotek, po to aby zachęcić czytelników, albo po prostu pokazać, że taka możliwość istnieje i została już zaimplementowana. Nie ma sensu bowiem duplikować tego, co jest już w dokumentacji.

Leave a Reply

Your email address will not be published.