scripts - variables globales javascript entre paginas
PolĂmero 1.0 Variables globales (8)
El elemento de polímero <iron-meta>
también es una opción. Para mí esta fue la solución más fácil.
En Polymer 0.5, el consejo sobre globales fue el bosquejado en esta pregunta / respuesta:
Variables globales de polímero
Sin embargo, en Polymer 1.0 esto no parece funcionar. Las notificaciones de cambios no se generan automáticamente en el modelo subyacente, sino que se generan en el <dom-module>
que significa que las notificaciones de cambio se generarán solo en una de las <app-globals>
.
¿Cuál es la forma recomendada de implementar este patrón en Polymer 1.0?
Es mucho más fácil lograr el mismo efecto de las variables globales si envuelve su aplicación en una plantilla. Mire la explicación en este video (lo relacioné con el minuto exacto y el segundo donde se explica el concepto).
He combinado todas las sugerencias anteriores en el siguiente objeto polimérico global
<dom-module id="app-data">
</dom-module>
<script>
(function () {
var instances = [];
var vars = Object.create(Polymer.Base);
var commondata = {
get loader() {
return vars.get("loader");
},
set loader(v) {
return setGlob("loader", v);
}
};
function setGlob(path, v) {
if (vars.get(path) != v) {
vars.set(path, v);
for (var i = 0; i < instances.length; i++) {
instances[i].notifyPath("data." + path, v);
}
}
return v;
}
Polymer({
is: ''app-data'',
properties: {
data: {
type: Object,
value: commondata,
notify: true,
readonly: true
}
},
created: function () {
instances.push(this);
},
detached: function () {
var i = instances.indexOf(this);
if (i >= 0) {
instances.splice(i, 1);
}
}
});
})();
</script>
y usarlo en otro lugar
<dom-module id="app-navigation">
<style>
</style>
<template>
<app-data id="data01" data="{{data1}}" ></app-data>
<app-data id="data02" data="{{data2}}"></app-data>
<span>{{data1.loader}}</span>
<span>{{data2.loader}}</span>
</template>
</dom-module>
<script>
(function () {
Polymer({
is: ''app-navigation'',
properties: {
},
ready: function () {
this.data1.loader=51;
}
});
})();
</script>
El cambio de data1.loader o data2.loader afecta a otras instancias. Debe extender el objeto de datos comunes para agregar más propiedades globales, como se muestra con la propiedad del cargador.
He extendido la solución de Etherealones para que funcione como un Comportamiento, y extiendo los métodos de "establecer" y "notificarPath" de Polymers para activar las actualizaciones automáticamente. Esto es lo más cercano que pude llegar a un enlace de datos verdadero a través de componentes / elementos:
globals-behavior.html:
<script>
var instances = [];
var dataGlobal = {};
var GlobalsBehaviour = {
properties: {
globals: {
type: Object,
notify: true,
value: dataGlobal
}
},
ready: function() {
var _setOrig = this.set;
var _notifyPathOrig = this.notifyPath;
this.set = function() {
_setOrig.apply(this, arguments);
if (arguments[0].split(".")[0] === "globals") {
this.invokeInstances(_notifyPathOrig, arguments);
}
};
this.notifyPath = function(path, value) {
_notifyPathOrig.apply(this, arguments);
if (arguments[0].split(".")[0] === "globals") {
this.invokeInstances(_notifyPathOrig, arguments);
}
};
},
invokeInstances: function(fn, args) {
var i;
for (i = 0; i < instances.length; i++) {
instance = instances[i];
if (instance !== this) {
fn.apply(instance, args);
}
}
},
attached: function() {
instances.push(this);
},
detached: function() {
var i;
i = instances.indexOf(this);
if (i >= 0) {
instances.splice(i, 1);
}
}
};
</script>
Y en todos los elementos de polímero que deberían tener acceso a la variable global:
<script>
Polymer({
is: ''globals-enabled-element'',
behaviors: [GlobalsBehaviour]
});
</script>
Ejemplos:
- He publicado un ejemplo completo como Gist en Github
- Aquí hay un fragmento para verlo en acción:
<!DOCTYPE html>
<html>
<head>
<title>Globals Behavior Example</title>
<link rel="import" href="//rawgit.com/Polymer/polymer/master/polymer.html">
<dom-module id="globals-enabled-element">
<template>
<input type="text" value="{{globals.my_variable::input}}">
</template>
<script>
var instances = [];
var dataGlobal = {};
var GlobalsBehaviour = {
properties: {
globals: {
type: Object,
notify: true,
value: dataGlobal
}
},
ready: function() {
var _setOrig = this.set;
var _notifyPathOrig = this.notifyPath;
this.set = function() {
_setOrig.apply(this, arguments);
if (arguments[0].split(".")[0] === "globals") {
this.invokeInstances(_notifyPathOrig, arguments);
}
};
this.notifyPath = function(path, value) {
_notifyPathOrig.apply(this, arguments);
if (arguments[0].split(".")[0] === "globals") {
this.invokeInstances(_notifyPathOrig, arguments);
}
};
},
invokeInstances: function(fn, args) {
var i;
for (i = 0; i < instances.length; i++) {
instance = instances[i];
if (instance !== this) {
fn.apply(instance, args);
}
}
},
attached: function() {
instances.push(this);
},
detached: function() {
var i;
i = instances.indexOf(this);
if (i >= 0) {
instances.splice(i, 1);
}
}
};
</script>
<script>
Polymer({
is: ''globals-enabled-element'',
behaviors: [GlobalsBehaviour]
});
</script>
</dom-module>
</head>
<body>
<template is="dom-bind">
<p>This is our first polymer element:</p>
<globals-enabled-element id="element1"></globals-enabled-element>
<p>And this is another one:</p>
<globals-enabled-element id="element2"></globals-enabled-element>
</template>
</body>
</html>
He implementado un patrón como usos de iron-signals
para este propósito. Entonces, el principio básico es que usted notifique manualmente a otras instancias cuando ocurra una actualización.
Considera esto:
<dom-module id="x-global">
<script>
(function() {
var instances = [];
var dataGlobal = {};
Polymer({
is: ''x-global'',
properties: {
data: {
type: Object,
value: dataGlobal,
},
},
attached: function() {
instances.push(this);
},
detached: function() {
var i = instances.indexOf(this);
if (i >= 0) {
instances.splice(i, 1);
}
},
set_: function(path, value) {
this.set(path, value);
instances.forEach(function(instance) {
if (instance !== this) { // if it is not this one
instance.notifyPath(path, value);
}
}.bind(this));
},
notifyPath_: function(path, value) {
instances.forEach(function(instance) {
instance.notifyPath(path, value);
});
},
fire_: function(name, d) {
instances.forEach(function(instance) {
instance.fire(name, d);
});
},
});
})();
</script>
</dom-module>
fire_
invocará la versión que tenga un sufijo de guión bajo como fire_
cuando esté disparando un evento. Incluso puede crear un comportamiento de polímero de algún tipo con este patrón, supongo.
Tenga en cuenta que Polymer ya utiliza las propiedades de subrayado anteriores, por lo que no continúe y _fire
en _fire
.
PD: No miré alrededor para resolver cómo reflejar la notificación de this.push(array, value);
como yo no lo necesito No sé si es posible de esta manera. Debería ir a buscar Polymer.Base.push
.
Intenté mejorar la respuesta de Alexei Volkov, pero quería definir las variables globales por separado. En lugar de getters / setters usé la propiedad del observer
y guardé la clave junto con las instancias.
El uso es:
<app-data key="fName" data="{{firstName}}" ></app-data>
mientras que la propiedad key
define el nombre de la variable global.
Entonces, por ejemplo, puedes usar:
<!-- Output element -->
<dom-module id="output-element" >
<template>
<app-data key="fName" data="{{data1}}" ></app-data>
<app-data key="lName" data="{{data2}}" ></app-data>
<h4>Output-Element</h4>
<div>First Name: <span>{{data1}}</span></div>
<div>Last Name: <span>{{data2}}</span></div>
</template>
</dom-module>
<script>Polymer({is:''output-element''});</script>
Definición del módulo dom <app-data>
:
<dom-module id="app-data"></dom-module>
<script>
(function () {
var instances = [];
var vars = Object.create(Polymer.Base);
Polymer({
is: ''app-data'',
properties: {
data: {
type: Object,
value: '''',
notify: true,
readonly: false,
observer: ''_data_changed''
},
key: String
},
created: function () {
key = this.getAttribute(''key'');
if (!key){
console.log(this);
throw(''app-data element requires key'');
}
instances.push({key:key, instance:this});
},
detached: function () {
key = this.getAttribute(''key'');
var i = instances.indexOf({key:key, instance:this});
if (i >= 0) {
instances.splice(i, 1);
}
},
_data_changed: function (newvalue, oldvalue) {
key = this.getAttribute(''key'');
if (!key){
throw(''_data_changed: app-data element requires key'');
}
vars.set(key, newvalue);
// notify the instances with the correct key
for (var i = 0; i < instances.length; i++)
{
if(instances[i].key == key)
{
instances[i].instance.notifyPath(''data'', newvalue);
}
}
}
});
})();
</script>
La demostración totalmente operativa está aquí: http://jsbin.com/femaceyusa/1/edit?html,output
Sjmiles, uno de los creadores de Polymer acaba de publicar el siguiente snippet en la sala slack de Polymer como ejemplo de datos compartidos:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="shared-data element and repeats">
<base href="http://milestech.net/components/">
<script href="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
</head>
<body>
<demo-test></demo-test>
<script>
(function() {
var private_data = [{name: ''a''}, {name: ''b''}, {name: ''c''}];
Polymer({
is: ''private-shared-data'',
properties: {
data: {
type: Object,
notify: true,
value: function() {
return private_data;
}
}
}
});
})();
Polymer({
is: ''xh-api-device'',
properties: {
data: {
type: Array,
notify: true
},
_share: {
value: document.createElement(''private-shared-data'')
}
},
observers: [
''dataChanged(data.*)''
],
ready: function() {
this.data = this._share.data;
this.listen(this._share, ''data-changed'', ''sharedDataChanged'');
},
dataChanged: function(info) {
this._share.fire(''data-changed'', info, {bubbles: false});
},
sharedDataChanged: function(e) {
this.fire(e.type, e.detail);
},
add: function(name) {
this.push(''data'', {name: name});
}
});
</script>
<dom-module id="demo-test">
<template>
<h2>One</h2>
<xh-api-device id="devices" data="{{data}}"></xh-api-device>
<template is="dom-repeat" items="{{data}}">
<div>name: <span>{{item.name}}</span></div>
</template>
<h2>Two</h2>
<xh-api-device data="{{data2}}"></xh-api-device>
<template is="dom-repeat" items="{{data2}}">
<div>name: <span>{{item.name}}</span></div>
</template>
<br>
<br>
<button on-click="populate">Populate</button>
</template>
<script>
Polymer({
populate: function() {
this.$.devices.add((Math.random()*100).toFixed(2));
// this works too
//this.push(''data'', {name: (Math.random()*100).toFixed(2)});
}
});
</script>
</dom-module>
</body>
</html>
De hecho, he movido mi aplicación a utilizar el enlace de datos simple, por lo que no estoy seguro de la validez de este enfoque, pero tal vez sería útil para alguien.
Usando la solución de Ootwch , encontré una situación de condición de carrera con componentes cargados de pereza.
Tal como se publicó, los componentes con carga diferida no se inicializan con el valor de los datos compartidos.
En caso de que alguien más se encuentre con el mismo problema, creo que lo solucioné agregando una devolución de llamada lista como esta:
ready: function() {
const key = this.getAttribute(''key'')
if (!key) {
throw new Error(''cm-app-global element requires key'')
}
const val = vars.get(key)
if (!!val) {
this.set(''data'', val)
}
},
Espero que esto le ahorre algo de dolor a alguien.