import { ConstReference } from '@glimmer/reference'; import { curry, UNDEFINED_REFERENCE, } from '@glimmer/runtime'; import * as WireFormat from '@glimmer/wire-format'; import { OutletComponentDefinition } from '../component-managers/outlet'; import { OutletReference } from '../utils/outlet'; /** The `{{outlet}}` helper lets you specify where a child route will render in your template. An important use of the `{{outlet}}` helper is in your application's `application.hbs` file: ```handlebars {{! app/templates/application.hbs }} {{my-header}}
{{outlet}}
{{my-footer}} ``` You may also specify a name for the `{{outlet}}`, which is useful when using more than one `{{outlet}}` in a template: ```handlebars {{outlet "menu"}} {{outlet "sidebar"}} {{outlet "main"}} ``` Your routes can then render into a specific one of these `outlet`s by specifying the `outlet` attribute in your `renderTemplate` function: ```app/routes/menu.js import Route from '@ember/routing/route'; export default Route.extend({ renderTemplate() { this.render({ outlet: 'menu' }); } }); ``` See the [routing guide](https://guides.emberjs.com/release/routing/rendering-a-template/) for more information on how your `route` interacts with the `{{outlet}}` helper. Note: Your content __will not render__ if there isn't an `{{outlet}}` for it. @method outlet @param {String} [name] @for Ember.Templates.helpers @public */ export function outletHelper(vm, args) { let scope = vm.dynamicScope(); let nameRef; if (args.positional.length === 0) { nameRef = new ConstReference('main'); } else { nameRef = args.positional.at(0); } return new OutletComponentReference(new OutletReference(scope.outletState, nameRef)); } export function outletMacro(_name, params, hash, builder) { let expr = [WireFormat.Ops.Helper, '-outlet', params || [], hash]; builder.dynamicComponent(expr, null, [], null, false, null, null); return true; } class OutletComponentReference { constructor(outletRef) { this.outletRef = outletRef; this.definition = null; this.lastState = null; // The router always dirties the root state. this.tag = outletRef.tag; } value() { let state = stateFor(this.outletRef); if (validate(state, this.lastState)) { return this.definition; } this.lastState = state; let definition = null; if (state !== null) { definition = curry(new OutletComponentDefinition(state)); } return (this.definition = definition); } get(_key) { return UNDEFINED_REFERENCE; } } function stateFor(ref) { let outlet = ref.value(); if (outlet === undefined) return null; let render = outlet.render; if (render === undefined) return null; let template = render.template; if (template === undefined) return null; return { ref, name: render.name, outlet: render.outlet, template, controller: render.controller, }; } function validate(state, lastState) { if (state === null) { return lastState === null; } if (lastState === null) { return false; } return state.template === lastState.template && state.controller === lastState.controller; }