Composant

Créer un composant

Un composant est une unité réutilisable. Il peut être inclus dans un template sous la forme d’un tag personnalisé (<MonComposant />) pour s’occuper de la logique et contenu d’un bloc.

Définir un template

Un composant a, a minima, un template.

  1. Créer un template dans components
    app/components/hello-world.hbs:

     <p>Hello World</p>
    
  2. Utiliser le composant dans un autre template
    app/templates/application.hbs:

     {{page-title "Emberjs App"}}
    
     <h1>Mon Application</h1>
     <HelloWorld />
    
     {{outlet}}
    

Dans un sous-répertoire

Ajouter de la logique


Slots

  1. Le parent peut définir du contenu entre les balises du composant
    app/templates/application.hbs:

     <HelloWorld>
       <h2>Lorem ipsum</h2>
     </HelloWorld>
    
  2. Et le composant peut afficher ce contenu en appelant yield:
    app/components/hello-world.hbs:

     <h1>Hello World</h1>
    
     {{yield}}
    

Multiples slots

  1. Le parent peut définir le contenu de différents emplacements comme suit:
    app/templates/application.hbs:

     <Popup>
       <:title>
         <h3>Header</h3>
       </:title>
    
       <:default>
         <img src="//placehold.it/300x100" />
       </:default>
     </Popup>
    
  2. Et le composant peut afficher un bloc nommé en appelant yield to="blocname"
    app/components/popup.hbs:

     <div class="popup">
       <header class="popup-header">
         {{yield to="title"}}
       </header>
    
       <article class="popup-body">
         {{yield}}
       </article>
     </div>
    
  3. On peut vérifier si un bloc a été définit par le parent ou non avec has-block, ce qui peut permettre d’ajouter du contenu par défaut.

     <div class="popup">
       <header class="popup-header">
         {{#if (has-block "title")}}
           {{yield to="title"}}
         {{else}}
           Default title
         {{/if}}
       </header>
    
       <article class="popup-body">
         {{#if (has-block)}}
           {{yield}}
         {{else}}
           Default content
         {{/if}}
       </article>
    
       <footer id="popup-footer">
         {{#if (has-block "footer")}}
           {{yield to="footer"}}
         {{else}}
           Default footer
         {{/if}}
       </footer>
     </div>
    

Attributs HTML

  1. Le parent peut passer des attributs HTML:
    app/templates/application.hbs:

     <HelloWorld id="custom-id" />
    
  2. Et le composant, peut ajouter ces attributs sur un élément avec ...attributes

     <h1 ...attributes>Hello World</h1>
    

Arguments

  1. Le parent peut également passer des arguments:

     <HelloWorld @username={{"Bob"}} />
    
  2. Et le composant peut accéder aux arguments avec this.args ou @:
    app/components/hello-world.hbs:

     <h1>Hello {{this.args.username}}</h1>
     <h1>Hello {{@username}}</h1>
    

    Dans le cas d’un composant sans instance de classe (il y a uniquement un template, pas de fichier .js) alors this sera null: il faut nécessairement utiliser @.

Lifecycle


Composants natifs

Built-in Components


Composants Classic

Lifecycle

Root element

  1. Pour modifier le type de l’élément racine, spécifier la propriété tagName
    Si tagName est vide (tagName=''), Ember utilisera le premier élément du template comme élément racine.

     import Component from '@ember/component';
    
     export default Component.extend({
       tagName: 'nav'
     });
    
  2. Pour appliquer des classes sur l’élément racine, spécifier la propriété classNames

    export default Component.extend({
      classNames: ['primary']
    });
    
  3. Pour appliquer des classes dynamiques, spécifier la propriété classNameBindings

     import { notEmpty, alias } from '@ember/object/computed';
    
     export default Component.extend({
       classNameBindings: [
         'priority',
         'hasWarning:has-warning',
         'hasError:has-error',
         'isEnabled:enabled:disabled',
       ],
    
       priority: 'highestPriority',
       hasWarning: notEmpty('warnings'),
       hasError: notEmpty('errors'),
       isEnabled: false,
    
       init() {
         this._super(...arguments);
         this.setupBindings();
       },
       setupBindings() {
         defineProperty(this, 'errors', alias('model.errors.' + this.model.property));
         defineProperty(this, 'warnings', alias('model.warnings.' + this.model.property));
       },
     });
    
  4. Pour appliquer des attributs sur l’élément racine, spécifier la propriété attributeBindings

     export default Component.extend({
       attrTitle: 'Ember JS',
       attributeBindings: ['attrTitle:title'],
     });
    

Arguments