Ember-Cli refactoring to use pods - ember.js

I have just started to refactor our Ember application to use Pods so that our directory/file structure is more manageable. At the same time i have upgraded Ember-Cli so I am running with the following configuration:
Ember : 1.8.1
Ember Data : 1.0.0-beta.12
Handlebars : 1.3.0
jQuery : 1.11.2
I have updated the the environment.js to include the following
modulePrefix: 'emberjs',
podModulePrefix: 'emberjs/pods',
I have also tried to set it to 'app/pods' and just 'pods' but with no luck.
The directory structure is as follows:
emberjs/
app/
controllers - original location, still has some original controllers here for other parts of the system
pods/
job/
parts/
index/
controller.js
route.js
template.hbs
edit/
controller.js
route.js
template.hbs
The application build ok and if i look in the emberjs.js file i can see the various defines for the pods controllers, routes and templates
e.g.
define('emberjs/pods/job/parts/index/controller', ['exports', 'ember'], function (exports, Ember) {
define('emberjs/pods/job/parts/index/route', ['exports', 'ember'], function (exports, Ember) {
define('emberjs/pods/job/parts/index/template', ['exports', 'ember'], function (exports, Ember) {
so something is recognising the pods structure.
But the problem comes when I try to access this route. I get a warning message in the console and get nothing displayed - basically it says it can find the template abd it looks like it is using an generated controller.
generated -> controller:parts Object {fullName: "controller:parts"}
vendor-ver-1423651170000.js:28585 Could not find "parts" template or view. Nothing will be rendered Object {fullName: "template:parts"}
vendor-ver-1423651170000.js:28585 generated -> controller:parts.index Object {fullName: "controller:parts.index"}
vendor-ver-1423651170000.js:28585 Could not find "parts.index" template or view. Nothing will be rendered Object {fullName: "template:parts.index"}
vendor-ver-1423651170000.js:28585 Transitioned into 'jobs.job.parts.index'
If I look in the Ember inspector in Chrome I see that in the Routes section it shows parts/index to have route of parts/index controller as parts/index and template as parts/index.
Is this what I should expect?
I am not sure how Ember resolves the various parts when using pods.
To test this out I put a copy of the template in the templates/parts directory and reloaded it. This time it found the template and rendered it but lacking the data - probably due ti it using the default route and controller.
Does anyone any idea what I am doing wrong. have I missed out a step somewhere, or configured it incorrectly?

Try removing old routes/controllers/templates when adding new ones. Don't keep two copies.
Also it could be unrelated to your files structure. Try creating a blank app and copying files one by one, to see when the issue starts to happen. Use generators and then overwrite the generated files with yours if possible.

Related

Ember link-to gets active class for the wrong transition

This is one of those Ember issues that I'm unable to replicate anywhere but my project. The visual effect of the problem is that the active class on a link-to is one transition behind. I'll click a link and the link that goes to the page I was just on is highlighted with the active class.
I've started digging into the link-to component code to figure out how active is computed. But it is based on _routing.currentState and I'm not sure what that is. The currentState, and other bits of info, are passed to the routing's isActiveForRoute which then calls the routerState's isActiveIntent. And that function calls another isActiveIntent and compares some more things together. All this seems like a large easter egg hunt for something (the root of my problem) that is probably not in Ember's code anyways.
I feel like the following snippet sums up the problem I'm having. The targetRouteName is the route that is being directed to by the link. _routing.currentRouteName seems to be pointing to the route the browser is currently looking at. The fact these match makes me feel like the link should be active, but the active function returns false.
> link.get('targetRouteName')
"parentRoute.pageA.index”
> link.get('_routing.currentRouteName')
"parentRoute.pageA.index”
> link.get('active')
false
For reference this is after finding the link via the Chrome extension and showing all components. I then did link = $E.
For the wrong link (the one that does get the active class) I get:
> link.get('targetRouteName')
"parentRoute.pageB.index"
> link.get('_routing.currentRouteName')
"parentRoute.pageA.index"
> link.get('active')
"active"
Additional Raw Information
The routes I'm dealing with are nested. But it is a pretty standard nesting, very much like the one I have in my ember-twiddle (e.g. page-a, page-b, page-c).
There is a model hook on the parent route and on the indexs of the children routes. But the children routes reference (this.modelFor(...)) the parent.
My template is referencing the .index of those routes. They are standard link-to components. They do not include model information.
I'm running Ember-cli 1.13.8, Ember 2.0.0, and Ember Data 2.0.0-beta.1.
What I have tried so far
Upgrading to 1.13.0
Moving the file structure to pods
Removing the functions in my authentication route which a lot of these routes inherit from.
Upgrading to 2.0.0
Trying to remove/add .index on my routes
Tried replicating on ember-twiddle
Doing ember init with ember-cli to see if my router or application setup was different from the standard layout and it doesn't differ in any significant way.
Adding model information to one of the links, that didn't change anything and since it didn't call the model hooks it messed up the view.
Asked on the slack channel
Please Help
I've had this issue for a couple weeks now and I'm not sure where else to look. I'd love any suggestions on how I can resolve this.
Update
This ended up getting fixed in 2.1.0.
This is common problem when you mess around with willTransition router action. For example,
IMS.ResultDetailsEditRoute = Ember.Route.extend({
actions: {
willTransition: function() {
this.controller.clearForm();
}
}
});
In this code snipped willTransition called controller's method "clearForm()" which no longer exists. For some reason, Ember doesn't throw an error, but it causes the problem that #RyanJM explained.
I have run into something similar when using a component with a nav. Here was my approach:
I added a controller (I know, you should be steering away form these, but I needed to). My controller:
import Ember from 'ember';
const {
Controller,
inject
} = Ember;
export default Controller.extend({
application: inject.controller(),
});
Then, in my template, I could pass application to my component.
{{account/account-icon-nav currentRouteName=application.currentRouteName}}
In my component, I set set up a function to test my current route names:
import Ember from 'ember';
const {
Component,
computed,
get
} = Ember;
const activeParentRoute = function(dependentKey, parentRouteName) {
return computed(dependentKey, {
get() {
return get(this, dependentKey).indexOf(parentRouteName) > -1;
}
});
};
export default Component.extend({
isYourProfile: activeParentRoute('currentRouteName', 'account.your-profile'),
isYourActivity: activeParentRoute('currentRouteName', 'account.your-activity'),
isYourGoals: activeParentRoute('currentRouteName', 'account.your-goals')
});
Then bind the active class yourself:
<div class="icon-nav md-hidden">
{{link-to "" "account.your-profile" classBinding=":profile isYourProfile:active" title="Your Life"}}
{{link-to "" "account.your-activity" classBinding=":activity isYourActivity:active" title="Your Money"}}
{{link-to "" "account.your-goals" classBinding=":goals isYourGoals:active" title="Your Goals"}}
</div>
I know this is a bit different since we are doing it within a component, but I hope it helps. You can bind these classes yourself by passing the application around.

ember-cli / pod: Nesting resources/templates

I have read various stackoverflow threads and other forum entries, but I am not able to figure out how to get nested resources/templates working using ember-cli 0.1.12 and pod structure.
Versions:
Ember : 1.8.1 (also tried 1.9.1)
Ember Data : 1.0.0-beta.12
Handlebars : 1.3.0 (also tried 2.0.0)
jQuery : 1.11.2
My router.js (unchanged, cli created it, only demo purposes):
Router.map(function() {
this.resource("controls", function() {
this.route("statements");
this.resource("handles", function() {});
});
Situation:
No additional modifications besides ember generate commands and text markers in the created template.hbs
Resource "controls": template is displayed as expected
Route "controls/statements": template is displayed as expected
Resource "handles" under resource "controls" is not rendered at at all.
Subsequent routes unter "controls/handles" are also not working.
When I invoke http://localhost:4200/controls/handles, ember inspector only list "application" and "controls" in the view tree. In the ember inspector routes section, it lists: handles.index
HandlesIndexRoute Send to console
HandlesIndexController Send to console
handles/index
/controls/handles
I tried:
Switching ember and handlebar versions - no effect
Not using pod structure - no effect
Manually adding an index.hbs template in the handles pod folder - no effect
I have the feeling that I am missing a basic point here.
Could you please help me out?
Thank you,
Manuel
I can't help on the pod issue but can try on the other point.
What is the nature of your nested resource?
I would be expecting URLs like: "..controls/:control_id/handles".
I would have written this like this:
this.resource('controls', function() {
this.route('statements');
this.route('show', { path: ':control_id' }, function() {
this.resource('handles', function() {
});
});
});
Nick

Ember App Kit: Controller without Route is not recognized?

as I mentioned in several questions here I am migrating an already existing and running Ember project to use Ember App Kit and I ran into several problems... here's another "problem" which wasn't a problem before :)
I've got a NotificationCollectionController which is placed under app/controllers/notification/collection.js.
file 'app/controllers/notification/collection.js':
export default Ember.ArrayController.extend({
addNotification: function (options) {
// some code
},
notifyOnDOMRemove: function (notification) {
this.removeObject(notification);
}
});
As this is the controller for notifications which are rendered through a named outlet I didn't declare a route for it.
Within my ApplicationRoute I want to access this controller within a function
file: 'app/routes/application.js'
import BaseRoute from 'appkit/routes/base';
export default BaseRoute.extend({
addGlobalNotificationCollection: function () {
var controller = this.controllerFor('notificationCollection');
// some more code...
}
});
But as soon as the application starts and this piece of code gets called I traced down the following error:
"Assertion Failed: The controller named 'notificationCollection' could
not be found. Make sure that this route exists and has already been
entered at least once. If you are accessing a controller not
associated with a route, make sure the controller class is explicitly
defined."
What does it mean and why is it thrown? What do I have to do to make it run again?
I didn't recognize that the hint is already given at the Naming Conventions section of the Ember App Kit Webpage:
It says, that the naming convention for a Controller is, for example: stop-watch.js
And if it’s a route controller, we can declare nested/child controllers like such:
app/controllers/test/index.js
So I placed my NotifcationCollectionController in controllers/notification-collection.js and call it like Route#controllerFor('notification-collection') and everything works as expected :)

Emberjs and Typescript SetUp

I'm having the hardest time getting typescript and ember to work together. I got all the definition files in definitely typed and I went through the ToDo walk throughs on Ember guide on the site. I'm trying to convert the js to typescript and see what the best way to go about setting up the project was, but I guess I'm not understanding the typescript definition very well.
If I do:
/// <reference path="typings/ember.d.ts" />
var App = Ember.Application.create();
App is a type of '{}' and I can't access 'Routers' to do the next line of the guide
App.Router.map( ... )
The best thing I found online was this which doesn't work with the current typing.
I've seen the typescript ember-app-kit but it doesn't really help since it barely includes any typescript and their setup is barely like the ember guides. I just need to be pointed in the right direction. Thanks guys.
I'm not familiar with Ember, but from inspecting ember.d.ts, I can see that create() is defined as a static generic function on object:
static create<T extends {}>(arguments?: {}): T;
So then you should be able to get better type information by passing an actual type:
var App = Ember.Application.create<Ember.Application>();
However, I see also that the ember typedef doesn't include a "Router" member in the application class, and even if it did, the Router class does not define map(). I was able to get it to work by creating an extended type definition:
// ./EmberExt.d.ts
/// <reference path="typedef/ember/ember.d.ts" />
declare class RouterExt extends Ember.Router {
map: ItemIndexEnumerableCallbackTarget;
}
declare class ApplicationExt extends Ember.Application {
Router: RouterExt;
}
And then referencing that from my combined router/application file:
/// <reference path="typedef/ember/ember.d.ts" />
/// <reference path="./EmberExt.d.ts" />
var App = Ember.Application.create<ApplicationExt>();
App.Router.map(function () {
this.resource('todos', { path: '/' });
});
After doing this, it compiles and loads without error, though it doesn't actually do anything (which I believe is ok for this phase of the walkthrough)
Full and mostly-accurate type definitions for Ember.js are now available to install from npm at #types/ember, #types/ember-data, and so on, currently all via the Definitely Typed project.
Ember CLI integration is available through the ember-cli-typescript addon. The easieset way to configure a Ember.js project with TypeScript is to run ember install ember-cli-typescript in the root of your Ember.js project. Doing so will automatically generate a tsconfig.json which handles Ember’s conventional project layout correctly (for apps, addons, and in-repo addons). It will also install the type definitions for all the core Ember projects automatically.

Why does this Ember.js app work locally but not on jsFiddle.net?

Here's the fiddle. Here's the gist with the contents of my local file.
As you can see, the HTML and JavaScript are identical, and I'm loading identical versions of the jQuery, Handlebars.js, and Ember.js libraries. It works as expected locally, but does not render the application template on jsFiddle.net.
I see the following error in the Web Console:
[19:44:18.202] Error: assertion failed: You must pass at least an object and event name to Ember.addListener # https://github.com/downloads/emberjs/ember.js/ember-latest.js:51
BTW-To test the gist as a local HTML file, make sure to run it behind a web server or your browser won't download the JavaScript libs. If you have thin installed (ruby webserver), go to the directory it's in and run thin -A file start, then navigate to localhost:3000/jsfiddle-problem.html in your browser.
If you set the "Code Wrap" configuration on your fiddle to one of the options other than "onLoad" your application will work. Here is an example.
The reason for this is Ember initializes an application when the jQuery ready event fires (assuming you have not set Ember.Application.autoinit to false). With the jsFiddle "Code Wrap" configuration set to "onLoad" your application is introduced to the document after the jQuery ready event has fired, and consequently after Ember auto-initializes.
See the snippet below from ember-latest, taken on the day of this writing, which documents Ember auto-initialization being performed in a handler function passed to $().ready.
if (this.autoinit) {
var self = this;
this.$().ready(function() {
if (self.isDestroyed || self.isInitialized) return;
self.initialize();
});
}
This was strange - I couldn't get your fiddle working, specifically your {{controller.foo}} call until I disabled autoinit. I am guessing when using jsfiddle the application initialize kicks off before seeing your router. I also noticed with your fiddle the router was not logging any output even when you had enableLogging set to true.
I updated your fiddle to not use autoinit, http://jsfiddle.net/zS5uu/4/. I know a new version of ember-latest was released today, I wonder if anything about initialization changed.