Giter Site home page Giter Site logo

can-simple-observable's Introduction

can-simple-observable's People

Contributors

bmomberger-bitovi avatar chasenlehara avatar cherifgsoul avatar christopherjbaker avatar greenkeeper[bot] avatar imaustink avatar justinbmeyer avatar m-mujica avatar mjstahl avatar phillipskevin avatar thomaswilburn avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

frank-dspeed

can-simple-observable's Issues

AsyncObservable cannot return a value after previously resolving

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;
	});

Should resolver always dispatch an event?

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:

if(this.value !== this.lastValue) {

PROPOSAL: Allow retention of bindings on a read if only values directly on the observable are read

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?

Set value on SetterObservable when it's set

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:

  1. A confusing semaphore warning is written out to the console because the 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 wrong
  2. The issue that led to me debugging this problem was that my child value was being set first to the expected value, then to whatever the parent value was when the UI was created, then back to the correct value, which was causing unexpected behavior in my application.

I'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.

An in-range update of can-event-queue is breaking the build 🚨


☝️ 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


The dependency can-event-queue was updated from 1.1.7 to 1.1.8.

🚨 View failing branch.

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.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build failed (Details).

Commits

The new version differs by 4 commits ahead by 4, behind by 1.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Should implement can.hasKey

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".

Action required: Greenkeeper could not be activated 🚨

🚨 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.

Should unbound ResolverObservables return their _value if it exists

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:

if (this.bound === true) {
return this._value;
} else {
var handler = function(){};
this.on(handler);
var val = this._value;
this.off(handler);
return val;
}

Here is a codepen showing the issue: https://codepen.io/kphillips86/pen/oNvYEMa?editors=0010.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.