Core observable indicators.
Read the can-simple-observable API docs on CanJS.com.
See the latest releases on GitHub.
The contribution guide has information on getting help, reporting bugs, developing locally, and more.
Create an observable value.
Home Page: https://canjs.com/doc/can-simple-observable.html
License: MIT License
Core observable indicators.
Read the can-simple-observable API docs on CanJS.com.
See the latest releases on GitHub.
The contribution guide has information on getting help, reporting bugs, developing locally, and more.
An AsyncObservable cannot return a value from its getter if resolve
has already been called.
That means the observable below cannot be used to toggle from 0
to 1
and then back to 0
:
var asyncObs = new AsyncObservable(function(lastSet, resolve){
if (value.get() === 1) {
resolve(1);
}
return 0;
});
In order for the can-define
value behavior to handle more use cases that streams can handle, maybe resolver
should be able to resolve the same value multiple times.
I would like to be able to do something like this in order to keep the value of oddNumber
as always an odd number:
oddNumber: {
value({ resolve, listenTo, lastSet }) {
let lastOddNumber = 5;
resolve(lastOddNumber);
listenTo(lastSet, val => {
if (val % 2 === 1) {
lastOddNumber = +val;
}
resolve(lastOddNumber);
});
}
}
This doesn't work because, the resolver
will only dispatch an event if the underlying value
changes:
can-simple-observable/resolver/resolver.js
Line 109 in 42a2b69
Copy can-stache/src/key-observable.js into this package as the key/
module.
key-observable
doesn’t have any tests in can-stache
; what should be tested?
For Resolver, we should barf if resolve is called after teardown. Something went wrong.
I'd like to retain "active" behavior on getters and async getters that only read values directly on their observable. For example:
const SaltShaker = DefineMap.extend({
saltCount: {
value({listenTo, resolve}){
var saltCount = resolve(0);
listenTo("fill", ()=>{
resolve(saltCount = 2);
});
listenTo("shake", ()=>{
resolve(--saltCount);
});
}
},
fill: function(){
this.dispatch("fill");
},
shake: function(){
let hadSalt = this.saltCount;
this.dispatch("shake");
return hadSalt ? "salt" : null;
},
get empty() {
return ! this.saltCount;
}
});
As saltCount
is only listening on an instance of saltShaker
, we can leave it bound once someone reads this.saltCount
.
The following should work:
const saltShaker = new SaltShaker();
// when read, we notice that the observation is only listening on `saltShaker`:
saltShaker.saltCount;
// Now that saltCount is active, everything works:
saltShaker.fill();
console.log( saltShaker.shake() ) //-> "salt"
console.log( saltShaker.shake() ) //-> "salt"
console.log( saltShaker.shake() ) //-> null
console.log( saltShaker.empty ) //-> true
I think this would be REALLY nice for getters and async getters:
var VM = DefineMap.extend({
todoId: "number",
get todoPromise(){
return Todo.get({id: this.todoId})
},
todo: {
get(lastSet, resolve){
todoPromise.then(resolve);
}
}
});
var vm = new VM({todoId: 5});
vm.todo //-> undefined
setTimeout(function(){
vm.todo //-> {todo}
},10000)
Obviously, there would still be corner cases like in saltShaker
above. But overall, I think these sorts of behaviors would act more like people suspect.
Thoughts?
In migrating one of our applications to Can 4, I've encountered what appears to be a pretty low-level problem in SetterObservable: specifically, when you call its setter, it never actually updates its value
property. I assume this is because it's expected that the observation
handler will be used to retrieve the value, but when can-bind calls the setter in updateValue (args.observable
will be a SetterObservable
in the case where value that's changing is bound to a converter), it then immediately calls the getter on the same observable.
This would be fine, except that because bound
is true, the getter (implemented in get-set.js) skips using the observation
function and returns this.value
directly, which returns whatever the parent value was at the time the binding was set up.
This has a few negative side effects when using two-way binding through a converter:
updateValue
function referenced above will cycle multiple times trying to get the parent and child values to agree (even though they already do; it's simply looking at an old snapshot of the parent value to do the comparison), which involves overwriting the child value with the original value of the parent, which will basically always be wrongI've created a jsbin that reproduces my binding scenario and demonstrates the warning: https://jsbin.com/kevolovonu/4/edit?html,js,console,output
I was unable to get it to reproduce the multiple sets, but I think the warning is probably sufficient to demonstrate that there's a problem here. The solution I found was to add this.value =
to the beginning of SetterObservable.prototype.set.
☝️ Important announcement: Greenkeeper will be saying goodbye 👋 and passing the torch to Snyk on June 3rd, 2020! Find out how to migrate to Snyk and more at greenkeeper.io
1.1.7
to 1.1.8
.This version is covered by your current version range and after updating it in your project the build failed.
can-event-queue is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.
The new version differs by 4 commits ahead by 4, behind by 1.
86c7082
1.1.8
ad72c04
Update version number
c804191
Merge pull request #34 from canjs/fix-instance-type
d67d7f0
Fix instance typo
See the full diff
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
I think SimpleObservable should delegate canReflect.hasKey
to its data
:
var Data = DefineMap.extend({
foo: "string"
});
var data = new Data();
var obs = new SimpleObservable(data);
canReflect.hasKey(data, "foo"); // -> true
canReflect.hasKey(obs, "foo"); // -> false, should be true
Without this, warnings are shown in {{#each}}
loops even for properties that are defined.
const Person = DefineMap.extend({
title: "string",
first: "string",
last: "string"
});
const People = DefineList.extend({
"#": Person
});
Component.extend({
tag: "my-app",
view: `
{{# each(people) }}
{{first}} {{last}}
{{/ each }}
`,
ViewModel: {
people: {
Type: People,
default() {
return [
{ first: "Emmet", last: "Brickowoski" },
{ first: "Wyldstyle" },
{ last:"Business" }
];
}
}
}
});
MyAppView:2: Unable to find key "last".
MyAppView:2: Unable to find key "first".
🚨 You need to enable Continuous Integration on all branches of this repository. 🚨
To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because we are using your CI build statuses to figure out when to notify you about breaking changes.
Since we did not receive a CI status on the greenkeeper/initial
branch, we assume that you still need to configure it.
If you have already set up a CI for this repository, you might need to check your configuration. Make sure it will run on all new branches. If you don’t want it to run on every branch, you can whitelist branches starting with greenkeeper/
.
We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.
Once you have installed CI on this repository, you’ll need to re-trigger Greenkeeper’s initial Pull Request. To do this, please delete the greenkeeper/initial
branch in this repository, and then remove and re-add this repository to the Greenkeeper integration’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.
Going through one of our examples, I was confused by the behavior of a ResolverObservable
that calls resolve
synchronously like this:
prop: String,
count: {
value({ listenTo, resolve }) {
let count = resolve(0); // synchronously calling resolve
listenTo("prop", () => resolve(++count));
}
}
For properties like this, if they are bound and then unbound, they no longer retain their value:
const obs = new Obs();
obs.listenTo("count", ({ value }) => {
console.log(`count changed to ${value}`); // -> "count changed to 1"
});
obs.prop = "Hi";
obs.stopListening();
console.log(`count: ${obs.count}`); // -> "count: 0"
This happens because when the property is read after it is no longer bound, the value
function is called again and the _value
is set to the synchronously resolved value:
can-simple-observable/resolver/resolver.js
Lines 205 to 213 in 42e61bc
Here is a codepen showing the issue: https://codepen.io/kphillips86/pen/oNvYEMa?editors=0010.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.