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 :)
Related
EmberJS 3.4
I'm loading a Project entity from a backend which takes a couple of seconds. Now I would like to show a spinner during loading.
as described I created a project-loading.hbs (also tried with loading.hbs) https://guides.emberjs.com/release/routing/loading-and-error-substates/
project model class:
export default AuthenticatedRoute.extend({
model(params) {
return this.store.findRecord("project", params.projectname);
},
actions: {
refresh: function() {
this.refresh();
}
}
});
though it takes time to load the entity, the loading template seems not to be rendered/shown. Am I doing something wrong ?
For a route called project (routes/project.js), the loading template should be called project-loading.hbs.
I cloned your project and actually made it work (Ember CLI 3.4.3) by adding templates/project-loading.hbs, adding a sleep(30) call to your /api/projects/:name endpoint and going to a URL like http://localhost:4200/projects/hallo.
Do you have the problem when transitioning to the route internally (by using transitionTo or the {{link-to}} helper with a model for instance) or by entering the URL manually? Note that model hook is not executed when you transition to a route and pass in a model context (see https://guides.emberjs.com/v3.4.0/routing/specifying-a-routes-model/).
I ended up with adding the following code to the application adapter:
// not very ember way of doing this, but quite simple :)
$(document).ajaxStart(() => {
$('#spinner').removeClass('hide');
});
$(document).ajaxStop(() => {
$('#spinner').addClass('hide');
});
I really would prefer doing it the ember way. for now, this seems to do the trick.
for anyone interested, here's the complete project: https://github.com/puzzle/mailbox-watcher/tree/master/frontend
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.
I'm very new to EmberJS 2.0 and trying to slowly understand it by building my own website with it. Anyways, I've managed to get Firebase integrated with Ember and my controller is able to authenticate correctly. However, I'd like to understand why when I execute:
this.send('toggleModal');
inside the authenticate action property function (.then()) it doesn't work but if I execute it outside then everything works fine.
1) Is the 'this' keyword getting confused with something other than the Ember controller?
Here is the sample:
// /app/controllers/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
isShowingModal: false,
actions: {
toggleModal: function() {
this.toggleProperty('isShowingModal');
},
authenticate: function(username, pass) {
this.get('session').open('firebase', {
provider: "password",
email: username,
password: pass
}).then(function (data) {
console.log(data.currentUser);
console.log(session.isAuthenticated); //Why is 'session' not defined?
this.send('toggleModal'); //This doesn't work. Throws an error.
});
this.send('toggleModal'); //This works.
},
logOut: function() {
this.get('session').close();
}
}
});
2) Also, I've noticed that when using Emberfire I'm able to use the property 'session.isAuthenticated' within the template application.hbs however, shouldn't 'session' be an object that is injected to all routes and controllers using Torii? Why is that property inaccessible/undefined within the application.js controller? I'm using https://www.firebase.com/docs/web/libraries/ember/guide.html#section-authentication as a reference.
3) In the guide above the actions for authentication are put inside the route. However, according to this quora post the route should only handle template rendering and model interfacing. Is this post incorrect? The authentication logic should reside in the application.js controller correct? https://www.quora.com/What-is-the-best-way-to-learn-Ember-js
1) Is the 'this' keyword getting confused with something other than the Ember controller?
Yes. This is one of the most common sticking points of Javascript. There's a lot of articles out there about it, but this one looked pretty good. To solve it you'll either need to use an arrow function, bind the function to the current context, or save the context in a local variable. (Read that article first though.)
2) Also, I've noticed that when using Emberfire I'm able to use the property 'session.isAuthenticated' within the template application.hbs however, shouldn't 'session' be an object that is injected to all routes and controllers using Torii? Why is that property inaccessible/undefined within the application.js controller? ...
That's because the template pulls the property from the current context (your controller). Inside of your controller you'll have to use this.get('session') instead. (After you fix the issue I mentioned above.)
3) ... Is this post incorrect? ...
I wouldn't say incorrect, just a bit oversimplified. I would follow whatever conventions the library uses as that's probably the best way given the library's requirements.
You're partially right about this although it's not really confused. this (where you're modal call doesn't work) isn't scoped to the Controller anymore, because it's inside a function. Either:
replace the function (data) call with data => if you're using ember cli. Or
var _self = this; up top and reference _self instead.
This should at least get you started.
To keep it short:
Is it possible to set up the Resolver of the application outside of the Ember.Application.create() block?
Ideally, I would like to set the Resolver in a Ember.Application.initializer#initialize() function. Something like:
import CustomResolver from 'appkit/utils/resolver/custom';
import CustomAjax from 'appkit/utils/ajax/custom';
Ember.Application.initializer({
name: 'resolver_setup',
initialize: function (container, application) {
// NOTE: For an unknown reason (unknown to me!) I can't import CustomAjax in CustomResolver...
application.set('Resolver', CustomResolver.create({ajax: CustomAjax.create({})});
}
});
Is this possible?
P.S.: The reason why I need a custom resolver is, that I'm fetching all templates from the server instead of delivering them to the user on application start. Therefore I'm extending the ember-jj-abrams-resolver which is used by default within EAK...
I don't think initializers can help you to set a custom Resolver, according to the source code, container is been set earlier than any initializers, resolver is a property of container.
You set the Resolver property inside initializer, but this will not be used by the process of set up the container. I think the right way is to reopen the Ember.Application and set the Resolver before create the Ember.Application.
Ember.Application.reopenClass({
Resolver: YOUR_CUSTOM_RESOLVER_NAME
});
Ember.Application.create({...});
I guess I'm missing something really basic, but the following fails with The action 'login' did not exist on App.AppController.
Template:
<h2>Click the button and watch the console</h2>
<button type="button" {{action login target="App.AppController"}}>Log in</button>
Controller:
App.AppController = Ember.Controller.extend({
login: function() {
// never gets here
debugger;
},
send: function() {
// or even here
debugger;
}
});
JSBin: http://jsbin.com/okuqiv/5/edit (this is pointing to Ember latest, but it's the same behavior with 1.0-rc2, the version I've been using for a couple of days; I haven't tried it on previous versions).
Upon debugging, it seems that somehow the controller mixin is not exposing all the functions it should -- login() is a function I added, but send() is an Ember function. It's also missing other functions like get().
I saw that in my app the login() function exists on the object App.AppController.prototype, while in the JSBin it exists on one of the objects in the mixin chain.
At this point I'd even be happy to handle the login action in the view, or the router (as it seems it was the default in the past), but none of those seem to work.
From the documentation, the current default place where the actions handlers should live is the controller anyway, and then the routes, but if I remove the target and add login() to the route, I get another error: Nothing handled the event 'login' (I'm using the target in the first place because in my app /login is a separate route and has a different controller).
Solutions and workaround will be very appreciated!
You are targeting the class App.AppController and not an actual instance of that class. If you are using the router and are in an app view then action would target the appController by default.
I've updated the JSbin to call login on the IndexController since your example is in the index route:
http://jsbin.com/okuqiv/10/
You were also over riding the send method which was preventing login from being called.