forked from knockout/knockout
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobservableBehaviors.js
178 lines (145 loc) · 6.49 KB
/
observableBehaviors.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
describe('Observable', {
'Should be subscribable': function () {
var instance = new ko.observable();
value_of(ko.isSubscribable(instance)).should_be(true);
},
'Should advertise that instances are observable': function () {
var instance = new ko.observable();
value_of(ko.isObservable(instance)).should_be(true);
},
'Should be able to write values to it': function () {
var instance = new ko.observable();
instance(123);
},
'Should be able to write to multiple observable properties on a model object using chaining syntax': function() {
var model = {
prop1: new ko.observable(),
prop2: new ko.observable()
};
model.prop1('A').prop2('B');
value_of(model.prop1()).should_be('A');
value_of(model.prop2()).should_be('B');
},
'Should advertise that instances can have values written to them': function () {
var instance = new ko.observable(function () { });
value_of(ko.isWriteableObservable(instance)).should_be(true);
},
'Should be able to read back most recent value': function () {
var instance = new ko.observable();
instance(123);
instance(234);
value_of(instance()).should_be(234);
},
'Should initially have undefined value': function () {
var instance = new ko.observable();
value_of(instance()).should_be(undefined);
},
'Should be able to set initial value as constructor param': function () {
var instance = new ko.observable('Hi!');
value_of(instance()).should_be('Hi!');
},
'Should notify subscribers about each new value': function () {
var instance = new ko.observable();
var notifiedValues = [];
instance.subscribe(function (value) {
notifiedValues.push(value);
});
instance('A');
instance('B');
value_of(notifiedValues.length).should_be(2);
value_of(notifiedValues[0]).should_be('A');
value_of(notifiedValues[1]).should_be('B');
},
'Should be able to tell it that its value has mutated, at which point it notifies subscribers': function () {
var instance = new ko.observable();
var notifiedValues = [];
instance.subscribe(function (value) {
notifiedValues.push(value.childProperty);
});
var someUnderlyingObject = { childProperty : "A" };
instance(someUnderlyingObject);
value_of(notifiedValues.length).should_be(1);
value_of(notifiedValues[0]).should_be("A");
someUnderlyingObject.childProperty = "B";
instance.valueHasMutated();
value_of(notifiedValues.length).should_be(2);
value_of(notifiedValues[1]).should_be("B");
},
'Should ignore writes when the new value is primitive and strictly equals the old value': function() {
var instance = new ko.observable();
var notifiedValues = [];
instance.subscribe(notifiedValues.push, notifiedValues);
for (var i = 0; i < 3; i++) {
instance("A");
value_of(instance()).should_be("A");
value_of(notifiedValues).should_be(["A"]);
}
instance("B");
value_of(instance()).should_be("B");
value_of(notifiedValues).should_be(["A", "B"]);
},
'Should ignore writes when both the old and new values are strictly null': function() {
var instance = new ko.observable(null);
var notifiedValues = [];
instance.subscribe(notifiedValues.push, notifiedValues);
instance(null);
value_of(notifiedValues).should_be([]);
},
'Should ignore writes when both the old and new values are strictly undefined': function() {
var instance = new ko.observable(undefined);
var notifiedValues = [];
instance.subscribe(notifiedValues.push, notifiedValues);
instance(undefined);
value_of(notifiedValues).should_be([]);
},
'Should notify subscribers of a change when an object value is written, even if it is identical to the old value': function() {
// Because we can't tell whether something further down the object graph has changed, we regard
// all objects as new values. To override this, set an "equalityComparer" callback
var constantObject = {};
var instance = new ko.observable(constantObject);
var notifiedValues = [];
instance.subscribe(notifiedValues.push, notifiedValues);
instance(constantObject);
value_of(notifiedValues).should_be([constantObject]);
},
'Should notify subscribers of a change even when an identical primitive is written if you\'ve set the equality comparer to null': function() {
var instance = new ko.observable("A");
var notifiedValues = [];
instance.subscribe(notifiedValues.push, notifiedValues);
// No notification by default
instance("A");
value_of(notifiedValues).should_be([]);
// But there is a notification if we null out the equality comparer
instance.equalityComparer = null;
instance("A");
value_of(notifiedValues).should_be(["A"]);
},
'Should ignore writes when the equalityComparer callback states that the values are equal': function() {
var instance = new ko.observable();
instance.equalityComparer = function(a, b) {
return !(a && b) ? a === b : a.id == b.id
};
var notifiedValues = [];
instance.subscribe(notifiedValues.push, notifiedValues);
instance({ id: 1 });
value_of(notifiedValues.length).should_be(1);
// Same key - no change
instance({ id: 1, ignoredProp: 'abc' });
value_of(notifiedValues.length).should_be(1);
// Different key - change
instance({ id: 2, ignoredProp: 'abc' });
value_of(notifiedValues.length).should_be(2);
// Null vs not-null - change
instance(null);
value_of(notifiedValues.length).should_be(3);
// Null vs null - no change
instance(null);
value_of(notifiedValues.length).should_be(3);
// Null vs undefined - change
instance(undefined);
value_of(notifiedValues.length).should_be(4);
// undefined vs object - change
instance({ id: 1 });
value_of(notifiedValues.length).should_be(5);
}
});