Общее состояние поведения для пользовательских элементов

У меня есть два пользовательских полимерных элемента (Polymer 1.0.3):

  1. Отображает текст для перевода.
  2. Отображает кнопку для запуска загрузки перевода.

У меня также есть Behavior, который содержит переводы (объект json) и содержит все функции, которые делают возможным перевод.

Вот что я ожидаю:

  1. Нажмите кнопку в элементе 2
  2. Переводы загружаются в поведение
  3. Выбор языка задается в Поведении.
  4. Текст в элементе 1 обновляется переведенным эквивалентом

Шаги 1-3 выполняются, а 4 - нет. Текст никогда не обновляется. Я могу заставить его работать, если элементы 1 и 2 объединены как один и тот же элемент, но не в том случае, если они отдельные (любые, которые должны быть отдельными).

Если вас интересует свойство "kick", я узнал об этом из Polymer 0.5. Когда два элемента были объединены, все заработало, поэтому я думаю, что это будет необходимо, когда элементы будут отдельными.

Любая идея, как я могу это сделать? Я открыт для альтернативных парадигм.

Код

Примерно так устроен мой код. Я также сделал планкер с одностраничным тестовым примером.

index.html

<!doctype html>
<html>

<head>
  <script src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html">
  <link rel="import" href="behavior.html">
  <link rel="import" href="element1.html">
  <link rel="import" href="element2.html">
</head>

<body>
  <my-element></my-element>
  <another-element></another-element>
</body>

</html>

Элемент 1

<dom-module id="my-element">
  <template>
    <p>{{localize(label, kick)}}</p>
  </template>
</dom-module>

<script>
  Polymer({
    is: 'my-element',
    behaviors: [
      behavior
    ],
    properties: {
      label: {
        type: String,
        value: 'original'
      }
    }
  });
</script>

Элемент 2

<dom-module id="another-element">
  <template>
    <button on-click="buttonClicked">load</button>
  </template>
</dom-module>
<script>
  Polymer({
    is: 'another-element',
    behaviors: [
      behavior
    ],
    buttonClicked: function() {
      this.registerTranslation('en', {
        original: 'changed'
      })
      this.selectLanguage('en');
    }
  });
</script>

Поведение

<script>
  var behavior = {
    properties: {
      kick: {
        type: Number,
        value: 0
      },
      language: {
        type: String,
        value: 'fun'
      },
      translations: {
        type: Object,
        value: function() {
          return {};
        }
      }
    },
    localize: function(key, i) {
      if (this.translations[this.language] && this.translations[this.language][key]) {
        return this.translations[this.language][key];
      }
      return key;
    },
    registerTranslation: function(translationKey, translationSet) {
      this.translations[translationKey] = translationSet;
    },
    selectLanguage: function(newLanguage) {
      this.language = newLanguage;
      this.set('kick', this.kick + 1);
    }
  };
</script>

person losttime    schedule 10.06.2015    source источник


Ответы (1)


Во-первых, хотя идея состоит в том, чтобы behavior быть каналом для общих данных между экземплярами, как написано, каждый экземпляр будет иметь свою собственную копию объекта translations и свойства kick.

Во-вторых, даже если эти данные были приватизированы, чтобы ими можно было поделиться, привязка kick, сделанная через localize(label, kick), находится в другой области действия, чем выражение, которое изменяет kick (т. е. this.set('kick', this.kick + 1); [{sic} это может быть просто this.kick++;]).

Чтобы уведомить N экземпляров об изменении общих данных, нужно отслеживать эти экземпляры. Хороший способ сделать это — подключить прослушиватели событий. Другой способ — просто вести список.

Вот пример реализации вашего дизайна:

    <script>
      (function() {
        var instances = [];
        var translationDb = {};
        var language = '';

        window.behavior = {
          properties: {
            l10n: {
              value: 0
            }  
          },
          attached: function() {
            instances.push(this);
          },
          detached: function() {
            this.arrayDelete(instances, this);
          },
          _broadcast: function() {
            instances.forEach(function(i) {
              i.l10n++;
            });
          },
          localize: function(key, i) {
            if (translationDb[language] && translationDb[language][key]) {
              return translationDb[language][key];
            }
            return key;
          },
          registerTranslation: function(translationKey, translationSet) {
            translationDb[translationKey] = translationSet;
          },
          selectLanguage: function(newLanguage) {
            language = newLanguage;
            this._broadcast();
          }
        };
      })();
  </script>

  <dom-module id="my-element">
    <template>
      <p>{{localize(label, l10n)}}</p>
    </template>
    <script>
      Polymer({
        behaviors: [
          behavior
        ],
        properties: {
          label: {
            type: String,
            value: 'original'
          }
        }
      });
    </script>
  </dom-module>

  <dom-module id="another-element">
    <template>
      <button on-tap="buttonClicked">load</button>
    </template>
    <script>
      Polymer({
        behaviors: [
          behavior
        ],
        buttonClicked: function() {
          this.registerTranslation('en', {
            original: 'changed'
          });
          this.selectLanguage('en');
        }
      });
    </script>
  </dom-module>
person Scott Miles    schedule 10.06.2015