UNPKG

ember-source

Version:

A JavaScript framework for creating ambitious web applications

489 lines (398 loc) 14 kB
declare module '@ember/-internals/glimmer' { /** [Glimmer](https://github.com/tildeio/glimmer) is a templating engine used by Ember.js that is compatible with a subset of the [Handlebars](http://handlebarsjs.com/) syntax. ### Showing a property Templates manage the flow of an application's UI, and display state (through the DOM) to a user. For example, given a component with the property "name", that component's template can use the name in several ways: ```app/components/person-profile.js import Component from '@ember/component'; export default Component.extend({ name: 'Jill' }); ``` ```app/components/person-profile.hbs {{this.name}} <div>{{this.name}}</div> <span data-name={{this.name}}></span> ``` Any time the "name" property on the component changes, the DOM will be updated. Properties can be chained as well: ```handlebars {{@aUserModel.name}} <div>{{@listOfUsers.firstObject.name}}</div> ``` ### Using Ember helpers When content is passed in mustaches `{{}}`, Ember will first try to find a helper or component with that name. For example, the `if` helper: ```app/components/person-profile.hbs {{if this.name "I have a name" "I have no name"}} <span data-has-name={{if this.name true}}></span> ``` The returned value is placed where the `{{}}` is called. The above style is called "inline". A second style of helper usage is called "block". For example: ```handlebars {{#if this.name}} I have a name {{else}} I have no name {{/if}} ``` The block form of helpers allows you to control how the UI is created based on the values of properties. A third form of helper is called "nested". For example here the concat helper will add " Doe" to a displayed name if the person has no last name: ```handlebars <span data-name={{concat this.firstName ( if this.lastName (concat " " this.lastName) "Doe" )}}></span> ``` Ember's built-in helpers are described under the [Ember.Templates.helpers](/ember/release/classes/Ember.Templates.helpers) namespace. Documentation on creating custom helpers can be found under [helper](/ember/release/functions/@ember%2Fcomponent%2Fhelper/helper) (or under [Helper](/ember/release/classes/Helper) if a helper requires access to dependency injection). ### Invoking a Component Ember components represent state to the UI of an application. Further reading on components can be found under [Component](/ember/release/classes/Component). @module @ember/component @main @ember/component @public */ /** @module ember */ /** @class Ember.Templates.helpers @public */ /** `{{yield}}` denotes an area of a template that will be rendered inside of another template. ### Use with `Component` When designing components `{{yield}}` is used to denote where, inside the component's template, an optional block passed to the component should render: ```app/templates/application.hbs <LabeledTextfield @value={{@model.name}}> First name: </LabeledTextfield> ``` ```app/components/labeled-textfield.hbs <label> {{yield}} <Input @value={{@value}} /> </label> ``` Result: ```html <label> First name: <input type="text" /> </label> ``` Additionally you can `yield` properties into the context for use by the consumer: ```app/templates/application.hbs <LabeledTextfield @value={{@model.validation}} @validator={{this.firstNameValidator}} as |validationError|> {{#if validationError}} <p class="error">{{validationError}}</p> {{/if}} First name: </LabeledTextfield> ``` ```app/components/labeled-textfield.hbs <label> {{yield this.validationError}} <Input @value={{@value}} /> </label> ``` Result: ```html <label> <p class="error">First Name must be at least 3 characters long.</p> First name: <input type="text" /> </label> ``` `yield` can also be used with the `hash` helper: ```app/templates/application.hbs <DateRanges @value={{@model.date}} as |range|> Start date: {{range.start}} End date: {{range.end}} </DateRanges> ``` ```app/components/date-ranges.hbs <div> {{yield (hash start=@value.start end=@value.end)}} </div> ``` Result: ```html <div> Start date: July 1st End date: July 30th </div> ``` Multiple values can be yielded as block params: ```app/templates/application.hbs <Banner @value={{@model}} as |title subtitle body|> <h1>{{title}}</h1> <h2>{{subtitle}}</h2> {{body}} </Banner> ``` ```app/components/banner.hbs <div> {{yield "Hello title" "hello subtitle" "body text"}} </div> ``` Result: ```html <div> <h1>Hello title</h1> <h2>hello subtitle</h2> body text </div> ``` However, it is preferred to use the hash helper, as this can prevent breaking changes to your component and also simplify the api for the component. Multiple components can be yielded with the `hash` and `component` helper: ```app/templates/application.hbs <Banner @value={{@model}} as |banner|> <banner.Title>Banner title</banner.Title> <banner.Subtitle>Banner subtitle</banner.Subtitle> <banner.Body>A load of body text</banner.Body> </Banner> ``` ```app/components/banner.js import Title from './banner/title'; import Subtitle from './banner/subtitle'; import Body from './banner/body'; export default class Banner extends Component { Title = Title; Subtitle = Subtitle; Body = Body; } ``` ```app/components/banner.hbs <div> {{yield (hash Title=this.Title Subtitle=this.Subtitle Body=(component this.Body defaultArg="some value") )}} </div> ``` Result: ```html <div> <h1>Banner title</h1> <h2>Banner subtitle</h2> A load of body text </div> ``` A benefit of using this pattern is that the user of the component can change the order the components are displayed. ```app/templates/application.hbs <Banner @value={{@model}} as |banner|> <banner.Subtitle>Banner subtitle</banner.Subtitle> <banner.Title>Banner title</banner.Title> <banner.Body>A load of body text</banner.Body> </Banner> ``` Result: ```html <div> <h2>Banner subtitle</h2> <h1>Banner title</h1> A load of body text </div> ``` Another benefit to using `yield` with the `hash` and `component` helper is you can pass attributes and arguments to these components: ```app/templates/application.hbs <Banner @value={{@model}} as |banner|> <banner.Subtitle class="mb-1">Banner subtitle</banner.Subtitle> <banner.Title @variant="loud">Banner title</banner.Title> <banner.Body>A load of body text</banner.Body> </Banner> ``` ```app/components/banner/subtitle.hbs {{!-- note the use of ..attributes --}} <h2 ...attributes> {{yield}} </h2> ``` ```app/components/banner/title.hbs {{#if (eq @variant "loud")}} <h1 class="loud">{{yield}}</h1> {{else}} <h1 class="quiet">{{yield}}</h1> {{/if}} ``` Result: ```html <div> <h2 class="mb-1">Banner subtitle</h2> <h1 class="loud">Banner title</h1> A load of body text </div> ``` @method yield @for Ember.Templates.helpers @param {Hash} options @return {String} HTML string @public */ /** `{{(has-block)}}` indicates if the component was invoked with a block. This component is invoked with a block: ```handlebars {{#my-component}} Hi Jen! {{/my-component}} ``` This component is invoked without a block: ```handlebars {{my-component}} ``` Using angle bracket invocation, this looks like: ```html <MyComponent>Hi Jen!</MyComponent> {{! with a block}} ``` ```html <MyComponent/> {{! without a block}} ``` This is useful when you want to create a component that can optionally take a block and then render a default template when it is not invoked with a block. ```app/templates/components/my-component.hbs {{#if (has-block)}} Welcome {{yield}}, we are happy you're here! {{else}} Hey you! You're great! {{/if}} ``` @method has-block @for Ember.Templates.helpers @param {String} the name of the block. The name (at the moment) is either "main" or "inverse" (though only curly components support inverse) @return {Boolean} `true` if the component was invoked with a block @public */ /** `{{(has-block-params)}}` indicates if the component was invoked with block params. This component is invoked with block params: ```handlebars {{#my-component as |favoriteFlavor|}} Hi Jen! {{/my-component}} ``` This component is invoked without block params: ```handlebars {{#my-component}} Hi Jenn! {{/my-component}} ``` With angle bracket syntax, block params look like this: ```handlebars <MyComponent as |favoriteFlavor|> Hi Jen! </MyComponent> ``` And without block params: ```handlebars <MyComponent> Hi Jen! </MyComponent> ``` This is useful when you want to create a component that can render itself differently when it is not invoked with block params. ```app/templates/components/my-component.hbs {{#if (has-block-params)}} Welcome {{yield this.favoriteFlavor}}, we're happy you're here and hope you enjoy your favorite ice cream flavor. {{else}} Welcome {{yield}}, we're happy you're here, but we're unsure what flavor ice cream you would enjoy. {{/if}} ``` @method has-block-params @for Ember.Templates.helpers @param {String} the name of the block. The name (at the moment) is either "main" or "inverse" (though only curly components support inverse) @return {Boolean} `true` if the component was invoked with block params @public */ /** Execute the `debugger` statement in the current template's context. ```handlebars {{debugger}} ``` When using the debugger helper you will have access to a `get` function. This function retrieves values available in the context of the template. For example, if you're wondering why a value `{{foo}}` isn't rendering as expected within a template, you could place a `{{debugger}}` statement and, when the `debugger;` breakpoint is hit, you can attempt to retrieve this value: ``` > get('foo') ``` `get` is also aware of keywords. So in this situation ```handlebars {{#each this.items as |item|}} {{debugger}} {{/each}} ``` You'll be able to get values from the current item: ``` > get('item.name') ``` You can also access the context of the view to make sure it is the object that you expect: ``` > context ``` @method debugger @for Ember.Templates.helpers @public */ export { templateFactory as template, templateCacheCounters } from '@glimmer/opcode-compiler'; export { default as RootTemplate } from '@ember/-internals/glimmer/lib/templates/root'; export { default as Input } from '@ember/-internals/glimmer/lib/components/input'; export { default as LinkTo } from '@ember/-internals/glimmer/lib/components/link-to'; export { default as Textarea } from '@ember/-internals/glimmer/lib/components/textarea'; export { default as Component } from '@ember/-internals/glimmer/lib/component'; export { default as Helper, helper, type FunctionBasedHelper, type FunctionBasedHelperInstance, } from '@ember/-internals/glimmer/lib/helper'; export { SafeString, escapeExpression, htmlSafe, isHTMLSafe, } from '@ember/-internals/glimmer/lib/utils/string'; export { Renderer, _resetRenderers, renderSettled } from '@ember/-internals/glimmer/lib/renderer'; export { getTemplate, setTemplate, hasTemplate, getTemplates, setTemplates, type TemplatesRegistry, } from '@ember/-internals/glimmer/lib/template_registry'; export { setupEngineRegistry, setupApplicationRegistry, } from '@ember/-internals/glimmer/lib/setup-registry'; export { DOMChanges, NodeDOMTreeConstruction, DOMTreeConstruction, } from '@ember/-internals/glimmer/lib/dom'; export { default as OutletView, type BootEnvironment, } from '@ember/-internals/glimmer/lib/views/outlet'; export type { OutletState, RenderState } from '@ember/-internals/glimmer/lib/utils/outlet'; export { componentCapabilities, modifierCapabilities, setComponentManager, } from '@ember/-internals/glimmer/lib/utils/managers'; export { isSerializationFirstNode } from '@ember/-internals/glimmer/lib/utils/serialization-first-node-helpers'; export { uniqueId } from '@ember/-internals/glimmer/lib/helpers/unique-id'; }