How to create a link-to drop-down in Ember.js - ember.js

I have an application where we'd like to use a <select> element to control which object is loaded in a detail route.
If this were a normal <ul>, like if I were using bootstrap's drop-down, using the #link-to helper would be perfect here, because I could use the active class to always automatically select the item that is loaded in the child route.
With a select element it's a little different. I'll probably need to write a view, I'm okay with that, but it occurs to me that parents aren't supposed to know about their children in ember, so how does a parent view get access to know which child view is currently selected?
Even a link to how the link-to helper is implemented could be helpful here.
Thanks!

If I'm interpreting this correctly, you're looking to change the URL when the <select> option changes.
With a combination of transitionToRoute, observes, and currentPath you can achieve this using the built in Ember.Select view class.
Here's a JSbin that might help:
http://emberjs.jsbin.com/jogadudase/2/edit

parents aren't supposed to know about their children in ember
Where does this come from?
I'm not 100% sure of what you want to accomplish, but you probably want to use one of this: Ember.ArrayController or Ember.CollectionView.
With either of those you can have control over children objects.

Related

Access the instance of the component from parent component in EmberJS

I have a "container" component
# components/container-component.js
import Ember from 'ember';
export default Ember.Component.extend({
displayComponent: 'simple-box'
});
The template is
# templates/container-component.hbs
<div>
{{component displayComponent}}
</div>
Now, from within "container-component" instance. How can I access the computed "displayComponent" instance?
Any ideas on how I could go about it?
When I use the get method I get the string identification of the component
this.get('displayComponent')
# returns (String) 'simple-box'
There is not a built-in way of retrieving children components from the parent component's js file as far as I know. If you really want to achieve this, please refer to my twiddle I have prepared for you.
As you can see from the code; within the template parent passes itself to the child and child registers itself to the parent. Note that this is an illustration of code smell and this is something I never use in my projects.
Because, in my opinion what you are trying to achieve is a clear violation of many principles that ember is built upon. Why do you want to get the child property from the parent directly? You can register actions to child component and get notified for various events within the child component. Why do you need direct access? It is better for a component to be working independently by itself. In this kind of approach you are polluting parent's code with child component's internal design considerations. You can query DOM tree via jquery within parent but getting the child component instance created for you by Ember infrastructure is a sign that you are trying to design something that is out of Ember's approach. We can help you better if you post another question (or modify this one) to describe your intention. May be someone could lead you to a better design. 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.

How do I structure an Ember.js app so I can access application state from itemControllers?

I have a collection of models, each of which stores a bit of application-persistent state on the controller. I want to access this state elsewhere in the app, but I'm not sure exactly how.
Here's a JS Bin with a stripped-down version of the app which demonstrates what I'm trying to do: On the "Boxes" route, I want to display a count of the number of clicked widgets, but from BoxController I don't know how to get access to the WidgetControllers that have that property.
If I understand the guides correctly, I should be able to use needs to inject one controller into another, but this doesn't really apply when I'm using itemController to wrap each model in its own controller instance.
I would break it up into 3 parts...
1) Add a computed property to the App.WidgetsController the contains the checked widgets. Something like
clickedWidgets: Ember.computed.filterBy('#this', 'hasBeenClicked', true)
2) Add needs: ['widgets'] to the App.BoxController
3) Change the clickedWidgets computed property of the App.BoxController to get the list of clickedWidgets from the App.WidgetsController and the filter that list by widgets which match the box.
clickedWidgets: function() {
return this.get('controllers.widgets.clickedWidgets')
.filterBy('box', this.get('model')).length;
}.property('controllers.widgets.clickedWidgets.[]')
You can see a working bin here: http://jsbin.com/yizafe/1/edit
This should work for you, yes needs:['widgets'] is way to go: http://jsbin.com/tunuj/1/edit?html,js,output

Difference between Ember.CollectionView and Ember.ContainerView

I've gone through the source code comments and the emberjs api but I don't really feel as though I've gotten a very clear idea at the differences between the two types of Ember.View. If anyone could delineate the situations where one might use Ember.ContainerView as opposed to Ember.CollectionView, and vice versa, I would be very grateful. Thanks!
CollectionView = the same child view over and over
This useful when you want to have a view object for every element in an array. For example, if have a list of posts and want to show a PostSummary view for each of them. A typical ember application will get this done by using the handlebars {{each}} helper, which has been implemented using CollectionView.
ContainerView = different child views
Ember.ContainerView when you need to manage an arbitrary list of child views programmatically. CollectionView extends ContainerView. As an alternative you can use handlebars helpers to insert child templates using conditionals around {{view}} helpers instead.

Ember.Select not binding data in IE8

is there possibly any reason why Ember.Select would bind in firefox/chrome/IE9 but it won't work in IE8?
i'm not able to reproduce this in a jsfiddle. but in my app, this is happening. i have a few nested views and the drop down is in the inner most layer. i verified that the data is there. the markup for the tags just won't render.
it works when i moved the dropdown up one level to the parent view.
i have another view that render a list of radio options and it's like that as well.
{{#each content}}<input type="radio">{{text}}</input>{{/each}}
(doesn't work in inner most view but works one level up in parent)
i really can't think of anything that would cause it.
any help would be appreciated. thanks!
i couldn't figure out why this is happening. my solution was to insert the options manually on didInsertElement.