My understanding is that when I run
App.CheeseController = Ember.Controller.extend({ type:"brie"});
A class CheeseController is created and that when I activate the Cheese route an instance of that class is made which is what I actually touch when talking to the controller in my handlebars template.
Is it possible to directly access that instantiated object from within the javascript console (or from within my program)? More generally, where do the objects that Ember automatically makes live?
A class CheeseController is created and that when I activate the Cheese route an instance of that class is made which is what I actually touch when talking to the controller in my handlebars template.
Yes that is exactly what happens. Ember creates a singleton instance of App.CheeseController and provides it as the context when rendering your handlebars template.
Is it possible to directly access that instantiated object from within the javascript console
Yes. The best way to do this from the javascript console is by using the handlebars {{debugger}} helper from your template. This will open the JS debug console in the context of your template.
<script type="text/x-handlebars" data-template-name="cheese">
{{debugger}}
</script>
With debugger open, you can access the instantiated controller singleton as this, so this.toString() should return something like <App.CheeseController:ember225>.
(or from within my program)?
Depends on which part of your program
From a route: Use this.controllerFor('cheese')
From a model: No. Please don't access controllers from models.
From another controller: If you declare a dependency in the other controller, needs: ['cheese'] then the singleton App.CheeseController will be accessible from the other controller via the property controllers.cheese. See Automatically synthesize the controller 'needs' dependencies
From a template: Use the needs array to declare a dependency from the templates controller, then from within your template the cheese controller is at: {{controllers.cheese}}
It is also possible to access the cheeseController instance via the ember container, but please don't. The container is not meant to be a public API. Recent updates to Ember have made accessing it somewhat awkward. This is because using global constants to access instances breaks encapsulation, and while that is fine for the console it should be avoided in your application code. For more detail, see App.container was not meant to be a public API
More generally, where do the objects that Ember automatically makes live?
Internally ember caches controller singletons in the container. Of course it is not a part of the public API, but if you are curious about how things work internally check out container_test.js and
What is the purpose of the Ember.Container
Related
I have inherited a codebase and trying to make sense of what is what. In emberjs application how do I know which controller (js) corresponds to a view (hbs) on a particular page. Is there a setting? Is there a convention?
The convention is that their names (or more accurately their paths) should be the same.
As in, controllers/page.js should have a templates/page.hbs and a routes/page.js
You can see this convention if you create a new Ember project using ember new or ember twiddle.
You can also specify the template name within a route using the templateName property.
// routes/page.js
import Route from '#ember/routing/route';
export default Route.extend({
templateName: 'something/different'
});
Ember also allows us to use the renderTemplate hook within our routes and pick a different template and/or a different controller.
// routes/page.js
export default Route.extend({
renderTemplate(controller, model) {
// Render the `something/else` template
// and use the and `other/thing` controller
this.render('something/else', {
controller: this.controllerFor('other/thing')
});
}
});
Read more in "Ember JS Guides: Rendering a template"
Ember also used to allow embedding templates within other templates using the partial helper.
It would matter a lot which Ember version you are using because that would restrict your concerns to a certain API behavior, since Ember did change a lot through the years.
For the most part it's pretty simple. Ember follows convention over configuration so let's learn the convention. The algorithm is as follows.
Look at the current url that you are on. In this case, we are on /foo
Open up the router.js file and find the route that matches this url pattern. If you don't specify paths then the url will just be the name of the route, but you could also be dealing with nested routes. Let's say we found route named foo.js which would be under appName/routes/foo.js.
Open the route file. Routes jobs are to fetch data in the model hooks, and then to set the variables on the corresponding controller instance via the setupController(controller, model) hook. When not specified, this method just sets the entire model object on the controller. Now we should have a decent idea of what variables have been dynamically set on the controller.
Open the controller under appName/controllers/foo.js. The best way to think about controllers is they are the single source of state for the corresponding template (appName/templates/foo.hbs). Their values are set via hooks on the route, as well as through the init method, computed properties, observers, etc. When you reference any {{variable}} in a handlebars template, the controller that matches this portion of the page's context is the source of state that resolves this variable. If the controller isn't defined, then Ember autogenerates one for you. Worth noting that controllers are singletons and their state persists between route changes.
Open the template.hbs file to see your markup. You might have components (custom html-looking tags that take attrs) which store their javascript under appName/components/component-name.js and their templates in appName/templates/components/component-name.hbs or have no template if the javascript file can just specify a tagName and that's it.
One other quick thing: routes are invoked in a parent/child hierarchy and correspond to urls via the route. The top level route is the application route. If you look in it's template, you will find an {{outlet}} Ember will then find whatever child route comes next and render its template into this outlet. by default /, the index route's template is rendered. But if the url was /foo then foo.hbs will be rendered into the application's outlet. Foo.hbs can have an outlet, and thats when we start getting into nested routes. That's about as quick/high level overview as I can give, ask any questions if you want specifics (I love Ember)
I am using AngularJS 1.5 and using ‘$emit’ to send an event to parent controller to refresh parent controller data. On ‘$On’ I have written the logic to refresh the parent controller data.
Now, Parent controller data is being updated but after that it is unable to bind data for the child controller from where ‘$emit’ was triggered.
I tried to use ‘$apply’ but it is saying that ‘$digest’ is already in progress. I have also use Batrang tool to view the data and it is showing that page having all those data but it is not being displayed on UI.
Can anybody tell me how to force angular to bind those data with HTML Control which is already available on the page.
I cannot put sample code here because it's a live project & I'll have to create a sample project to replicate the issue. Even though If it is not easy to answer my query without sample code then I will put sample code on Plunker in a day.
Based on Angular documentation, there are two methods to declare controller in HTML:
one binds methods and properties directly onto the controller using ng-controller="SettingsController1 as settings"
one injects $scope into the controller: ng-controller="SettingsController2"
The second option is more common in the Angular community, and is
generally used in boilerplates and in this guide. However, there are
advantages to binding properties directly to the controller and
avoiding scope.
Using controller as makes it obvious which controller you are
accessing in the template when multiple controllers apply to an
element. If you are writing your controllers as classes you have
easier access to the properties and methods, which will appear on the
scope, from inside the controller code. Since there is always a . in
the bindings, you don't have to worry about prototypal inheritance
masking primitives.
So you could always refer to parent scope in child scope by using controller as:
<div ng-controller="parentController as parent">
<span>{{parent.title}}</span>
<div ng-controller="childController as child">
<span>{{parent.title}}</span>
<span>{{child.title}}</span>
</div>
</div>
I am mildly familiar with require.js and Backbone.js having used them together for about a year now and relatively new to Backbone.Marionette although I am very interested in what it can bring to the table.
In looking for examples of project structure (I can get a little obsessed with this stuff) I have found https://github.com/BoilerplateMVC/Marionette-Require-Boilerplate and other similar examples.
Something that has been bothering me: in their app.js file, they return a reference to an instance of a Marionette application, ie:
var app = new Backbone.Marionette.Application();
app.addInitializer(...);
...
return app;
And in many components, they reference the app.js via require.js and use as follows:
define([..., 'app'], function (... , App) {
App.someProperty(...);
});
Now here's what I'm not understanding: I have been under the assumption that the code in their app.js is really more like a Factory than a Class since it returns an instance of an application rather than, say, a modified prototype or extension thereof.
Therefore, when they reference app.js, aren't they actually creating a whole new instance rather than accessing some sort of shared instance? There is nothing to suggest that app.js is returning a singleton in their code.
And yet, it works, and obviously I am the one who is confused.
So, why does this work?
This works because objects are passed by reference in javascript and the fact that require.js only loads every dependency once. Then, app.js returns an initialized instance, and every other module that requires 'app' gets reference to the same object.
It's not a factory, it's simply an initialized application object instance.
Please take a look at this JSBin1. I am using the same template for both the render in the index template and manually rendered in the renderTemplate function of the ColorsRoute. Clicking the More Colors link does not render the list of colors I return in the ColorsRoute model hook. Now, if you change the render 'colors-list model to render colors-list2 model, as I have done here, everything works as I would expect it to. The only difference between the two is that in JSBin1, I am only using the colors-list template, but in the second working example, I have one template for the render and an identical, differently named template for the ColorsRoute.
The code example, while trivial in the JSBin, is an exact extraction of something I am doing in a much larger application. This application has a bunch of widgets, which I represent by multiple named outlets in the same templates. I manually render into these outlets, as I do in the JSBin in the ColorsRoute renderTemplate hook. I do the manually rendering so that when certain events happen, I have actions defined on the route that will allow me to dynamically replace the contents of the outlet after making an ajax call to a REST API.
What is the explanation for this kind of behavior?
It's more related to the controller that's being created, not the template. And technically I'd say it shouldn't work on either, but it appears there's some route where if you don't define a controller, and that type of controller hasn't been created, create it, and use the current controller/model as the model backing it.
Really you should be providing a controller when using render if you're expecting it to have that controller as the backing controller.
renderTemplate: function(controller, model){
this.render();
this.render('color-list', {
outlet: "named",
into: 'colors',
controller: controller
});
}
http://emberjs.jsbin.com/cevagocekofu/3/edit
There are scattered explainations of each around, but I'm still not 100% clear on the differences & usage. Could someone give me a side-by-side comparison?
{{outlet}}
{{outlet NAME}}
{{render}}
{{partial}}
{{view}}
{{control}}
Note: this post was very helpful with partial vs render
They are all template helpers with the following main characteristics as described in emberjs guides.
(http://emberjs.com/guides/templates/rendering-with-helpers/)
1.{{outlet}} - Renders a template based on the route determined by the router. Based on the route the corresponding controller and view are used. This is useful when rendering contents based on the route, which is the most common case.
2.{{outlet NAME}} - Provides the ability to specify in the route where exactly to render the content. Useful when trying to render contents from more than one templates for a route.
3.{{render}} - Similar to outlet but the controller/view/model can be specified directly or indirectly from the helper. Useful when required to render content from more than one template with the ability to override the context (view/controller) and model. If model is specified it uses a unique instance of the corresponding controller, otherwise it will use the singleton instance. Useful when required to overide the route's context and model, while rendering multiple template contents.
4.{{control}} - Works like render, except it uses a new controller instance for every call, instead of reusing the singleton controller. When using render it is not possible to use multiple render for the same route without specifying the model, for that case the control should be used. Useful to support new instances of a controller for every template content rendered.
Update: Control helper has been removed https://github.com/emberjs/ember.js/commit/86eecd7ef7cdc7d2ea6f77b3a726b293292ec55d .
5.{{partial}} - Takes the template to be rendered as an argument, and renders that template in place. It does not change context or scope. It simply drops the given template into place with the current scope. So no view class is specified for the partial. Useful when it is required to break a template into template modules, for better control or reusability, without creating any view classes.
6.{{view}} - This works like partial but a view class is provided. The view class specifies the template to be used. Useful when breaking a template into modules but requiring a view class e.g. for event handling.
7.{{#view}} - There is also the block form of the view helper, which allows specifying the template of the child view inline with the parent view template. (http://emberjs.com/guides/views/inserting-views-in-templates/)
{{outlet}} this defines where nested resources/routes will be rendered inside a route's template
{{outlet NAME}} this creates a named outlet where you can programmatically render something into
App.PostRoute = App.Route.extend({
renderTemplate: function() {
this.render('favoritePost', { // the template to render
into: 'posts', // the route to render into
outlet: 'posts', // the name of the outlet in the route's template
controller: 'blogPost' // the controller to use for the template
});
this.render('comments', {
into: 'favoritePost',
outlet: 'comment',
controller: 'blogPost'
});
}
});
{{render}} takes two parameters:
The first parameter describes the context to be setup
The optional second parameter is a model, which will be passed to the controller if provided
{{render}} does several things:
When no model is provided it gets the singleton instance of the corresponding controller
When a model is provided it gets a unique instance of the corresponding controller
Renders the named template using this controller
Sets the model of the corresponding controller
{{partial}} takes the template to be rendered as an argument, and renders that template in place (using the current scope as the context).
{{view}} This helper works like the partial helper, except instead of providing a template to be rendered within the current template, you provide a view class. The view controls what template is rendered.
{{control}} is deprecated works like render, except it uses a new controller instance for every call, instead of reusing the singleton controller.
Most of this I just copied and pasted from their documentation: http://emberjs.com/guides/templates/rendering-with-helpers/
render helper is deprecated in v2.x instead you need to use ember-elsewhere addon. https://emberjs.com/deprecations/v2.x/#toc_rendering-into-a-render-helper-that-resolves-to-an-outlet
ember.view is deprecated in v1.x instead use Component. refer https://emberjs.com/deprecations/v1.x/#toc_ember-view
control helper is experimental only, its already removed
I would say currently only {{outlet}} is encouraged one remaining all are either deprecated/removed.
Main differences are
{{view}} renders the provided view class which should be available
{{partial}} renders the template available in Ember.TEMPLATES. its may not have related the view class. Advantage is context of the template remains of the parent view.
{{outlet}} Specify the router that here it is supposed to render the provided view or template or as per renderTemplate() hook.
{{outlet NAME}} useful when you want to render two views/templates at different positions. You can name the outlets and ask router to render.
{{render}} same as outlet except you force the router to render specific view/template.