1

Рассмотрим следующий использование пользовательского полимерного элементаПолимер связывания данных и Immutable.js вместе

<app-header bar-foo="[[abc.def.ghi]]" app-title="[[appTitle]]"></app-header> 

Здесь я связать две переменные для пользовательского элемента app-header. Теперь, когда я хочу, чтобы обновить значения, вы могли бы ожидать, чтобы сделать это следующим образом (в родителе app-header!):

this.abc.def.ghi = 10; 
this.appTitle = 'New title'; 

Однако, это только обновляет appTitle не abc.def.ghi. Для того чтобы обновить это значение, а вам нужно сделать это следующим образом:

this.abc = {def: {ghi: 10}}; 

Если кто-то знает, почему это, пожалуйста, дайте мне знать !!

В любом случае, из-за этого, я хотел бы использовать Immutable! Однако, это вводит некоторые проблемы с тем, как данные связываются с настраиваемыми элементами

Вот пример фрагмента:

<dom-module id="my-app"> 
    <template> 
     <app-header hits="[[state.get('page').get('hits')]]"></app-header> 
    </template> 
    <script> 
     (function() { 
      class MyApp { 
       beforeRegister() { 
        this.is = 'my-app'; 

        this.properties = { 
         state: { 
          type: Object, 
          notify: true, 
          value: Immutable.Map({ 
           page: Immutable.Map({hits: 10}) 
          }) 
         } 
        }; 
       } 
      } 

      Polymer(MyApp); 
     })(); 
    </script> 
</dom-module> 

Таким образом, проблема возникает, когда привязки данных к элементу:

<app-header hits="[[state.get('page').get('hits')]]"></app-header> 

Является ли что-то вроде этого даже возможным, или я делаю что-то еще совершенно неправильно?

ответ

1

При обновлении данных структуры вы должны использовать API-интерфейс Polymer. Это приведет к обновлению измененных событий и привязанных данных. Посмотрите на this article на уведомление об изменении пути. В этом случае вы должны изменить код следующим образом:

this.set('abc.def.ghi', 10); 

Я не знаком с Неизменным, однако, таким родом выражение не поддерживается в полимере.

hits="[[state.get('page').get('hits')]]" 

Вы можете либо привязать к (суб) свойство элемента, либо вычислительную функцию. Вычислительная функция должна быть определена в вашем элементе. Вы не можете вызывать произвольные функции на произвольных объектах в ваших привязках к данным. Возможно, использование API set устранит необходимость использования неизменяемого.

1

Я знаю, что этот пост немного старый, но я хотел бы ответить, потому что я хотел исследовать с помощью Неизменного JS и полимера вместе, потому что:

  1. моя команда использует полимер структурировать приложения, не может изменить это
  2. неизменные делает реализацию отмен и Redos тривиальна и это требование

Я нашел способ связать неизменные Js объекты в полимере, но имейте в виду, что это некрасиво и Hacky.


Связывание с неизменным объектом

Для того, чтобы получить полимер для доступа неизменных Js свойств, необходимо создать свойство типа Object на прототипе элемента, который выступает в качестве своего рода «адаптера» между неизменяемые js и полимер.

Этого объект недвижимость должна использовать JavaScript getters (или Object.defineProperty), так что полимерный API, может получить доступ к объекту в форме object.property но фактическая реализация будет иметь доступ к неизменяемому объекту.

let immutableMap = Immutable.map({count: 0, text: 'world'}); 

Polymer({ 
    // ... 
    properties: { 
    /** 
    * This property is an 'adapter' to assign a property path to access the immutablejs object. 
    * The property starts with an underscore because we don't want the user to set it 
    */ 
    _adapter: { 
     type: Object, 
     value: { 
     /** 
     * the properties of this object use 
     * [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) 
     * so that polyer can access the object like `obj.count` 
     */ 
     get count() { return immutableMap.get('count'); }, 
     get text() { return immutableMap.get('text'); } 
     } 
    } 
    } 
    // ... 
}); 

Таким образом, в приведенном выше примере, я создал свойство типа Object, который имеет два метода: count и text. Поскольку эти методы добавляются с get, они должны иметь доступ только по имени метода - это getter.

Это позволяет полимеру связываться с объектом _adapter, и этот объект получает значения «0» от immutableMap.

Изменение неизменяемого объекта

Вторая деталь, необходимая для получения этого рабочего меняется неизменность объекта. Поскольку объект является неизменным, двусторонняя привязка не является вариантом. При использовании неизменяемых, вы должны добавить слушателей событий, которые переназначат неизменяемый объект и повторно визуализируют.

Для этого у вас должно быть override dirty checking in polymer. Я пробовал использовать notifyPath, но я обнаружил, что это не работает как исключение. notifyPath должен работать.

Caveat

Поскольку мы перекрывая грязную проверку и мы не используем библиотеку виртуальных DOM (как реагирует), используя неизменный объект требует повторного рендеринг какого-либо элемент, который использует _adapter каждый раз, когда изменение происходит в неизменяемом объекте. Это можно улучшить, используя notifyPath.

Полный демонстрационный (с отмен)

Вот полный демонстрационный неизменных JS и полимера вместе. Я добавил функцию отмены для небольшого стимула использования неизменен - ​​неизменен JS делает отмен и Redos очень просто: D

<base href="https://cdn.rawgit.com/download/polymer-cdn/1.7.0/lib/"> 
 
<script src="webcomponentsjs/webcomponents-lite.min.js"></script> 
 
<link rel="import" href="polymer/polymer.html"> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script> 
 

 
<!-- Defines element markup --> 
 
<dom-module id="hello-world"> 
 
    <template> 
 
    <div> 
 
     <!--use only one-way binding because the object is immutable--> 
 
     <button on-tap="onButtonClick">clicks <span>[[_adapter.count]]</span></button> 
 
    </div> 
 
    <div> 
 
     <input on-input="onInput" type="text" value="[[_adapter.text]]"> 
 
     <h1>hello, <span>[[_adapter.text]]</span>!</h1> 
 
    </div> 
 
    <div> 
 
     <button on-tap="onUndo">Undo</button> 
 
    </div> 
 
    </template> 
 

 
    <!-- Registers custom element --> 
 
    <script> 
 
    // immutable map is defined out of the scope of the polymer object 
 
    let immutableMap = Immutable.Map({ 
 
     count: 0, 
 
     text: 'world' 
 
    }); 
 
    // add undos 
 
    let undos = []; 
 

 
    Polymer({ 
 
     is: 'hello-world', 
 
     /** 
 
     * every event should reassign the `immutableMap` then manually `notifyPath` 
 
     */ 
 
     onButtonClick: function() { 
 
     undos.push(immutableMap); 
 
     immutableMap = immutableMap.update('count', count => count + 1); 
 
     this.notifyPath('_adapter.count'); 
 
     }, 
 
     onInput: function (event) { 
 
     undos.push(immutableMap); 
 
     immutableMap = immutableMap.set('text', event.target.value); 
 
     this.notifyPath('_adapter.text'); 
 
     }, 
 
     onUndo: function() { 
 
     if (undos.length) { 
 
      immutableMap = undos.pop(); 
 
     } 
 
     const obj = this._adapter; 
 
     this._adapter = {}; 
 
     this._adapter = obj; 
 
     }, 
 
     properties: { 
 
     /** 
 
     * This property is an 'adapter' to assign a property path to access the immutablejs object. 
 
     * The property starts with an underscore because we don't want the user to set it 
 
     */ 
 
     _adapter: { 
 
      type: Object, 
 
      value: { 
 
      /** 
 
      * the properties of this object use 
 
      * [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) 
 
      * so that polymer can access the object like `obj.count` 
 
      */ 
 
      get count() { return immutableMap.get('count'); }, 
 
      get text() { return immutableMap.get('text'); } 
 
      } 
 
     } 
 
     } 
 
    }); 
 
    </script> 
 
</dom-module> 
 

 
<hello-world></hello-world>