New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Settable can.computes #824
Comments
This relates to #819. I'd like a getter API that used this: {
define: {
todos: {
get: function(oldValue, setValue){
Todo.findAll({makeId: map.attr("makeId")}, function(todos){
setValue(todos);
})
}
}
}
} |
I like it, can we figure out a way to do this and #816 as one signature though? |
What if it were one of the existing signatures, but we added a function to the compute that could be used in this way. For example: var todos = can.compute(new Todo.List()).later(function(oldVal, setVal) {
}); That way any existing signature could be used async. ( |
@matthewp Ha! I forgot I created the other issue. Closing that one. |
@matthewp I like the idea. It feels deferred ish. A small issue with that is it would involve creating 2 computes ... the initial one and the one that gets called when there are changes. One would be setup to change the other. This 2x the number of change events being fired. I'm not sure about performance. |
I think a signature like: var todos = can.compute(new Todo.List(), function(newVal, oldVal, setVal){
Todo.findAll({makeId: map.attr("makeId")}, function(todos){
setVal(todos);
})
}) will work now. |
That will not work. I was thinking something like: var obj = can.compute({}, {
value: {},
fn: function( curVal, setVal ){
if(a()) {
curVal.a = a();
} else {
delete curVal.a;
}
if(b()) {
curVal.b = b();
} else {
delete curVal.b;
}
}
}); But the problem with all of this ... what is the value of an unbound compute? It will not be correct. |
So, I think this should not be through the compute constructor because it is returning a compute that you can read but might not have the current best value. Only a "bound" async compute will have the current value. can.compute.async@function can.compute.async Create a compute that can set its value after the computed function has been called. @Signature @param {*} The initial value of the compute. @return {can.computed} Returns a compute, but a compute that will possibly not have the correct value unless it is bound to. UseThe following compute is a live list of todos for a given userId. var userId = can.compute(5)
var todos = can.compute.async(null, function(oldTodoList, setValue){
Todo.findAll({ userId: userId() }, function(todos){
setValue(todos)
});
return null;
}) The following replaces the list in place: var userId = can.compute(5)
var todos = can.compute.async(new Todo.List(), function(todoList, setValue){
todoList.replace( Todo.findAll({ userId: userId() })
return todoList;
}) can.compute.asyncComputer@typedef {function(*,function)} can.compute.asyncComputer(currentVal, setVal) A function that determines a value for an [can.compute.async async compute]. @option {function(*,function)} can.compute.asyncComputer(currentVal, setVal) @param {*} currentVal The current value of the compute. This should be returned @param {function(*)} setVal(newVal) Called to update the value of the compute at a later time. @return The immediate value of the compute. Thoughts? |
I am not going to document this for 2.1. can.Map define will use it, but I'm not sure it's super useful outside maps. I've added the documentation but hidden it. We can unhide it for 2.2 if people crave it. |
It's useful beyond |
How would you use async for a spinner image on its own? |
Write a component that has a Inside said compute, create an Listen to the compute for changes. When a change occurs, wipe the existing children of the component's containing element and either append the newly resolved element or, if the resolved element is The value for the Sure, you can hack this today as well; but it involves a substantial amount of book-keeping you have to perform manually. Having |
I would not do it that way. I would probably do it like: can.Component({
tag: "img-spinner",
template: "<img {{^ready}}style='display:none'{{/ready}} src='{{src}}' can-load='loaded'/>"+
"{{^ready}}<img src='{{spinnerSrc}}'/>{{/ready}}"
scope: {
loaded: function(){
this.attr("ready", true);
}
}
}) stache:
|
Depending on the order in which the templating system creates the Also; you're somewhat conveniently discarding the error handling case, which requires also incorporating a timeout somewhere for IE, as it does not reliably fire events for timed out image requests... Loading images async reliably is not something you can solve trivially from simple template markup like that. ;) |
As all of that happens in the same "turn", it should not miss load. Sent from my iPhone
|
It could in IE, which resolves images from cache and executes any bound load event handlers synchronously; without deferring to the next tick. But anyway; this is already veering off-topic, the example was only meant to illustrate that there are still use cases where having can.compute.async directly exposed for use may be a useful thing. |
Can you write out how you would use |
I would like a
can.compute
API that could set itself.For example, the following would update its value with a new todo list everytime makeId changes.
The following would update the list every time makeId changes.
Essentially, we are using the "rerun when a source value changes" ability of compute, but not for an immediate value. Instead when a source value changes, we run the function with a
setVal
function that will be called back with the final value.The signature as proposed will not work as it conflicts with another signature of can.compute. Please share any proposals that might work.
The text was updated successfully, but these errors were encountered: