Cant figure out views rendering (they are prepended right before /body) - ember.js

First my apologies: Im very new to ember.js and struggling so far.
I have a pretty basic app written and I've been using this as my main guide: http://trek.github.com/
My biggest issue right now is figuring out how to deal with Views, specifically the rendered HTML and where it appears in the DOM. It appears, at least with my app currently, the DOM elements are created and inserted into the page but right before /body. So everything just loads below the footer of my main site design.
Doesnt seem to matter where placement of the script templates are in relation to the page, or anything like that??
Is there a way to render views to an existing container div or something? Am I thinking about this wrong? Im used to working with jsRender where I have templates setup, but they typically rendered to an in-memory string that I then needed to insert into an existing container like $('#containerDiv').html(myRenderedHtmlFromATemplate);
Thanks for any help or guidance with this!

Ember will want its views to be hierarchical in the DOM so it can rely on event propagation. You probably noticed a <div class="ember-application"> that gets injected, and then all of your views are rendered inside of that.
You can specify the rootElement when you create your Application. The application will be created inside that element and leave the rest of the DOM untouched. If you don't specify that rootElement, then Ember will insert itself right before </body> as you observed.
Example:
window.MyApp = Ember.Application.create({
rootElement: "#containerDiv"
});

Without seeing code it isn't completely clear what exactly is going on, but, I do not see you mention anything about outlets so I assume that might be your problem.
Check out this url on outlets: http://emberjs.com/guides/outlets/

tuxedo25 has the best solution. If you are using StateManager you can also use the following:
App.StateManager = Ember.StateManager.create({
rootElement: '.content',
initialState: 'initial',
initial: Ember.ViewState.create({
route: 'initial',
view: Ember.View.create({ templateName: 'initial' })
})
});

Related

Ember router breaks on redirect to '/'

I'm having a hard time making my router understand that we are on a certain page and it should be displayed in the navigation as active. The situation is as follows:
this.route('mainRoute', function() {
this.route('list');
});
The path we are interested in is /mainRoute. Unfortunately, there are a lot of legacy links that point to /mainRoute/list. The workaround for this was to redirect from the /mainRoute/list component back to the /mainRoute component.
beforeModel() {
this.replaceWith('/mainRoute');
}
Now, my issue is that the /mainRoute navigation link will never be seen as active. I've tried adding a path for the /mainRoute ('/', '/mainRoute', 'mainRoute'), I've tried transforming it to a resource and a bunch of other things that passed my mind. But it either won't work, or will go in an infinite redirecting loop.
Any thoughts on it? Thanks so much, I really need a solution for this!
If the navigation links are {{link-to}} components. There is a current-when property you could use here. It accepts either a boolean or a string. The string is a space separated values with the route names you want this link to be active when.
From the docs
If you need a link to be 'active' even when it doesn't match the current route, you can use the
current-when argument.
<LinkTo #route='photoGallery' #current-when='photos'>
Photo Gallery
</LinkTo>
{{#link-to 'photoGallery' current-when='photos'}}
Photo Gallery
{{/link-to}}

Recommended way to rerender page in Ember after language switch

I need to rerender whole page application after language has switched. I don't like to use observers for it because of performance issues.
Language switch is done by a Ember.View. I tried to rerender parentView after changing Ember.I18n.translations but running into a known bug. It works one time but Ember Inspector shows parentView has dutzend of children views of it's own afterwards. After another switch parentView got destroyed. Just like demonstrated in this JSFiddle.
Here is simplified code of my view:
export default Ember.View.extend({
templateName: 'language-switch',
languageChanged: function() {
// change language
var language = this.get('controller.language.selected');
Ember.I18n.translations = translations[language];
// rerender page
this.get('parentView').rerender();
}.observes('controller.language.selected')
});
There is also a discussion about that problem on discuss.emberjs.com. I tried the suggestions there but they don't work. Last post suggest a work-a-round to map over all views, rerender them and afterwards use a transition. I don't like that one since I am afraid getting side problems by that hack.
I am pretty sure there must be a way to do a language switch in Ember with ember-i18n but what's the right way to do that?
Update:
I tried to implement the hack from discuss.emberjs.com. It's working but it's very limited. I implement it like this in the view:
var self = this;
var currentRoute = self.get('controller.currentRouteName');
this.get('controller.target').transitionTo('loading').then(function(){
self.get('controller.target').transitionTo(currentRoute);
});
Problem is that all data stored in model is lost. I did not find a way to get the current model and use it in transition. Also query parameters are lost. That limitation makes this work-a-round unacceptable for my application.
Update App.reset():
As suggested in comment I tried to use App.reset(). It works better than transitionTo work-a-round but doesn't match all needs. If calling App.reset() queryParams aren't lost but model is reseted. I'm looking for a way to rerender application while keeping current model and queryParams.
It seems that mostly these problem is handled by a full page reload on locale change. E.q. one of the main developers of ember-i18n said so in this discussion.

How to prevent views from being destroyed in Ember.js

Quick note:
I don't believe this is a duplicate of Ember.js: Prevent destroying of views. Other related questions that I've found are out-of-date.
In case this becomes out-of-date later, I am using Ember 1.7.0 with Handlebars 1.3.0.
Context for the question:
As the title states, I am wondering how to transition between views without destroying them. Using queryParams does not solve my issue.
I am creating a calculator with the following nested views:
>>Calculator View
>>Report View (hasMany relationship to Calculator)
--School Partial (I am using queryParams here)
I am able to navigate between the Report views just fine without destroying my School partial, since I am using queryParams and using a displaySchoolPartial boolean to show/hide the partial. Example below:
Report template (stripped to only show the essential part):
<script type="text/x-handlebars" data-template-name="calculator/report">
...
{{#link-to "calculator.report" (query-parameters displaySchoolPartial="true")}}
{{render "_school"}}
</script>
School template (also stripped down):
<script type="text/x-handlebars" data-template-name="_school">
{{#with controllers.calculatorReport}}
<div {{bind-attr class=":schoolPartialWrapper displaySchoolPartial::hide-element"}}>
...
</div>
{{/with}}
</script>
This works as expected. Navigating between different Report views and School partials, as stated before, does not destroy the view.
The problem:
My problem comes when navigating to the Calculator view, the Report view is destroyed, which then destroys my School view. I do not want to also use queryParams to replace my Report views.
The reason I need to make sure the views aren't destroyed is because I have a select box with 3,000 schools in my School partial. It takes too long to re-render this. It would be a much better UX to simply show/hide the Report views.
Don't fight with Ember. You will lose.
Views are instantiated and rendered when needed and torn down when done.
Why do you have a 3000-element dropdown, anyway?
If you really, really want to do this, what I would suggest is putting a {{render}} on your application page, and hide it. The view will be created and rendered when the app comes up and persist as long as the app is alive. Then, in the didInsertElement of your view, do a cloneNode of that hidden element and insert it into the view's DOM somewhere. You may have to muck around getting event handlers wired up correctly.
My suggestion is not using "render" but using "partial", so you only need to drop in the template that you want. Have a control variable that set show/hide via css class. And control that variable using you controllers.
Using "partial" will allow you to have school template independent from report, thereby removing report will not affect school.
Just make sure you define the outlet and partial correctly.
Hope it helps!

Rerender view after change route's dynamic segment

I have a Route with dynamic segment :id. When I change only the dynamic segement part manually in browser url input field, then goes a transition, and all model hooks are called as expected.
The problem is: none of the views are rerendered. I guess it is because only model changed - not the UI. But I have some UI logic in views' didInsertElement handler - reinitialize UI plugins and so on.
How to force ember to rerender view after dynamic segment change?
I agree with the josh's comment. if you are rerendering views with the change of dynamic segment means your code is not written properly. But still if you want to go like that i am gonna give is a part of code.
In your route:
model: function(params){
model.set('id', params.id);
}
In your view which needs to be rerendered:
_modelIdChange: function(){
this.rerender();
}.observes('controller.model.id')
But i don't suggest this. I would rather prefer proper bindings. But i did use rerendering in some cases which mostly when you end up using jquery plugins.

use results from ember data findQuery as ArrayController contentBinding

I'm trying to write my first "real" ember app. I've gone through a couple tutorials and I'm now attempting to use ember in conjunction with Ember Data to fetch data from a Rails app and display it.
I've gotten it to fetch the data, parse it, and display it, although I'm not convinced it's in the best way possible. I have an App.itemsController that is similar to this:
App.itemsController = Em.ArrayController.create({
content: App.store.findQuery(App.Item, {visible: true}),
});
I also have an App.ItemIndexView, whose template looks like
{{#each App.itemsController}}
{{id}}{{view App.ItemView item=this}}
{{/each}}
I have a couple of questions about this.
First and foremost, I want to allow a user to change an items visibility to false. I have this code in the App.ItemView file:
acknowledge: function() {
this.item.set('visible', false);
App.store.commit();
}
the record gets updated, however I want that entire item to drop from the view and it doesn't. How do I make this record be removed from App.itemsController.content?
My second question, which may in fact also answer the first, am I completely off in the boondocks as far as my implementation of this? I feel like there should be a way for me to set something like contentBinding: 'App.store.findQuery(App.Item, {visible: true})' and have non-visible ones be removed but I've tried that and nothing shows up. So I'm wondering if something in the way I have my whole app setup is flawed and keeping things from playing nice.
You can use the filter function instead of findQuery:
content: App.store.filter(App.Item, function (item) {
return item.get('visible');
})
The result will be re-evaluated when underlying data change. You still have to get data from the server via find/findAll/findQuery though.