These are chat archives for canjs/canjs

17th
Apr 2017
Mohamed Cherif Bouchelaghem
@cherifGsoul
Apr 17 2017 08:34
@nriesco The issue is that the plugin dosent find the needed DOM, I've seen some other libs that used it when I have time I will make a jsbin
Mohamed Cherif Bouchelaghem
@cherifGsoul
Apr 17 2017 11:14
@nriesco I make it work finaly
Viktor Busko
@Lighttree
Apr 17 2017 13:12

Hi, I have one strange case, maybe someone can suggest better solution:

I have a textarea that should track its content and increase height. This is implemented using "helper" textarea that can provide us required height.
This was working fine when I bind all the logic to keyboard events, but I descided to change the logic a bit and do recalculation when message property changes.
The problem that I faced is that it seems that super-input:messageChange dispatches BEFORE DOM actually renders new value in textareaHelper so I have old scrollHeight (because if I put breakpoint I see new value in ViewModel and old value in textarea DOM element)

This works more-less fine if I wrap messageChange handler to setTimeout(function () { }, 0), but this is something that I'm trying to avoid, because looks like hack and adds some blink on UI when height of textarea changes.

Is there any nice way to get correct textarea height (right after this updates in DOM) ?

events: {
            inserted: function () {
                this.viewModel.attr('textarea', this.element.find('.superTextarea-field'));
                this.viewModel.attr('textareaHelper', this.element.find('.superTextarea-helper'));
            },
            init: function () {
                this.viewModel.bind('message', function (ev, newValue, oldValue) {
                    this.dispatch('super-input:messageChange', [newValue, newValue, oldValue]);
                });
            },
            '{scope} super-input:messageChange': function () {
                this.viewModel.updateHeight(this.viewModel.attr('textarea').outerHeight(), this.viewModel.attr('textareaHelper')[0].scrollHeight);
            },
            '{window} resize': debounce(function () {
                this.viewModel.updateHeight(this.viewModel.attr('textarea').outerHeight, this.viewModel.attr('textareaHelper')[0].scrollHeight);
            }, 66)
 }
Ranjan Subbiah
@ranjanbuilds
Apr 17 2017 14:48

Hi, I am using map.set and passing in an object:

this.default_selector.set({ selectorName: { options: updatedOptionsHash } });

And I was wondering the best way to pass in 'selectorName' as a variable

Kevin Phillips
@phillipskevin
Apr 17 2017 14:51
this.default_selector.set({ [ selectorNameVariable ]: { options: updatedOptionsHash } }); should work
Ranjan Subbiah
@ranjanbuilds
Apr 17 2017 15:09
thanks Kevin
Kevin Phillips
@phillipskevin
Apr 17 2017 15:10
:thumbsup: no problem
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 16:06
@Lighttree one thing you could do is listen to attributes on the textarea. This may generate a lot of events, but a handler like this will probably do what you want without timeouts:
"{viewModel.textarea} attributes": function(vm, el, event) { 
    if(event.attributeName === "style") {
        this.viewModel.updateHeight(...)
   }
}
Viktor Busko
@Lighttree
Apr 17 2017 16:06
I'll try thanks
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 16:15
when the height of the element changes, it triggers a general style attribute change. I'm doing this in a JSbin with slightly different distribution of control (handler on the element bound in the stache) : https://jsbin.com/fupuxiveta/1/edit?html,js,output
Gregg Roemhildt
@roemhildtg
Apr 17 2017 17:04
I've been running into a scenario, where I would like to access a particular element rendered in a component. For now, it seems like the only way to do this is to use the inserted event, and then use element.querySelector('.my-element-class'). Has anyone thought of adding a special tag type, that would pass the specific element into the component viewmodel as a property? Or can I do this already? <div class="my-element-class" {^%element}="myProp" /> ?
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 17:10
Something like <div class="my-element-class" ($inserted)="%viewModel.set('myProp', %element)" /> ?
Gregg Roemhildt
@roemhildtg
Apr 17 2017 17:12
Ah, that'll work
Awesome, thanks!
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 17:21
I have to look into this a bit more, but if it seems like %viewModel.set isn't setting the value where you'd expect, try %scope.set
Oh right, I forgot about %context, which is what I meant in the first place.
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 17:35
For general channel's benefit and info, can-stache-bindings has three different scope references that you might want to use at different times:
  • %scope is the whole stack of scope context. sets to %scope are set on the current context (top of the stack), but gets can happen at any level
  • %context is the top of the scope stack, and gets and sets only from/to that object. If you need to go to a scope level above (like if you're rendering a {{#section}}), try %scope._parent or %scope._parent._context instead
  • %viewModel is the view model bound to the element, and isn't related to the scope or scope context. This is where the naming can get confusing, because the identifier scope on components has been replaced with viewModel to mean the view model on the component.
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 18:10
(%viewModel when setting up bindings on a component element === viewModel within in the component)
Gregg Roemhildt
@roemhildtg
Apr 17 2017 18:13
That helps clear it up a lot I think. Just to be clear, scope on a can.Component is deprecated, but %scope in a template is not deprecated?
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 18:15
That's correct. You can see the full list of special names in bindings on the page for event bindings: http://canjs.com/doc/can-stache-bindings.event.html
To the best of my knowledge, none of these are deprecated.
Viktor Busko
@Lighttree
Apr 17 2017 19:01

@bmomberger-bitovi thanks for your answers. "{viewModel.textarea} attributes" I didn't use such syntax before but it works, and gave me some other ideas how to improve the code :)

For example instead of this:

init: function () {
                this.viewModel.bind('message', function (ev, newValue, oldValue) {
                    // some code
                });
            },

I can write this:

'{viewModel} message' : function  () {}

Looks better :)

Brad Momberger
@bmomberger-bitovi
Apr 17 2017 19:04
Yes, and you also get the benefit of automatic event teardown when the component is destroyed.
Viktor Busko
@Lighttree
Apr 17 2017 19:04
:+1:
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 19:05
(Don't forget, if you don't need an element reference, you can handle most property change effects with a setter on the view model. If you do need an element ref, like for dispatching events, then the above syntax is the preferred way)
Viktor Busko
@Lighttree
Apr 17 2017 19:11
I use get / set heavily, but sometimes I need to handle value when it just "setted", but if I put my logic to setter it will run before the value actually changed (because it will happen only after return from setter). In this case this will be correct as well (even if there is no need in element reference) ?:
'{viewModel} message' : function  () {}
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 19:13
You can also use the async setter pattern synchronously if you want to handle the value after being set:
set: function(newVal, setter) {
  setter(newVal);
  // then do something interesting with the value or dependent values.
 }
Kevin Phillips
@phillipskevin
Apr 17 2017 19:14
what’s the benefit of that @bmomberger-bitovi ? over just return newVal;
oh, I get what you mean about dependent values
Viktor Busko
@Lighttree
Apr 17 2017 19:15
@bmomberger-bitovi oh :) I'll try this next time, thanks this might be very handy, because I have some cases when I need to do something right after new value being set.
Brad Momberger
@bmomberger-bitovi
Apr 17 2017 19:15
Yeah, what can happen is that you might call a function that doesn't accept the value as an arg but reads it off the object.
Kevin Phillips
@phillipskevin
Apr 17 2017 19:16
yeah, I got ya