Ember classNameBindings not being called for the sample program - ember.js

I am facing issue with class name bindings. Here is the jsfiddle code for the same. Logging the number of times binding is called. It is never called when the property is changed.

You appear to have a couple of issues here. Primarily, if you want properties to be recalculated when the contents of an array change, you cannot just depend on the array property itself - it will only fire a change when it is set to a different array. If you depend on myArray.#each instead, your property will be recalculated when the contents change as well.
Next, your template containing the span isn't rendering because you're providing an empty view template in your handlebars view declaration. Change your "HTML" to:
{{view App.contact}}
and your span will appear.
Finally, running Ember.run.sync() does not appear to be enough here. I am not as clear on the reason behind this but...computed properties only update when read (versus observers that update immediately). I would hypothesize that since your computed property is only used by the view and the view may only update on a subsequent run through the JS event loop, your computed property is recalculated only once for all your changes to "subordinates". Change your code to use timeouts and it'll work fine.
Here's a jsfiddle with all of my proposed changes.

Related

Mutuable property passed from template is not updated

I have a case where I am passing a property to child component wrapped inside a mut helper. Then I am updating this value in child component, and send action into parent component using closure action.
Then if I read this value in parent component with get, I get correct value. But if I pass this property to action from template, I get not updated value.
I've provided an Ember-Twiddle to illustrate this problem (check out console.log).
Am I missing something in this solution? Or is it working as expected? Please take a look at onInnerUp action in index controller to see what I am trying to do.
I know this is very messy description, hope someone will understand what am I struggling with
It is working as expected. Here is why?
When the template index.hbs is rendered at some point it creates an action via the action helper with the current value assigned to controllerVal. In your case; after the initial render that value is 0.
The action will only be recreated after the template is re-rendered. In your twiddle you are not waiting for the template to re-render and immediately triggering the action (which has already been created with the previous value of controllerVal). Even though the controllerVal is increased automatically (due to two-way-binding) when value within my-component.js is increased; the action is not yet re-created and holds the previous value; hence you get previus value that was assigned to controllerVal as parameter to your action. I hope I manage to explain what is going on in a simple way.
In fact Lux has already explained the way to overcome this situation in his comment above; but I have created a modified twiddle for you. In this twiddle I am not immediately triggering the action; but delaying it till the next rendering is finished via Ember.run.scheduleOnce(queue, target, method). I used afterRender queue in order to wait for rerendering of the template. You can look further for Ember run loop if you like. This might be a good starting point I guess. My best regards.

Ember.js: sending actions to components?

I have a mixin for Ember components, named in-view, the job of which is to request that that the element be brought in view. It is provided an attribute whose value is an piece of content to be brought into view, and if that attribute matches the component's content then I call scrollIntoView or the equivalent. The code looks something like this:
// calling template
{{#each items as |item|}}
{{my-item content=item inViewItem=inViewItem}}
}}
// mixins/in-view.js
scrollIntoView() {
if (this.get('content') === this.get('inViewItem'))
this.get('element').scrollIntoView();
}.on('didInsertElement')
// components/my-item/component.js
import InView from 'mixins/in-view';
export default Ember.Component.extend(InView,
This works fine. The question I have arises when I want to change the item in view. I can have the in-view mixin observe the inviewItem attribute:
}.on('didInsertElement').observes('inViewItem')
and this also works, but seems like a bit of a code smell.
In addition, my actual code structure is that there is a controller which knows which item is supposed to be in view, and then its template calls a my-item-list component which displays the scrollable div containing the item list, and that in turn calls the my-item component. This means I have to pass the inViewItem attribute from the controller down through two levels, as in
// resource/controller.js
inViewItem: something
// resource/template.js
{{my-item-list items=item inViewItem=inViewItem}}
// components/my-item-list/template.js
{{#each items as |item|}}
{{my-item content=item inViewItem=inViewItem}}
}}
I could avoid this by having the my-item template hard-wired to access the inViewItem attribute on the controller:
scrollIntoView() {
if (this.get('content') === this.get('controller.inViewItem'))
this.get('element').scrollIntoView();
}.on('didInsertElement')
but that's another code smell; I don't want to build this kind of dependency on a specific controller field into the mixin. Instead I could possibly pass the component the name of the controller attribute to watch, but this seems unduly clumsy, and it's tricky to observe an attribute whose name is variable. More importantly, I don't think this will work when controllers go away in 2.0.
What I want essentially is a way to "ping" or somehow send a message to a template. I know that in principle this violates the DDAU principle, but in this particular case what I need is exactly to somehow send an "action down"--an action telling the component to adjust itself to bring itself into view.
Of course, I could give up on the entire idea of the in-view mixin and simply have the controller dig down into the generated HTML to find the item to bring into view and issue the scrollIntoView on it directly. However, this seems to violate some principle of separation of concerns; the my-item template would no longer be in complete control of itself.
What is the recommended design pattern for this kind of case?
The solution here is to go the opposite direction that you have. Your component here is a localized scope, and the pain you are feeling is that your localized scope needs to access and mutate global state (the app's scroll position).
Some people use a scroll-service for keeping track of and mutating state, I've used several variations on that myself.
It sounds though like you're dealing with a scrollable list, perhaps a div, and that what item is in view isn't merely a function of page state, but programmatically may change. For instance, a new item has been inserted and you want to scroll the new item into view.
A plugin like jquery.scrollTo or similar (collectively "scroller") would be better for that than simply jumping to the new position as it preserves the user's contextual awareness to where they are on page.
With a scrollable div or list or similar, you might choose to have your top level component control scroll state. The scroll state is still localized in this case, but instead of being localized to each item it's been localized to the scrollable region as a whole, which is where it better belongs.
There are a number of patterns for list items to register themselves with a parent list-component. In a robust scenario, I might do so, but a quick and not very dirty approach is to do something wherein on didInsertElement the new child emits an action to the parent containing it's context, which the parent then uses to check if it's the active item and if so triggers the scrollTo.

Ember select element - unable to capture on change event

Ember question - still getting used to Ember, but making progress. Here's my issue: I have a template which references a component; the component contains a select element. The select element displays properly, and I want to update the contents of another select element based on the selection in the first element. However, I have not been able to capture the on change event of the first select element. Here is the component code containing the select:
{{view
"select"
content=types
value=selectedtType
selection=selectedtType
prompt="Select Type..."
}}
So I'm not sure how to reference the on change event in the component template, or where the function itself should go - the component's component.js file, or in the route.js file of the parent template. I've done much research on this, but haven't been able to make it work yet. Any help would be appreciated. Thanks.
Check this JSBin. In this example, I had my dependent select use a computed property as its content. This computed property's single dependent key is the value of the first select. If you are doing this with components, your component needs to take the computed property as the attribute that is the select views' content. Any time the first select changes, it will cause the computed property to recompute and thus update the content of the second select. Even in an example using components, this code would probably sit on the controller to keep your component generic enough that it simply takes a content for its select and displays it rather than controlling the display logic itself.
Other options, have a function that observes the first select value and updates a controller variable that is the second select's content. Now if you're example is more complicated in that the changing select's have different option.valuePath and option.labelPath, you can pass pass those values into your component as well.

How is Ember handling this controller .property()

I am displaying a list of Document titles on the site's sidebar area. To achieve this I created a documents property on the App.SidebarController
Document = require '../models/document'
SidebarController = Ember.Controller.extend
documents: (->
Document.find()
).property()
module.exports = SidebarController
This works fine, when I create a new Document in my application, this sidebar property get's updated automatically and I don't know why. It works no matter what I put in the .property() function. e.g.
.property('Document')
.property('App.Document')
Can somebody explain how this works? What would be the correct thing for the property() function to observe?
So you are basically saying that is works, but you would like to know why.
Here is my guess: When your controller gets rendered, your computed property gets computed for the first time and an instance of an array is returned. When you create a new Document, i think this very same array is updated (= Document is added). So it does work despite the fact, that you do not specify a dependent key on property(). This is because the right array is already in place. As i said just a guess, but this seems like an understandable explanation.
And what would be the correct thing to do?
IMHO one should not use such Data Access methods directly in a computed property. Instead you should call this Data Access method inside a Route and then assign it to the controller. This way you make sure, that the find() method gets executed when needed.

Emberjs Handlebars #each helper slow when bound to computed properties

I'm running into a performance issue when I render a list of items using the #each helper or a collection view bound to some computed properties of an Ember.ArrayController. Performance is fine with a small list of 10 - 20 items, but around 50 - 100 it starts to lag quite noticeably. Try checking off a few todos or clicking "Add Todo"
Example code is here: http://jsfiddle.net/Jonesy/ed3ZS/4/
I noticed that the childViews in the DOM get re-rendered with each change, which could very well be the intended behaviour at the moment, but I'd prefer to be able to just have a todo be removed from the DOM of unfinished todos list individually and appended to the bottom of the finished todos list, which would in theory be much less costly.
What I'm hoping to have answered is whether am I looking at a performance issue with Ember collection views, or is displaying a list populated from a computed property a bad idea, and if so, will I need to manually manage the todo model's location in the view layer as it changes from unfinished to finished and vice versa.
This is a side-effect of how {{#each}} (and CollectionView, which is what powers it) works.
Internally, CollectionView uses something called array observers. An array observer allows you to subscribe to mutations made to an array when they are done using Ember.Array's mutation methods (replace, pushObject, popObject, etc.) The API for array observers is described here.
What this means is that, if you push a new object into a collection view, it will insert render one new element in the DOM and leave the rest in place.
In the example you posted, however, the array is not being mutated--you're creating a brand new Array object every time a new item is added or removed. When the binding synchronizes, it replaces the old array with the new array. To {{#each}}, this is no different than removing all of the elements and then adding them back in.
The solution to the problem is to use a single array, instead of a computed property that returns a different array object each time it changes. You can see the Contacts app for an example of how to do this.
Obviously this is a very common pattern, and we'd like to add some kind of filtering that does the right thing by default to Ember.ArrayController down the road.