restamp - dom-repeat polymer 2
Polymer Dom-Repeat Binding al contenido (3)
En el polímero 1.2.3, ¿es posible que una dom-repeat
use el contenido como plantilla y vincule los valores a los elementos proporcionados?
Elemento personalizado:
<dom-module id="modify-collection">
<template>
<div>
<template is="dom-repeat" items="[[collection]]">
<content></content>
</template>
</div>
</template>
</dom-module>
Uso:
<modify-collection collection="{{things}}">
<list-item resource="[[item]]"></list-item>
</modify-collection>
He mirado los siguientes recursos sin ayuda:
Polímero: Cómo observar el cambio en las propiedades de <contenido>
Polímero 1.0 plantilla de enlace ref equivalente
Unión de datos entre elementos poliméricos anidados
https://github.com/grappendorf/grapp-template-ref
https://github.com/Trakkasure/dom-bindref
https://github.com/Polymer/polymer/issues/1852
https://github.com/Polymer/polymer/pull/2196
Actualización 2016-02-03 : Desde el Equipo de Polímeros https://github.com/Polymer/polymer/pull/2196 , se planea un mejor soporte para esto en el futuro, para ayudar a abordar algunas de las deficiencias.TLDR
Solución 2, aunque un poco más detallado, parece funcionar mejor. También le permite elegir dinámicamente su plantilla, quizás basándose en los atributos de un modelo. (Ver Solución 2: Ejemplo avanzado)
Historia de fondo
Muchas cosas están sucediendo en este sencillo ejemplo, que incluye la creación de plantillas, el contenido de "obtención" entre las cúpulas de sombra, sombra y luz y, por supuesto, el enlace de datos.
Esta pregunta proporcionó algo de información, pero sin Polymer 0.5''s injectBoundHtml
, no era viable ( utilizando una plantilla definida en dom de luz dentro de un elemento Polymer ). El problema es que nuestros enlaces de datos parecen perderse (AFAIK) cuando intentamos copiar un elemento usando innerHTML en nuestra plantilla.
Así que sin eso no podemos crear nuestra plantilla sobre la marcha con enlaces de datos. Por lo tanto, ambas soluciones envuelven el contenido en una plantilla antes de tiempo; esto hizo que el html fuera inerte y permitiera a Polymer enlazar datos en el momento adecuado ( http://www.html5rocks.com/en/tutorials/webcomponents/template/ ).
Si realmente quiere entenderlo todo, le recomendé leer el Polímero src
para lib/template/dom-repeat.html
, lib/template/templatizer.html
, lib/annotations/annotations.html
(~ 1500 líneas).
Solución 1 -
Vea la respuesta de btelle a continuación para obtener una solución mejorada 1.
Tenga en cuenta que este enfoque hace que dom-repeat
no genere contenido automáticamente, por lo que llamamos render manualmente.
Elemento
<dom-module id="modify-collection">
<template>
<div>
<content></content>
<template id="repeater" is="dom-repeat" items="[[collection]]"></template>
</div>
</template>
<script>
...
ready: function() {
this.$.repeater.templatize(this.querySelector(''#templ''));
}
_changeCollection: function(item) {
this.push(''collection'', item);
this.$.repeater.render();
}
</script>
</dom-module>
Uso
<modify-collection collection="{{things}}">
<template id="templ"><list-item resource="[[item]]"></list-item></template>
</modify-collection>
Solucion 2
Tenga en cuenta que el uso de esto varía según el elemento 1, en que <template>
debe tener un atributo is="dom-template"
.
Elemento de ayuda
(Modificado ligeramente de esta PR: https://github.com/Polymer/polymer/pull/2196 , originalmente basado en https://github.com/grappendorf/grapp-template-ref )
!--
@license
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<!--
Portions of this code have been adapted from the `grapp-template-ref` element.
The original copyright notices are below.
-->
<!--
MIT License
Copyright (c) 2014-2015 Dirk Grappendorf, www.grappendorf.net
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<!--
The `dom-ref` element is a custom `HTMLTemplateElement` type extension that
can be used to reference another template by id using the `ref` property.
`dom-bindref` accepts a `bind` property to bind an object to the referenced
template. By default the bound object can be accessed as `item`, this can be
changed using the `as` property.
Example:
```html
<template is="dom-template" id="template-bind"><span>[[item.key]]</span></template>
<template is="dom-ref" ref="template-bind" bind=''{"key":"value"}''></dom-ref>
```
-->
<!-- <link rel="import" href="templatizer.html"> -->
<script>
Polymer({
is: ''dom-ref'',
extends: ''template'',
/**
* Fired whenever DOM is added or removed by this template (by
* default, rendering occurs lazily). To force immediate rendering, call
* `render`.
*
* @event dom-change
*/
properties: {
/**
* Reference to another template''s id.
*/
ref: {
type: String,
observer: ''_refChanged''
},
/**
* Object to be bound to referenced template.
*/
bind: {
type: Object,
observer: ''_bindChanged''
},
/**
* The name of the variable to add to the binding scope for the
* element associated with a given template instance.
*/
as: {
type: String,
value: ''item''
}
},
behaviors: [
Polymer.Templatizer
],
ready: function() {
this.templatize(this);
},
attached: function() {
return this._stamp();
},
detached: function() {
return this._removeChildren();
},
_refChanged: function(newRef, oldRef) {
if (oldRef) {
this._removeChildren();
return this._stamp();
}
},
_bindChanged: function(newBind, oldBind) {
if (oldBind) {
this._removeChildren();
return this._stamp();
}
},
_stamp: function() {
var root, template, templateRoot, bind = {};
this._parent = Polymer.dom(this).parentNode;
root = this._parent;
while (Polymer.dom(root).parentNode) {
root = Polymer.dom(root).parentNode;
}
template = Polymer.dom(root).querySelector("template#" + this.ref);
// Check For Light Dom Elements that may be passed to this shadow root (Useful for: `<content></content>`)
if (!template) {
template = root.host.querySelector("template#" + this.ref);
}
// Check the whole document
if (!template) {
template = document.querySelector("template#" + this.ref);
}
bind[this.as] = this.bind;
// templateRoot = template.stamp(bind).root;
// Use this method until this lands: https://github.com/Polymer/polymer/pull/1889
templateRoot = (new template.ctor(bind, template)).root;
this._children = Array.prototype.slice.call(templateRoot.childNodes);
return Polymer.dom(this._parent).insertBefore(templateRoot, this);
},
_removeChildren: function() {
var child, i, len, ref, results;
if (this._children) {
ref = this._children;
results = [];
for (i = 0, len = ref.length; i < len; i++) {
child = ref[i];
results.push(Polymer.dom(this._parent).removeChild(child));
}
return results;
}
}
});
</script>
Elemento
<dom-module id="modify-collection">
<template>
<div>
<content></content>
<template is="dom-repeat" items="[[collection]]">
<template is="dom-ref" bind="[[item]]" ref="templ"></template>
</template>
</div>
</template>
</dom-module>
Uso
<modify-collection collection="{{things}}">
<template id="templ" is="dom-template"><list-item resource="[[item]]"></list-item></template>
</modify-collection>
Elemento avanzado
El uso no cambia desde arriba.
Lo que hacemos aquí es introducir un nivel de direccionamiento indirecto, lo que nos permite envolver una plantilla pasada a nuestro elemento (en nuestro ejemplo, con una superposición).
<dom-module id="modify-collection">
<template>
<div>
<content></content>
<template id="wrapper" is="dom-template">
<div class="overlay">
<template is="dom-ref" bind="[[item]]" ref="templ"></template>
</div>
</template>
<template is="dom-repeat" items="[[collection]]">
<template is="dom-ref" bind="[[item]]" ref="[[_templateRef(_overlayMode)]]"></template>
</template>
</div>
</template>
<script>
...
properties: {
_overlayMode: {
type: Boolean,
value: false
}
},
_templateRef: function(overlayMode) {
return overlayMode ? ''wrapper'' : ''templ'';
}
</script>
</dom-module>
FWIW, parece que lo siguiente funciona tan bien como la solución 1, y le agrega rutas de notificación (y enlace / cambio automático, etc.):
<dom-module id="i-me">
<template>
<content></content>
<template is="dom-repeat" id="repeater" items="[[collection]]"></template>
</template>
<script>
Polymer({
is: ''i-me'',
properties: {
collection: {
type: Array,
value: [
{id: 1, name: ''a''},
{id: 2, name: ''b''}
],
notify: true
}
},
ready() {
this.$.repeater.templatize(this.querySelector(''#templ''));
Polymer.Bind.prepareModel(this.$.repeater);
Polymer.Base.prepareModelNotifyPath(this.$.repeater);
}
});
</script>
</dom-module>
Entonces solo usa esto:
<i-me>
<template id="templ">
<p><span>[[item.id]]</span>: <span>[[item.name]]</span></p>
</template>
</i-me>
Usa el elemento de la lista de hierro como ejemplo. Aquí está agarrando el elemento de plantilla pasado https://github.com/PolymerElements/iron-list/blob/9909b73a00ecc91fb957232f7bc66b59435d66ad/iron-list.html#L830 . La mezcla de templatiz se usa AFAIK para implementar el enlace a la plantilla pasada (también es utilizada por <template is="dom-repeat">
)