props emberjs ember create component bubbling ember.js handlebars.js ember.js-view

ember.js - emberjs - ember onclick action



Ember.Component(forma de bloque): más de una salida{{yield}} (3)

Agregué una extensión a CoreView para manejar esto (al final de esta publicación). La extensión funciona seccionando el método _renderToBuffer y

  1. registrar ayudantes temporales de Handlebars para capturar ''contenido marcador de posición'' del contenido interno de la instancia componente,
  2. representando el componente en un buffer temporal descartado (esencialmente llamando a rendimiento en nombre del componente),
  3. volver a registrar ayudantes de manubrio para inyectar el ''contenido marcador de posición'' capturado,
  4. renderizando la plantilla del componente como normal,
  5. limpiar (restaurar los ayudantes de manubrio a su estado anterior).

Para la plantilla del componente, use marcadores de posición, como este

<div class=''modal-dialog''> <div class=''modal-content''> <div class=''modal-header''> {{header}} </div> <div class=''modal-body''> {{body}} </div> <div class=''modal-footer''> {{footer}} </div> </div> </div>

En la definición del componente, incluya una propiedad ''marcadores de posición'' que identifique los marcadores de posición que se usarán:

App.BootstrapDialogComponent = Ember.Component.extend({ placeholders: [ ''header'', ''body'', ''footer'' ], ... });

Luego, cuando use el componente, use el nombre de marcador de posición, como este

{{#bootstrap-dialog}} {{#header}} Add Product {{/header}} {{#body}} ...form... {{/body}} {{#footer}} <button>Save</button> {{/footer}} {{/bootstrap-dialog}}

Aquí está el código que empuja en la extensión:

(function() { var _renderToBufferOriginal = Ember.CoreView.create()._renderToBuffer; Ember.CoreView.reopen({ _renderToBuffer: function(buffer, bufferOperation) { this.transitionTo(''inBuffer'', false); var placeholders = { } if (this.placeholders) { this.placeholders.map(function(n) { placeholders[n] = { saved: Ember.Handlebars.helpers[n], buffer: null, } Ember.Handlebars.helpers[n] = function(options) { var tmp = placeholders[n].buffer = placeholders[n].buffer || Ember.RenderBuffer(); var saved = options.data.buffer; options.data.buffer = tmp; options.fn(options.contexts[0], options); options.data.buffer = saved; }; }); Ember.Handlebars.helpers[''yield''].call(this, { hash: { }, contexts: [ this.get(''context'') ], types: [ "ID" ], hashContexts: { }, hashTypes: { }, data: { view: this, buffer: Ember.RenderBuffer(), isRenderData: true, keywords: this.cloneKeywords(), insideGroup: this.get(''templateData.insideGroup''), } }); this.placeholders.map(function(n) { Ember.Handlebars.helpers[n] = function(options) { var str = ((placeholders[n].buffer)? placeholders[n].buffer.innerString(): ""); options.data.buffer.push(str); }; }); } var result = this._renderToBufferOriginal.apply(this, arguments); if (this.placeholders) { this.placeholders.map(function(n) { Ember.Handlebars.helpers[n] = placeholders[n].saved; }); } return result; }, _renderToBufferOriginal: _renderToBufferOriginal, }); }).call(this);

Veo que la brasa tiene un mecanismo muy bueno para envolver contenido en un componente usando el mecanismo {{yield}} documentado here .

Entonces, para usar el ejemplo en la documentación, puedo tener una plantilla de componente de blog-post definida así:

<script type="text/x-handlebars" id="components/blog-post"> <h1>{{title}}</h1> <div class="body">{{yield}}</div> </script>

Luego puedo insertar una blog-post en cualquier otra plantilla usando el formulario:

{{#blog-post title=title}} <p class="author">by {{author}}</p> {{body}} {{/blog-post}}

Mi pregunta es, ¿puedo especificar dos puntos de venta {{yield}} en la plantilla de componentes?

Algo así es posible a través de Named Outlets en Ember.Route#renderTemplate así:

Manubrios :

<div class="toolbar">{{outlet toolbar}}</div> <div class="sidebar">{{outlet sidebar}}</div>

JavaScript :

App.PostsRoute = Ember.Route.extend({ renderTemplate: function() { this.render({ outlet: ''sidebar'' }); } });

No estoy seguro de poder tomar esta ruta para un componente que no sabrá qué plantilla de ruta lo representaría.

EDIT 1:

En aras de la claridad, estoy tratando de implementar Android Swipe for Action Pattern como un componente Ember.

Por lo tanto, me gustaría que los usuarios de este componente puedan especificar dos plantillas diferentes:

  1. Una plantilla para el elemento de la lista normal, y
  2. Una plantilla para las acciones que se revelan cuando se detecta un deslizamiento en (1).

Quiero hacer de esto un componente, ya que una gran cantidad de JavaScript se usa para manejar los eventos de toque (inicio / movimiento / final), mientras se sigue administrando el desplazamiento táctil suave de la lista. Los usuarios suministrarían las dos plantillas y este componente gestionaría el manejo de los eventos táctiles y las animaciones necesarias.

Logré que el componente funcione en forma de bloque, donde el contenido del bloque se trata como (1). La segunda plantilla (2) se especifica a través de un parámetro ( actionPartial continuación) que es el nombre de una plantilla partial para las acciones:

Plantilla de manubrios de componentes: sfa-item.handlebars

<div {{bind-attr class=":sfa-item-actions shouldRevealActions:show" }}> {{partial actionPartial}} </div> <div {{bind-attr class=":sfa-item-details isDragging:dragging shouldRevealActions:moveout"}}> {{yield}} </div>

Llamando a la plantilla de manubrios:

{{#each response in controller}} <div class="list-group-item sf-mr-item"> {{#sfa-item actionPartial="mr-item-action"}} <h5>{{response.name}}</h5> {{/sfa-item}} </div> {{/each}}

Donde el manillar mr-item-action se define de esta manera:

mr-item-action.handlebars :

<div class="sf-mr-item-action"> <button class="btn btn-lg btn-primary" {{action ''sfaClickedAction''}}>Edit</button> <button class="btn btn-lg btn-primary">Delete</button> </div>

El problema es que las acciones del usuario proporcionado parcial, sfaClickedAction anterior, no se sfaClickedAction del componente. Un hecho que se menciona en los docs párrafo 4.

Entonces, ahora no sé cómo un usuario podría capturar acciones que definió en la plantilla de acciones suministradas. Un componente no puede detectar esas acciones porque tampoco las conoce.

EDIT 2

Surgió una pregunta de seguimiento here


Dado que no es posible tener dos ayudantes {{yield}} dentro de un componente (¿cómo sabría el componente dónde se detiene el marcado de un {{yield}} y comienza el siguiente?), Puede abordar este problema desde una dirección diferente.

Considere el patrón de componentes anidados. Los navegadores ya lo hacen con gran éxito. Tome, por ejemplo, los componentes <ul> y <li> . A <ul> desea tomar muchos bits de marcado y representar cada uno como un miembro de una lista. Para lograr esto, te obliga a separar tu marcado detallado en etiquetas <li> . Hay muchos otros ejemplos de esto. <table> , <tbody> , <tr> , <td> es otro buen caso.

Creo que es posible que hayas tropezado con un caso en el que puedas implementar este patrón. Por ejemplo:

{{#sfa-item}} {{#first-thing}} ... some markup {{/first-thing}} {{#second-thing}} ... some other markup {{/second-thing}} {{/sfa-item}}

Obviamente, lo first-thing second-thing son nombres terribles para sus componentes especializados que representan las cosas que le gustaría envolver con su primera y segunda plantilla. Entiendes la idea.

Tenga cuidado ya que los componentes anidados no tendrán acceso a las propiedades dentro del componente externo. Deberá vincular los valores con componentes externos e internos si se necesitan en ambos.


Esta publicación de blog describe la solución más elegante para Ember 1.10+: https://coderwall.com/p/qkk2zq/components-with-structured-markup-in-ember-js-v1-10

En tu componente, pasas los nombres de rendimiento a {{yield}} s:

<header> {{yield "header"}} </header> <div class="body"> {{yield "body"}} </div> <footer> {{yield "footer"}} </footer>

Cuando invocas tu componente, aceptas el nombre del rendimiento como un parámetro de bloqueo ... ¡y usas una cadena de esleif!

{{#my-comp as |section|}} {{#if (eq section "header")}} My header {{else if (eq section "body")}} My body {{else if (eq section "footer")}} My footer {{/if}} {{/my-comp}}

PS eq es un auxiliar de subexpresiones del complemento must-have ember-truth-helpers .

PPS RFC relevante: proposal , discussion .