Ember's template rendering pipeline - javascript

I have a specific template for both the main app and the public facing pages. Based on the docs the code below is what I thought should work. However I continually get a Cannot read property 'connectOutlet' of undefined error thrown.
router.js
Router.map(function() {
this.route('app');
this.route('login');
});
application.hbs
{{outlet}}
public.hbs
This is the public template
{{outlet}}
app.hbs
This is the app template
{{outlet}}
login.hbs
<input type="email" ...>
<input type="password" ...>
routes/login.js
import Ember from "ember";
export default Ember.Route.extend({
renderTemplate: function() {
this.render('login', { into: 'public' });
}
});
routes/app.js
import Ember from "ember";
export default Ember.Route.extend({
renderTemplate: function() {
this.render('login', { into: 'public' });
}
});
If I remove the {into:..} options no error is thrown but both the login and app templates are rendered into the application template rather then the public and app respectively.
Am I totally misunderstanding how Ember handles the rendering?

In the app that I'm doing with ember I also use the renderTemplate hook to render a template into another one, your code there is the same as mine and looks good.
I think the problem might be that there isn't any public route. I think that if you define one in your router, and then try again, it may work. Looks to me like its not able to render the templates into public because public does not exist.

Related

Correcting Invalid Route Naming

I'm currently working on a CRUD application - so far I've created an index route, a show route and create route and have moved on to creating an update method. I've gone ahead and added a route, template and a controller, but whenever I try to click on a link to my new template I receive an error letting me know the following:
This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid.
I'm linking to the update path through the show page and can confirm that the ID I'm passing into the link-to function exists. This being the case, I think that there's something likely wrong with my route name but can't figure out where I'm going wrong. I assume it's likely something wrong with the nested routes.
I've tried altering the order of my routes and have put console log statements in the controller I anticipated hitting once the link-to statement was hit - so far I haven't entered the controller.
app/router.js
import EmberRouter from '#ember/routing/router';
import config from './config/environment';
const Router = EmberRouter.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
this.route('about');
this.route('contact');
this.route('posts', function() {
this.route('post');
this.route('show', { path: '/:post_id' });
this.route('edit', { path: '/:post_id/edit' });
this.route('destroy', {path: ':post_id/destroy'});
});
});
export default Router;
apps/routes/posts/edit.js
import Route from '#ember/routing/route';
export default Route.extend({
model(params) {
console.log('hit this when edit route is hit')
return this.store.findRecord('post', params.post_id);
}
});
app/templates/post/show.hbs
<div class="jumbo show-posts">
...
</div>
{{log this.model.id}}
<div class="col-sm-offset-2 col-sm-10">
<h3>{{#link-to "post.edit" post class=this.model.id}}Update post{{/link-to}}</h3>
</div>
{{outlet}}
...
You have mentioned a wrong route name. It should be posts.edit according to your router.js. You should pass at least one params to the post.edit route.
Have a look at my working ember-twiddle
Since you have mentioned this.route('edit', { path: '/:post_id/edit' }), the route will be expecting at least one of its parameters :post_id is present.
Modify you {{link-to}} as below,
{{#link-to "posts.edit" this.model.id}}Update post{{/link-to}}
You can access the post id in your controller through params.post_id,
model(params) {
console.log('hit this when edit route is hit')
return this.store.findRecord('post', params.post_id);
}

Reading a computed property injected by a service with handlebars in ember.js

I am trying to mutate my handlebars scripts by using a computed isAuthenticated property injected via a custom auth service. In the my-application component, this works with little problem via the following code:
{{#if isAuthenticated}}
<li>{{#link-to "accounts.my-account"}}My Account{{/link-to}}</li>
<li>{{#link-to "accounts.search-accounts"}}Find other Medici Users{{/link-to}}</li>
{{/if}}
import Ember from 'ember';
export default Ember.Component.extend({
auth: Ember.inject.service(),
user: Ember.computed.alias('auth.credentials.email'),
isAuthenticated: Ember.computed.alias('auth.isAuthenticated'),
actions: {
signOut () {
this.sendAction('signOut');
},
},
});
When I try to implement this exact same code in a different location (in this case, the accounts route) as such:
<button type="btn" {{action "test"}}>test</button>
{{#if isAuthenticated}}
<p>test</p>
{{/if}}
{{outlet}}
import Ember from 'ember';
export default Ember.Route.extend({
auth: Ember.inject.service(),
user: Ember.computed.alias('auth.credentials.email'),
isAuthenticated: Ember.computed.alias('auth.isAuthenticated'),
actions: {
test () {
console.log(this.get('user'));
console.log(this.get('isAuthenticated'));
}
}
});
There is no change in the template (though test does appear when you switch the if out with an unless). Making this all the stranger is the fact that, when I click the test button, it successfully fires the result of isAuthenticated. Why am I unable to transfer this property over from my js file to my hbs file?
You need to define the property in a controller; is there a controller for the accounts route? Props on the route (other than model) aren't directly visible to the template.
An alternative would be to create a component which wraps the accounts template; you could inject the auth service in there instead of a controller if you don't want one or want to keep it small.
Note that one thing our team does is automatically inject the auth service (or rather, the equivalent session service) into all components; you can do this with an initializer. That reduces boilerplate somewhat.

Is it possible to inject a controller or another class in an EmberJS Component?

I'm trying to use a method from one controller inside a component but something must be wrong.
I have the route /calendars with its own controller (controllers/calendars.js) and template (templates/calendars.hbs)
Inside calendars.hbs I have implemented a chain of components with templates for the main screen of my app and for the menu. Inside the menu, I have the final component that should call to a calendars' controller method.
Controller:
import Ember from 'ember';
export default Ember.Controller.extend({
actions:{
createCalendar: function(){
console.log("app/controllers/calendars.js");
}
}
});
Route:
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin,{
model: function(params) {
return [
{id:"1", name:"Calendario de trabajo", shared:false, position: 0},
{id:"2", name:"Calendario personal", shared:false, position: 1},
];
},
actions:{
createCalendar: function(calendar){
console.log("app/routes/calendars.js");
}
}
});
Component:
import Ember from 'ember';
export default Ember.Component.extend({
calendars: Ember.inject.controller("calendars");
actions: {
createCalendar: function(){
console.log("app/components/menu/calendar-dock-footer.js");
this.calendars.createCalendar();
}
}
});
Templates:
calendars.hbs
{{#main-template}}
{{#link-to "calendars.new" (query-params posX=150 posY=50)}} Show me the money! {{/link-to}}
{{outlet}}
{{calendars.full-calendar size="calendar" action="createEvent"}}
{{/main-template}}
main-template.hbs (component)
...
{{menu.main-dock}}
...
main-dock.hbs (component)
...
{{menu.calendar-dock-footer}}
...
calendar-dock-footer.hbs (component with button)
<div class="row ht-calendar-footer-content">
<button class="btn btn-sm btn-info" {{action 'createCalendar'}}>
<label> Add Calendar</label>
</button>
</div>
I have tried to pass the action from the calendars.hbs to the component with the button, and it runs but what I need to call the method inside calendars.js from the component with the button.
Use sendAction('createCalendar',params) in your component's controller. Your component's controller doesn't know about the controller in your calendar. It is the action up data down principle that Mirza Memic mentioned in your comments. You can handle the action in your route. If you are familiar with sending queries to a database starting from the component level (from component -> route) it is the same principle.
http://emberjs.com/api/classes/Ember.Component.html#method_sendAction
You cannot inject a controller into a component. When you want to do stuff like that, Ember would prefer that you use a Service to communicate between the two entities.
Or, you can just pass the controller down into the component when you instantiate it in the template. It's a cheat, but it's how I prefer to do it.
my-component controller=this
Also, you can be super ember-y, and utilize sendAction(), and then handle action bubbling in the route.
Pick the way that makes the most sense to you.

dependency injection without singleton in ember-cli

Just converted my app to ember-cli, but I don't know how to use Ember.Application.register any more because register doesn't seem to be available when Application is started with extend rather than create.
import Ember from 'ember';
import App from 'myapp/app';
var AdminMyController = Ember.ObjectController.extend({
});
// THROWS ERROR HERE BECAUSE register isn't, uh...registered?
App.register('controller:adminMyController', AdminMyController, { singleton: false });
export default AdminMyController;
Previously, because App was a global, I could register this right in the same class.
Am I going to have to move all the register calls to an initializer so I can get access to the app instance?
I belive an initializer would do this for you. You'll need to create an initializers folder in your app directory (same level as controllers, templates, etc). This file should go there.
import Ember from 'ember';
var AdminMyController = Ember.ObjectController.extend({
...
});
export default {
name: 'adminMyController',
initialize: function (container, application) {
container.register('controller:adminMyController', AdminMyController, {singleton: false});
}
};

Bootstrap for Ember using Ember CLI; can't get popovers component to work

I'm stuck here...
http://ember-addons.github.io/bootstrap-for-ember/#/show_components/popover shows the documentation on how this is supposed to work...quoted below may be the bit I'm not understanding (it's a little confusing because this all mentions tooltips and not popovers but I'm making a leap that since it's all in the same documentation that it's all related...)
For Popover support, it is required to adapt the application route and
add a named outlet to your main template and reference a controller
that extends from Bootstrap.TooltipBoxController
//Create some controller in your app that references
Bootstrap.TooltipBoxController App.TooltipBoxController = Bootstrap.TooltipBoxController
//Application route App.ApplicationRoute = Ember.Route.extend({
renderTemplate: function() {
// Render default outlet
this.render();
// render extra outlets
var controller = this.controllerFor('tooltip-box');
this.render("bs-tooltip-box", {
outlet: "bs-tooltip-box",
controller: controller,
into: "application" // important when using at root level
});
} });
Ok fine, so in templates/application.hbs I added this bit:
{{outlet bs-tooltip-box}}
Then, at routes/application.js I added what it said:
renderTemplate: function() {
// Render default outlet
this.render();
// render extra outlets
var controller = this.controllerFor('tooltip-box');
this.render("bs-tooltip-box", {
outlet: "bs-tooltip-box",
controller: controller,
into: "application" // important when using at root level
});
},
Predictably, upon rebuilding, I get an error that controller named 'tooltip-box' doesn't exist. So I create one:
ember g controller tooltip-box
Ok, great, now it doesn't puke on that part.
Now here's were things go sideways for me... I'm trying to do this bit:
//Create some controller in your app that references _Bootstrap.TooltipBoxController_
App.TooltipBoxController = Bootstrap.TooltipBoxController
So my assumption is that instead of the generated blueprint of:
import Ember from 'ember';
export default Ember.Controller.extend({
});
I'm guessing need it to say something like this??: <-- this is where I'm stuck
import Bootstrap from 'somewhere I cant seem to figure out';
export default Bootstrap.TooltipBoxController.extend({
});
Additional information:
I've added this to a template that's otherwise working fine:
<h2 {{bs-bind-popover testme}}>Click for a popover</h2>
And in the appropriate controller, I've added:
testme: Ember.Object.create({
title: "Hello world!",
content: "yup",
placement: "left"
}),
It's not complaining about the {{bs-bind-popover}} handlebars and I've tested a couple of other things included and they seem to work OK so I'm fairly confident that I've added the assets to the project properly, etc.
Solved it myself.
My issue was misunderstanding of how things are plugged in via ember-cli...and frankly I'm still not 100% clear as some things appear to need to be imported when used, some things create a namespace under Ember and this one (bootstrap for Ember) just sticks Bootstrap as a global namespace. So, the answer to this is that I had everything right, except...
import Bootstrap from 'somewhere I cant seem to figure out';
export default Bootstrap.TooltipBoxController.extend({
});
Should've just been...
export default Bootstrap.TooltipBoxController.extend({
});
...no import needed, though you'll want some jshint comments or else it'll complain at build-time that it isn't defined (hence why I assumed it needed to be imported I guess).

Categories

Resources