These are chat archives for canjs/canjs

8th
Mar 2016
dylanrtt
@dylanrtt
Mar 08 2016 00:04
@Bajix I have run into this a number of times, but I was always able to resolve it by callling .attr() on the map before passing it in. Example: map1.attr(map2.attr()). What is your use case exactly?
Thomas Sieverding
@Bajix
Mar 08 2016 00:05
I'm documenting the issue now, but the childToParent bindings passing in the can.Map directly
childToParent: function(el, parentCompute, childCompute, bindingsSemaphore, attrName, syncChild) { var parentUpdateIsFunction = typeof parentCompute === 'function'; var updateParent = function(ev, newVal) { if (!bindingsSemaphore[attrName]) { if (parentUpdateIsFunction) { parentCompute(newVal); if (syncChild) { if (parentCompute() !== childCompute()) { bindingsSemaphore[attrName] = (bindingsSemaphore[attrName] || 0) + 1; childCompute(parentCompute()); can.batch.after(function() { --bindingsSemaphore[attrName]; }); } } } else if (parentCompute instanceof can.Map) { parentCompute.attr(newVal, true); } } }; if (childCompute && childCompute.isComputed) { childCompute.bind('change', updateParent); } return updateParent; },
Hmm that didn't format well
dylanrtt
@dylanrtt
Mar 08 2016 00:07
I think I see the problem on parentCompute.attr(newVal, true); in bindings.js
Thomas Sieverding
@Bajix
Mar 08 2016 00:07
can/view/bindings childToParent is messing things up here: parentCompute.attr(newVal, true);
As newVal often will be a can.Map
So what I was seeing in _setAttr is a symptom of that
dylanrtt
@dylanrtt
Mar 08 2016 00:09
Yeah, so either a check there to run attr()/serialize() or update _setAttrs seem reasonable
If you pass a map to a map constructor with map1 = new can.Map(map2) it currently runs serialize()
Thomas Sieverding
@Bajix
Mar 08 2016 00:09
Is there any specific reason why we can't do map1.attr(map2, true)?
Surely we could make _setAttr serialize map2 internally
IMO the childToParent line should be acceptable
That's a trap that I've seen hang up a lot of developers
dylanrtt
@dylanrtt
Mar 08 2016 00:12
Seems reasonable to me but I can't say for sure. I have also seen this a lot before
Thomas Sieverding
@Bajix
Mar 08 2016 00:13
IMO it's a coding trap
I don't think it's enough to simply tell developers to not pass maps into attr
If it doesn't make sense to allow this feature, then we should throw an error
@justinbmeyer Do you see any reason not to support allowing passing can.Map instances into attr?
Thomas Sieverding
@Bajix
Mar 08 2016 00:32
@dylanrtt Now that I think about it, the childToParent behavior introduces other issues
For example, if the parent Map is a can.Model instance of a different ID
dylanrtt
@dylanrtt
Mar 08 2016 00:35
@Bajix Under what circumstances are you seeing that parentCompute is a plain object?
Thomas Sieverding
@Bajix
Mar 08 2016 00:35
I never said I was
parentCompute was an instanceof can.Map
dylanrtt
@dylanrtt
Mar 08 2016 00:36
oops, I misunderstood
Thomas Sieverding
@Bajix
Mar 08 2016 00:36
the newVal was also a can.Map, and that logic tries to merge properties
My argument is that merging properties is unsafe, and will create unintentional consequences w/ out can.Model works
dylanrtt
@dylanrtt
Mar 08 2016 00:37
so parentCompute I think is a map because a compute could not be created because the parent of it was a plain object
I'm just trying to think of another way to address the original problem in case that solves the can.Model issue you are referring to
Thomas Sieverding
@Bajix
Mar 08 2016 00:37
In my case, childToParent is updating %root
parentCompute is always a compute/can.Map AFAIK
I've brought up this issue before, but I don't think it's safe to merge can.Map's in a number of cases, not just this one
For example, if you don't override can.Model.parseModel to explicitly call can.Model.model/can.Model.models on the respective properties, then the current behavior recursively sets properties by merging
dylanrtt
@dylanrtt
Mar 08 2016 00:44
With can.Model being deprecated in favor of can-connect, I'm not sure if that will be an issue moving forward.
I agree that merging in this case seems inappropriate. With the problem being that the parent scope is a plain object, I can see how it is challenging. Perhaps the solution would be to prevent the case where the parent is a plain object so a compute can always be created.
Thomas Sieverding
@Bajix
Mar 08 2016 00:45
I don't think can-connect is a substitute for can.Model
If anything it would be a plugin of can.Model
dylanrtt
@dylanrtt
Mar 08 2016 00:46
Everything I've heard suggests it is supposed to be the substitute
Thomas Sieverding
@Bajix
Mar 08 2016 00:46
It would still be dependent on the same kind of model store concept
I don't see any reason why can-connect wouldn't suffer the exact same issue
They're both dependent on all instances of the same ID being the same instance
This is an issue that happens consistently if you have nested model structures
dylanrtt
@dylanrtt
Mar 08 2016 00:51
Merging happens often with nested model structures?
Thomas Sieverding
@Bajix
Mar 08 2016 00:53
For example, say you have a User model w/ blockedUsers as a property that's a User.List
Adam Tourkow
@atourkow
Mar 08 2016 00:54
I'm confused, if I have <input ($enter)="save()" /> and in the VM have save: function(a,b,c) { console.log(a,b,c); } a,b,c are undefined. I'm looking through the docs, but there's multiple versions of how events are used
Thomas Sieverding
@Bajix
Mar 08 2016 00:54
If you updated a user's blockedUser list, and saved, the data that returned would be unsafely merged
@atourkow See call expressions.
($enter)="model.save()"
$submit would probably be better
(on the form tag)
Adam Tourkow
@atourkow
Mar 08 2016 00:57
it's for a search, wasn't using a full form tag.
Adam Tourkow
@atourkow
Mar 08 2016 00:57
so, not save() but search()
Thomas Sieverding
@Bajix
Mar 08 2016 00:58
If you just did {search} it would call back w/ the el/ev/scope I believe
but since you're using a call expression, you need to setup the passed parameters
Adam Tourkow
@atourkow
Mar 08 2016 01:00
@Bajix What do you mean {search} can you show me the full <input> with {search}
Thomas Sieverding
@Bajix
Mar 08 2016 01:00
One sec
So this should probably be reference w/in the stache call expression docs
<input {($value)}="myQuery" ($enter)="search()">
<input ($enter)="search(%element)">
Thomas Sieverding
@Bajix
Mar 08 2016 01:04
You can use $value to cross-bind to some property in your scope, or otherwise to root
And then pass that into search
Otherwise you could pass the element into search and read it's value
Adam Tourkow
@atourkow
Mar 08 2016 01:05
god, those wrapper things confuse me
Yeah, i don't need to cross-bind in this case
Thomas Sieverding
@Bajix
Mar 08 2016 01:06
You get used to them very quickily
Adam Tourkow
@atourkow
Mar 08 2016 01:06
Like I don't get the {($value)}="myQuery" part either
Thomas Sieverding
@Bajix
Mar 08 2016 01:07
I don't think %element.value works sadly, otherwise I'd recommend that
Well, the $ part means it's an event on the elment
Adam Tourkow
@atourkow
Mar 08 2016 01:07
could use $element.attr('value')?
Thomas Sieverding
@Bajix
Mar 08 2016 01:09
$element.val(), $element.attr('value'), and %element.value should all work, but I don't think it's properly supported at the moment
dylanrtt
@dylanrtt
Mar 08 2016 01:09
You should be able to do search($element.val)
Thomas Sieverding
@Bajix
Mar 08 2016 01:09
If it were any other value that would work
Yea. If that doesn't work I'll create a ticket and make sure it's in the next release
dylanrtt
@dylanrtt
Mar 08 2016 01:11
I can confirm that works, as well as %element.value so not sure what your issue was there
Adam Tourkow
@atourkow
Mar 08 2016 01:11
Interesting, if I do ($keypress)=search($element.val) it shows the result from the previous keypress
Thomas Sieverding
@Bajix
Mar 08 2016 01:12
@atourkow That's how keypress works
you're looking for keyup
Also paste
Adam Tourkow
@atourkow
Mar 08 2016 01:12
Why, yes I Am :)
Thomas Sieverding
@Bajix
Mar 08 2016 01:13
The $value event is the easiest to work with
Adam Tourkow
@atourkow
Mar 08 2016 01:13
Just do double confirm, %element.value works.
Thomas Sieverding
@Bajix
Mar 08 2016 01:13
perfect
Adam Tourkow
@atourkow
Mar 08 2016 01:13
@Bajix you mean the {($value)} thingy?
Thomas Sieverding
@Bajix
Mar 08 2016 01:14
Yes. That uses the change event
Change isn't triggered every keystroke. See above for a more detailed explanation
Adam Tourkow
@atourkow
Mar 08 2016 01:15
So {($value)}="myVal" would translate to viewModel: { myVal: ... }
Thomas Sieverding
@Bajix
Mar 08 2016 01:16
If you want to use keyup, and support 2 way binding, you need to wire up element selection logic
Thomas Sieverding
@Bajix
Mar 08 2016 01:16
'textarea keyup': function( el, ev ) {
  var message = el.val();

  if (message !== this.scope.message) {
    var selection = el.selection();
    this.scope.attr('message', message);
    el.selection(selection.start, selection.start);
  }
}
Adam Tourkow
@atourkow
Mar 08 2016 01:17
perhaps a newline after the three `
Thomas Sieverding
@Bajix
Mar 08 2016 01:18
Yea
Adam Tourkow
@atourkow
Mar 08 2016 01:18
that would then go into viewModel: { events: { ... } }
Thomas Sieverding
@Bajix
Mar 08 2016 01:19
IMO we should add in something like {($live)} to support paste/keyup out of the box
Well no, events isn't part of viewModel
They're sibling properties of can.Component
Adam Tourkow
@atourkow
Mar 08 2016 01:20
Oh, I see in the docs
Thomas Sieverding
@Bajix
Mar 08 2016 01:20
You have a lot of options there though. Events, viewModel as a function, or as a helper
Adam Tourkow
@atourkow
Mar 08 2016 01:21
I think that's why I get tripped up
Thomas Sieverding
@Bajix
Mar 08 2016 01:22
Use viewModel functions whenever possible
Use helpers when a viewModel doesn't suffice (IE options.inverse)
Adam Tourkow
@atourkow
Mar 08 2016 01:23
I dunno what it is about CanJS that keeps drawing me back, but man, the docs are now all over the place in consistent. :)
Thomas Sieverding
@Bajix
Mar 08 2016 01:24
Use events to supplement computes by binding to scope changes and manually updating state
Well, CanJS has a monopoly on observables/computes
Adam Tourkow
@atourkow
Mar 08 2016 01:25
is "init" still valid?
Thomas Sieverding
@Bajix
Mar 08 2016 01:25
Yes
events = can.Control
viewModel = can.Map
both extend can.Construct, and have setup/init
Adam Tourkow
@atourkow
Mar 08 2016 01:26
but not component? So, like when it first loads. But, is that what define.get is for?
Thomas Sieverding
@Bajix
Mar 08 2016 01:27
Components are just glue for can.Control + can.Map + can.view
define getters aren't a substitute for init
Adam Tourkow
@atourkow
Mar 08 2016 01:35
Thanks :)
can.ajax vs jQuery.ajax?
Thomas Sieverding
@Bajix
Mar 08 2016 01:46
can.ajax
Adam Tourkow
@atourkow
Mar 08 2016 01:47
@Bajix just curious, why?
Thomas Sieverding
@Bajix
Mar 08 2016 01:48
CanJS is portable, and as an author you cannot assume jQuery is what's being used
Also, can.ajax === jQuery.ajax
It's an alias. Same reference in memory
It's also a simpler dependency tree if you don't need to include jQuery
(use can.$ instead of $ directly, whenever applicable)
Thomas Sieverding
@Bajix
Mar 08 2016 02:05
Why aren't sub templates included within the dependency tree when using can/view/stache/system? I can open a PR to include them
Phippsy
@michaelphipps
Mar 08 2016 02:39
In models, I call endpoints like findall: " GET /campaigns". How do I set the domain name those endpoints are on?
Thomas Sieverding
@Bajix
Mar 08 2016 02:41
You're doing cross-site?
@michaelphipps
Phippsy
@michaelphipps
Mar 08 2016 02:42
kinda. I have an api subdomain and an app subdomain
front end on app. domain.com back end on api.domain.com
same server.
Thomas Sieverding
@Bajix
Mar 08 2016 02:43
You'll need to modify your XHR requests as well
can.ajaxSetup({
  beforeSend: function( deferred, xhr ) {
    if (xhr.dataType === 'json') {
      xhr.withCredentials = true;
    }
  }
});
I'd recommend using the resource property for this
IE: resource: config.hosts.api + '/users'
Phippsy
@michaelphipps
Mar 08 2016 02:44
ok cool. Thanks for the pointers. I'm literally 2 hours new with canjs.
Thomas Sieverding
@Bajix
Mar 08 2016 02:45
That's shorthand for explicitly setting up each route
Do you have a build system?
Phippsy
@michaelphipps
Mar 08 2016 02:45
No.
Thomas Sieverding
@Bajix
Mar 08 2016 02:46
Couple of options there then. You could use the setup @ donejs.com
That's sort of the entire CanJS ecosystem rolled up in one
Phippsy
@michaelphipps
Mar 08 2016 02:48
just looking at that now
what's a build system achieve for me anyway. I feel like I've been playing in the dark with PHP and MySQL for way longer than I should have.
Thomas Sieverding
@Bajix
Mar 08 2016 02:52
I personally use BroccoliJS, which allows me to add steps do to things like compiling SASS templates
Or minifying my stache templates
I also combine that w/ a couple modules I wrote
I use broccoli-config-writer to take my config, and include a subset of that to be used within the browser
It allows you to hierarchically merge settings, such that your base settings can be overridden by environment settings, or by environment variables
My user model, for instance, requires config and uses resource: config.hosts.api + '/users',
That way it points to the domain I'm currently using, be it staging/prod/beta/dev
Phippsy
@michaelphipps
Mar 08 2016 02:56
Ok. Now I understand.
Thomas Sieverding
@Bajix
Mar 08 2016 02:56
I also use the build system to bundle dependencies
I'm using SystemJS, rather than steal js, and my main file is simply a self-executing bundle that calls can.autorender
Phippsy
@michaelphipps
Mar 08 2016 02:56
so when there's updates in a dependency it's easy to update.
Thomas Sieverding
@Bajix
Mar 08 2016 02:57
Well, build systems don't have anything to do with external dependencies generally
Well, at least not directly
I'm using JSPM which writes to my packages folder, which I then treat as a separate tree and merge into my assets during build
JSPM + SystemJS is a pretty good middle ground IMO
I just put together a couple pieces to make it fit better into the CanJS ecosystem, and I'm releasing that soon, but right now it doesn't play nice out of the box
Follow me on Github. I'm releasing the respective tools later this week
Phippsy
@michaelphipps
Mar 08 2016 03:02
done - I'll have to revisit the build stuff later on - too much information for my head right now.
Thomas Sieverding
@Bajix
Mar 08 2016 03:03
Yea. It's a lot to digest
Phippsy
@michaelphipps
Mar 08 2016 03:03
Thanks for the guidance btw
Thomas Sieverding
@Bajix
Mar 08 2016 03:03
Np
Phippsy
@michaelphipps
Mar 08 2016 03:03
It is a lot to digest. Like I said earlier - I've been playing with PHP / MySQL apps that long, that I've been blind to what's happening around me.
Thomas Sieverding
@Bajix
Mar 08 2016 03:04
It doesn't take long for that to happen
Guido Smeets
@gsmeets
Mar 08 2016 06:08
.
DWD
@smoothlikejazz00
Mar 08 2016 19:04

Hi, I have a question regarding stache, I have a user model object which has a method hasRole(<string>) returns true/false, im passing the model into my template and have a section of code that looks like

{{#user}}
    {{#hasRole "admin" }}
        <i class="glyphicon glyphicon-trash delete-agent"></i>
    {{/hasRole}}
{{/user}

as an admin the output of this template places “true” in the DOM instead of my expected block with icon.

Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 08 2016 19:23
@smoothlikejazz00 a helper would be better
Kevin Phillips
@phillipskevin
Mar 08 2016 19:26
@smoothlikejazz00 you might be able to do {{#is hasRole(“admin”) true}}
actually that won’t work
like @cherifGsoul a helper is probably the way to go… or a property on the model like isAdmin that just uses your hasRole method
DWD
@smoothlikejazz00
Mar 08 2016 19:29
I have several methods on my models, would i need to then port them all and use as helpers. Im converting my ejs templates into stache. in ejs this was doable with just
<% if( user.hasRole(‘admin')){ … %>
Kevin Phillips
@phillipskevin
Mar 08 2016 19:29
you might be able to do it with call expressions
I’m trying it out in a jsbin, I’ll let you know how it goes
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 08 2016 19:29
Oh I forgot is builtin helper thank you @phillipskevin
Kevin Phillips
@phillipskevin
Mar 08 2016 19:30
I don’t think it would work with true though
@smoothlikejazz00 did you try {{#hasRole(“admin”)}} ?
DWD
@smoothlikejazz00
Mar 08 2016 19:31
thanks for the replys as well @phillipskevin & @cherifGsoul, ill try the #is and also the helper
Kevin Phillips
@phillipskevin
Mar 08 2016 19:31
same as you had, with ()
DWD
@smoothlikejazz00
Mar 08 2016 19:34
yeah that unfortunately doesnt work {{#hasRole(“admin”)}}its not calling my model method
Kevin Phillips
@phillipskevin
Mar 08 2016 19:35
hmm, seems to work for me
DWD
@smoothlikejazz00
Mar 08 2016 19:37
maybe my context is off, this is inside of a {{#each loop, thanks for your example, ill debug more
Kevin Phillips
@phillipskevin
Mar 08 2016 19:38
ok, good luck
DWD
@smoothlikejazz00
Mar 08 2016 19:38
thanks @phillipskevin much appreciated.
DWD
@smoothlikejazz00
Mar 08 2016 21:16
hey @phillipskevin so turns out to be the version i am using 2.2.9, ive modified your jsbin http://jsbin.com/yeyaxi/edit?html,js,output
updating the version to latest version works as expected
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 08 2016 21:18
@smoothlikejazz00 2.3 is required to use expression calls
DWD
@smoothlikejazz00
Mar 08 2016 21:20
okay cool thanks @cherifGsoul for your help as well, ill be upgrading my project.
Kevin Phillips
@phillipskevin
Mar 08 2016 21:20
that’s great if you can do that
Adam Tourkow
@atourkow
Mar 08 2016 21:22
So many helpful people here :)
Adam Tourkow
@atourkow
Mar 08 2016 21:50
In a component, how can I run an init script when it loads?
oh, setup: function() {... }
well, init:
Mohamed Cherif Bouchelaghem
@cherifGsoul
Mar 08 2016 21:55
@atourkow if you mean you want to run a behavior when component is inserted in the DOM so inserted event if the best place
Adam Tourkow
@atourkow
Mar 08 2016 22:01
@cherifGsoul so can.Component.extend({ tag: 'foo', inserted: function() { ... } });
no, that didn't work
dylanrtt
@dylanrtt
Mar 08 2016 22:04
inserted should be in the events
Adam Tourkow
@atourkow
Mar 08 2016 22:05
@dylanrtt ahh, got it
Oh, I see what init is supposed to do
Kevin Phillips
@phillipskevin
Mar 08 2016 22:07
what is the script you’re trying to run when the component loads?
Adam Tourkow
@atourkow
Mar 08 2016 22:08
Some ajax and start a timer, but I don't want to use model/define/get functionallity
Kevin Phillips
@phillipskevin
Mar 08 2016 22:08
ok
why not? :smile:
Adam Tourkow
@atourkow
Mar 08 2016 22:09
Confuses me, you helped me out before. Just have trouble wrapping my head around it. :)
with the get, deferred, set stuff, I can't wrap my head around it as opposed as to a more linear flow
Kevin Phillips
@phillipskevin
Mar 08 2016 22:11
ok
you can checkout this video on the define plugin: https://www.youtube.com/watch?v=8tVE7QFstdE
might help make more sense of it
Adam Tourkow
@atourkow
Mar 08 2016 22:14
holy hour batman :)
Kevin Phillips
@phillipskevin
Mar 08 2016 22:14
yeah...
totally up to you… if what you’re doing is working :+1:
Gregg Roemhildt
@roemhildtg
Mar 08 2016 22:18
Hello, not sure if I'm doing this wrong but it seems that a child to parent binding on a List doesn't update when the list changes. http://jsbin.com/tumenohate/1/edit?html,js,console,output
Adam Tourkow
@atourkow
Mar 08 2016 22:34
thanks @phillipskevin :)
Adam Tourkow
@atourkow
Mar 08 2016 23:00
how can I have an action in one component trigger a function in another component.viewModel?
dylanrtt
@dylanrtt
Mar 08 2016 23:04
@atourkow there are many ways. what is the relationship between your components? e.g., parent-child, siblings...? are they used in the same template?
@roemhildtg the parent myRows will only be updated when the child rows is set directly, so adding/removing items in the list will not trigger the myRows.set
Gregg Roemhildt
@roemhildtg
Mar 08 2016 23:10
Oh I see. So I could just do val.bind('change, function(...){...}); in the set function.
dylanrtt
@dylanrtt
Mar 08 2016 23:11
I don't think that's a good idea because you would have to unbind it manually elsewhere
you could use the component's events object to observe changes to the list
"{viewModel.myRows add}": function(){...}
not sure what your use case is, but you may not need to observe changes at all if you simply want to display them in a template which will automatically observe changes
Gregg Roemhildt
@roemhildtg
Mar 08 2016 23:14
Let me back up a second, I had forgotten why I originally posted that..the parent component doesn't seem to render the list.
If I set it up correctly, my-component should be rendering myList which should be the same as rows from the child-component.
dylanrtt
@dylanrtt
Mar 08 2016 23:16
If you update both myRows in the template to *myRows it works as expected. The references scope looks like the right thing to use in this example unless you actually need it on the parent viewmodel
not sure why it doesn't work the way you did it
dylanrtt
@dylanrtt
Mar 08 2016 23:21
oh it's because you didn't return val in your setter so it was set to undefined in the parent viewmodel
Gregg Roemhildt
@roemhildtg
Mar 08 2016 23:24
Ah.
My use case is, I have a list in a child component, that when updated, I would like to update another value on the parent component.
dylanrtt
@dylanrtt
Mar 08 2016 23:30
Hmm... that still seems a bit vague so there are a few ways you could do it. One way would be to make your "another value" a virtual get property that loops on the list to perform some sort of aggregation.
Gregg Roemhildt
@roemhildtg
Mar 08 2016 23:37
I'll update my jsbin with a more relevant example, but I think the '{viewModel.myRows add}' event should work for me.
Gregg Roemhildt
@roemhildtg
Mar 08 2016 23:50
Here's the updated: http://jsbin.com/vifapemobo/1/edit?html,js,console,output
Basically, when the value of rows changes in the child, I want to update another property on the parent viewModel. The reason I don't think a getter on the other property would work is because parameters is not an entirely 'virtual' property, parameters could be passed into the parent component.