These are chat archives for canjs/canjs

30th
Mar 2016
Thomas Sieverding
@Bajix
Mar 30 2016 06:31

@RALifeCoach @pYr0x

5) Use computes like a mad man. The goal is to lower unnecessary change events. For example, the isAdmin getter I described above is actually really performant, as now I can bind to it elsewhere, and something like changing users or logging in that would trigger isAdmin to be re-computed wouldn’t trigger other computes that are dependent on isAdmin from re-computing if isAdmin doesn’t change

 isAdmin: {
  get: function() {
    var profile = this.attr('profile');

    if (profile) {
      return profile.attr('tier') === config.tiers.indexOf('admin');
    }

    return false
  }
}

Changing profile / tier would recompute this. But if the value hasn't changed, computes dependent on this wouldn't recompute

ok.. and what about the point 5) bajix said?

Computes cache if they're bound, and then re-compute whenever an observable they've bound to changes. Only if the re-computed value is different will it then emit a change event. So the general technique is to utilize computes for intermediate values, such that more expensive, poorly-cacheable computes would be re-computed less frequently. This is especially true for Component helpers, as new Document Fragments that would otherwise be identical still need to be re-rendered.

There's no need to shy away from components within loops either if that means that you're better able to accomplish the above. Using an extra component wins out if it reduces unnecessary DOM manipulation.

For example, the Chat app I work on uses a message component when iterating user messages. Consecutive messages from the same author are grouped, and messages can come out of order; using a component to manage state based off of the prev/next message means my section helpers trigger O(n^3) times less often.

TLDR; Make cache-able computes. Use cache-able intermediates. Win at helpers. Win at computed objects.

Guido Smeets
@gsmeets
Mar 30 2016 09:40
Hmm, there was an issue on github that discussed all the details for the 2.3 binding syntax, I can't find it anymore. Anyone happen to know which issue I'm referring to?
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 09:42
@gsmeets did you do a filter for closed issues?
Guido Smeets
@gsmeets
Mar 30 2016 11:13
@cherifGsoul yeah I did, just can't recall what it was named
I, got it #1700
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 11:16
ok I tought it was opened by you ;)
Dovid Bleier
@dbleier
Mar 30 2016 12:41
when a compute changes value, do only other define getters that use that compute rerun, or do map methods using the compute also rerun?
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 13:02
@dbleier in stache I think both
Dovid Bleier
@dbleier
Mar 30 2016 13:04
@cherifGsoul not in stache, on VM methods that are not stache related, for internal non-visual processing
related to that, when can-connect fall-through-cache updates the List after retrieving updates from the server, I want it to call methods in my VM
I am currently sifting thru can-connect code to understand how it updates the list
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 13:06
you should bind an event handler on that compute
Dovid Bleier
@dbleier
Mar 30 2016 13:07
how do I do that inside of a map? all the examples I saw use bind as an external line of code
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 13:08
@dbleier do you use can.map.define plugin?
Dovid Bleier
@dbleier
Mar 30 2016 13:08
do you mean in viewModel: { events: { {someprop change}: function()
yes
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 13:09
so you can have set setter on that prop that invoke your method
Dovid Bleier
@dbleier
Mar 30 2016 13:10
ah right, let me think about how that would work in my design
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 13:11
ok
Dovid Bleier
@dbleier
Mar 30 2016 13:11
@cherifGsoul do you know if when fall-through-cache updates, it calls the setter of the prop that called getList?
for example
signPromise: {
   get(lastval, set) {
      return Sign.getList({...});
  },
  set(newval) {
  }
},
sign: {
   get(lastval, set) {
    this.attr('signPromise').then(function(signs) { set(signs[0]);}
  },
  set(newval) {
  }
}
Christopher Oliphant
@RALifeCoach
Mar 30 2016 13:15

further to this discussion, I have a component with it’s internal viewModel i.e.

can.Component.extend({
tag: ‘my-component’,
template: can.view(‘#some-template’),
viewModel: {
    define: {
        xxx: { type: ‘string’ }
    }
}
});

I add the component to my page via:

var template = can.stache(‘<my-component id="me"></my-component>’)
$(‘body”).append(template());
var myComponent = $(‘#me’);
myComponent.bind(??????);

I want to bind to the component to know when the value of xxx changes.

Dovid Bleier
@dbleier
Mar 30 2016 13:15
what would I bind to to emit a change event when the List is updated?
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 13:16
@dbleier I think you should listen to sign changes
Dovid Bleier
@dbleier
Mar 30 2016 13:17
sign the VM prop or the connect prop?
I don't think the sign getter is called again after the list is updated
at least I don't see that happening
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 13:18
the setter should be called
@RALifeCoach we can not make it like that
@dbleier sorry I didnt have a closer look at fall-through-cachebehavior so I dont know how it realy does things :/
Dovid Bleier
@dbleier
Mar 30 2016 13:20
@cherifGsoul I just but a debugger; line in set for both signPromise and sign and neither got hit
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 13:21
@dbleier can you make a jsbin?
Dovid Bleier
@dbleier
Mar 30 2016 13:21
ok
Christopher Oliphant
@RALifeCoach
Mar 30 2016 13:21
@cherifGsoul okay, that’s what I thought. What I have done is trigger an event from within the component and listen for the event in the owning module. That works.
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 13:22
@RALifeCoach
   can.Component.extend({
tag: ‘my-component’,
template: can.view(‘#some-template’),
viewModel: {
    define: {
        xxx: { type: ‘string’ }
    }
},
events: {
"{viewModel} xxx":function(){
}
}
});
Justin Meyer
@justinbmeyer
Mar 30 2016 14:13
@RALifeCoach was unable to read all of what you wrote ... but I want to address one thing you said .... CanJS, and most frameworks, make your life easier, but that always comes at some performance cost
C makes your life easier than assembly, but at some cost
JavaScript makes your life easier than C, but at some cost
CanJS makes your life easier than plain JS, but at some cost
Why does CanJS's observables covert the entire object into an observable? Because when MOST properties are used (which is the case for MOST apps), its faster to do all of them right away instead of progressively convert them like LazyMap
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:15
@justinbmeyer I am willing to accept some performance hit when initially creating the page. I was surprised when updating the page took even longer. My expectation was that Can JS would be quick and efficient especially when no DOM updates were required.
Justin Meyer
@justinbmeyer
Mar 30 2016 14:16
CanJS's observables are "quick" but not quick compared to plain JS objects
they have been worked on a lot to make performance as fast as possible
btw, if you have objects that you don't need observable, you can define their type like "type": "*"
with the define plugin
those objects will not be converted to Maps / Lists
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:17
When I strip down the big object to be an object that contains only needed properties, there is slight improvement on initial load and a huge improvement on update.
I did make use of type: ‘*’ - that gave some improvement
Justin Meyer
@justinbmeyer
Mar 30 2016 14:19
the improvement on update doesn't make sense
I wonder if this is what @Bajix was talking about
are you listening to "change" events?
the number of props shouldn't matter to update
ah ... if you are listening to "change" events ... then @Bajix is also right that additional slowness will be introduced
in the initial render
b/c bubbling will need to be setup
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:20
I don’t have a need to fire events on data changing. The only events would be internal to the UI. (Updating the DOM when a value changed.)
Justin Meyer
@justinbmeyer
Mar 30 2016 14:20
not sure what that means ... does that mean no, you are not binding on "change" events?
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:21
no I am not binding change events
Dovid Bleier
@dbleier
Mar 30 2016 14:21
@cherifGsoul here is the jsbin http://jsbin.com/hemuliyugu/1/edit?js,console
the 1st time you run will set up the cache
then try making a change to the data in the fixture
you'll notice it console.logs the cached data only
if you run a 3rd time you'll see the updates
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 14:22
ok Im checking
Justin Meyer
@justinbmeyer
Mar 30 2016 14:22
@RALifeCoach if you'd like to check if bubbling is getting setup, you can put a debugger here: https://github.com/canjs/canjs/blob/master/map/bubble.js#L42
if that gets hit, something is setting up bubbling
Dovid Bleier
@dbleier
Mar 30 2016 14:22
the goal is to get logHellos to fire again after cache is updated
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:23
@justinbmeyer in many ways my code is quite simple. All data is display only. There is some binding against controls, but not against the data itself.
Dovid Bleier
@dbleier
Mar 30 2016 14:23
I have to run to a wedding, so I probably won't check back until tomorrow. thanks for the help
Justin Meyer
@justinbmeyer
Mar 30 2016 14:23
@RALifeCoach if that's the case, I wouldn't convert it to a Map at all
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:23
Once everything is loaded, the page is quite quick.
the problem is that on initial display the controls are loaded and then updated on all 156 rows
Dovid Bleier
@dbleier
Mar 30 2016 14:25
@justinbmeyer what would you use if not a Map? I thought maps were the heart of canjs. My app is also read only and changes are only based on what is received from the server
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:25
Are you suggesting that I pass all data as attributes to the component? There are a lot of attributes!
@justinbmeyer are you still here?
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:34
This is the annoying part - someone makes a statement, I ask for clarification and … silence. This doesn’t happen all the time, but enough that it is annoying.
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 14:36
@RALifeCoach we try to help you everyday
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:37
And you guys have been great - I do not say that often enough. I praise you guys to the folks at work. The level of response to questions from original developers is truly amazing.
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 14:37
We are at our work offices and we took time to help you
Thank you :)
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:38
It’s just the statement, question, silence that’s trying. If you are busy, fine, just let me know.
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 14:39
yes silence means busy
:)
Kevin Phillips
@phillipskevin
Mar 30 2016 14:39
He might just mean to pass the raw data to your template
instead of creating a can.Map instance and passing that
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:40
Justin made a statement - I don’t need to use a Map. That’s a significant statement, one that the other user questioned as well. We both asked for more details and I now may wait an hour to a few days to get a response.
Justin Meyer
@justinbmeyer
Mar 30 2016 14:50
@RALifeCoach jeez man ... I was literally helping you up to the second I had to leave for a client training
I was late for my car even
sorry for not letting you know
anyway, I'm going to have to start the training now. I will hopefully be available after 7 PM CST, but I might go to dinner
and then talk to my wife / baby
and hopefully after that be available
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:53
@justinbmeyer I do appreciate your help. Now that I know, I will make plans to work on other tasks. When you are free, please fill in the details to your “don’t need a Map” statement. I will check tonight or tomorrow for details. Enjoy your time eating, and spending time with your wife and baby.
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 30 2016 14:55
@RALifeCoach I think @phillipskevin gave details about that
he means use plain javascript objects
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:57
@phillipskevin wrote, "@phillipskevin
He might just mean to pass the raw data to your template
instead of creating a can.Map instance and passing that” notice the word ‘might’ and I asked how would I pass the data, would I use attributes when creating the fragment to add to my document?
Kevin Phillips
@phillipskevin
Mar 30 2016 14:57
I didn’t see you ask anything
just like this:
var template = can.stache('<player-row id="player-row-{{pid}}" {pid}="pid" {parent}="parent"></player-row>');
            var fragment = template({
                pid: this.pid,
                parent: this
            });
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:58
at 10:25 I wrote, "Are you suggesting that I pass all data as attributes to the component? There are a lot of attributes!”
Kevin Phillips
@phillipskevin
Mar 30 2016 14:59
sorry, I wasn’t trying to be confrontational. I just meant, I didn’t think you wanted more info on my suggestion.
so, in the code above, it is just a plain object being passed to the renderer
Christopher Oliphant
@RALifeCoach
Mar 30 2016 14:59
Those two attributes get converted inside the Map to 50+ attributes. I could reorganize and pass the 50+ attributes in a few objects. Is that what you are suggesting?
Kevin Phillips
@phillipskevin
Mar 30 2016 15:00
I’m not suggesting any detailed solution for your code. I don’t know your codebase that well.
If what you want to do is take data you receive from a server and pass it to a template, you can just do it without creating can.Maps
by passing the raw data to your stache renderer function
I don’t know for sure if that is what Justin is proposing
Christopher Oliphant
@RALifeCoach
Mar 30 2016 15:03
I will try on JSBin and see how it all hangs together
Kevin Phillips
@phillipskevin
Mar 30 2016 15:04
ok
Christopher Oliphant
@RALifeCoach
Mar 30 2016 15:18
@phillipskevin here is my JSBin http://jsbin.com/qahepi/edit?html,js,console,output
If I click on ‘here’ before the timer fires, then it works and the timer event throws an exception. If I wait for the timer to fire, the names disappear and clicking on the anchor throws and exception.
It is a short JSBin
Christopher Oliphant
@RALifeCoach
Mar 30 2016 15:27
Things work fine when I update the simple PID property.
Kevin Phillips
@phillipskevin
Mar 30 2016 15:45
Ok I'll take a look. Might be 45 mins or an hour.
Christopher Oliphant
@RALifeCoach
Mar 30 2016 15:47
thanks
Kevin Phillips
@phillipskevin
Mar 30 2016 16:57
@RALifeCoach is there something specific you want me to look at in the jsbin?
are you just wondering why the last line doesn’t work?
Christopher Oliphant
@RALifeCoach
Mar 30 2016 16:59
I am just wondering why the last line doesn’t work. It seems I cannot replace an attribute which is an object.
Kevin Phillips
@phillipskevin
Mar 30 2016 17:05
it just looks like that attribute is not set
Christopher Oliphant
@RALifeCoach
Mar 30 2016 17:06
it is set earlier - it becomes unset when I try to update the player object
Kevin Phillips
@phillipskevin
Mar 30 2016 17:09
is this related to the question about not using Maps?
Christopher Oliphant
@RALifeCoach
Mar 30 2016 17:09
yes
Kevin Phillips
@phillipskevin
Mar 30 2016 17:41
does jquery.attr allow you to pass objects?
Christopher Oliphant
@RALifeCoach
Mar 30 2016 17:41
I’m not sure. I can try in the JSBin.
Kevin Phillips
@phillipskevin
Mar 30 2016 17:42
I think that is the problem
it looks like it’s toStringing your object
Christopher Oliphant
@RALifeCoach
Mar 30 2016 17:42
okay, any ideas on a solution?
Kevin Phillips
@phillipskevin
Mar 30 2016 17:42
this is something you need to do in your real code?
Christopher Oliphant
@RALifeCoach
Mar 30 2016 17:42
is there a can equivalent?
Yes, this is something that will have to happen in my code.
Kevin Phillips
@phillipskevin
Mar 30 2016 17:43
so you call template({pid: '11111', player: player}) with the initial data from the server
and then later you need to update it?
Christopher Oliphant
@RALifeCoach
Mar 30 2016 17:44
yes - that is correct
the data in player will change often
Kevin Phillips
@phillipskevin
Mar 30 2016 17:44
so maybe there is some confusion
@justinbmeyer in many ways my code is quite simple. All data is display only. There is some binding against controls, but not against the data itself.
I definitely misunderstood that to mean the data wouldn’t be changing
I have to run to a meeting, be back in a few
Christopher Oliphant
@RALifeCoach
Mar 30 2016 17:45
okay - thanks
Kevin Phillips
@phillipskevin
Mar 30 2016 18:04
I would say that you do want to use a Map then
but maybe Justin can explain more what he was suggesting when he is around later
Christopher Oliphant
@RALifeCoach
Mar 30 2016 18:05
actually - your question started me thinking - I changed .attr(‘player', player) to .data(‘player’, player) and the JSBin is now working
Kevin Phillips
@phillipskevin
Mar 30 2016 18:08
it’s working? or it’s just not throwing an error?
I don’t see it change to iiiii ppppp
Christopher Oliphant
@RALifeCoach
Mar 30 2016 18:10
You’re right - I spoke too soon
Bummer
that’s working
it’s a bit sketchy, but it’s working
Kevin Phillips
@phillipskevin
Mar 30 2016 18:35
ok
I’m not really sure if that will perform any better
Christopher Oliphant
@RALifeCoach
Mar 30 2016 18:36
either am I
and it will take me a couple of hours of work to find out
Thomas Sieverding
@Bajix
Mar 30 2016 18:39
Why are you doing this playerStr stuff?
You can just set player to an object
Christopher Oliphant
@RALifeCoach
Mar 30 2016 18:39
Because I am trying to pass an object into the component via attributes
that didn’t work when I tried it
Thomas Sieverding
@Bajix
Mar 30 2016 18:40
You’re trying to construct the component from JSON passed as attributes?
Christopher Oliphant
@RALifeCoach
Mar 30 2016 18:40
yes
Thomas Sieverding
@Bajix
Mar 30 2016 18:41
I think something akin to data-player=‘{“foo”:”bar”}’ would work
This would only work on insertion
Also, but why?
Christopher Oliphant
@RALifeCoach
Mar 30 2016 18:42
I have the insertion working fine. I need help getting the update to work.
Why? An idea suggested by Justin.
Kevin Phillips
@phillipskevin
Mar 30 2016 18:43
@justinbmeyer in many ways my code is quite simple. All data is display only. There is some binding against controls, but not against the data itself.
This message was deleted
This message was deleted
Thomas Sieverding
@Bajix
Mar 30 2016 18:44
Yea, I think you’ve misconstrued what he was saying
Kevin Phillips
@phillipskevin
Mar 30 2016 18:44
@RALifeCoach if that's the case, I wouldn't convert it to a Map at all
since Justin won’t be around until later this evening, I took a guess that he meant to just pass the raw data to the template renderer
then we went down this rabbit hole
Christopher Oliphant
@RALifeCoach
Mar 30 2016 18:55
@Bajix any ideas on how to pass an object into the component?
Thomas Sieverding
@Bajix
Mar 30 2016 18:56
can.view(‘#my-template’, { player: {} }, function( frag ) { … })
Christopher Oliphant
@RALifeCoach
Mar 30 2016 18:57
that gets it in - what about updating?
Thomas Sieverding
@Bajix
Mar 30 2016 19:00
You have several options. 1) Update it within the component. 2) Update your root scope lexically 3) Use sibling components, write to the reference scope & have your main component bind to changes 4) Use can.viewModel 5) Use Model stores to indirectly update data
can.view will accept a PJSO, can.Map instance, or can.view.Scope instance
Christopher Oliphant
@RALifeCoach
Mar 30 2016 19:03
  1. I understand
  2. I do not understand
  3. I understand
  4. How would I access can.viewModel from outside the component?
  5. I do not know what you mean by Model stores?
Thomas Sieverding
@Bajix
Mar 30 2016 19:03
You could use a can.view.Scope instance to build a scope tree from multiple can.Map instances, that would traverse in reverse order
Christopher Oliphant
@RALifeCoach
Mar 30 2016 19:04
Remember, the goal is to avoid using can.Map.
Thomas Sieverding
@Bajix
Mar 30 2016 19:04
That’s a silly goal
If you pass a PJSO into can.view, it’ll become a can.Map instance regardless
Christopher Oliphant
@RALifeCoach
Mar 30 2016 19:05
lol - it was suggested by Justin - I am just trying to figure out what he meant
Thomas Sieverding
@Bajix
Mar 30 2016 19:06
He meant you should use type: ‘*’
Christopher Oliphant
@RALifeCoach
Mar 30 2016 19:06
Here is his statement, "if that's the case, I wouldn't convert it to a Map at all”
and using ‘*’ requires a map
Kevin Phillips
@phillipskevin
Mar 30 2016 19:07
like I said before, I think he might have said that thinking that you don’t need to update the data
“the case” in the statement “if that’s the case” was that your data didn’t need binding
Thomas Sieverding
@Bajix
Mar 30 2016 19:07
You would need to use a can.Map.extend that takes advantage of type: ‘*’ to prevent those properties from automatically being converted
If you just pass a PJSO into can.view, it’s the same as constructing a can.Map
The only way to avoid implicitely construction can.Map / can.List instances is to explicitely use type: ‘*’ on those properties
Christopher Oliphant
@RALifeCoach
Mar 30 2016 19:08
You could be right. I will await his return and see what he has to say on the matter. I managed to solve the problem, and that was fun.
It is now time for me to run. Thanks again for all your help and assistance.
Thomas Sieverding
@Bajix
Mar 30 2016 19:09
I can assure you my above statements are accurate
Justin will say the same
Christopher Oliphant
@RALifeCoach
Mar 30 2016 19:12
@Bajix I will be optimistic and see what Justin has to offer, although I expect you are right.