Polymer и Polymerfire: как да преминете през данните от наблюдател?

Имам прост етикет <firebase-query> и бих искал да манипулирам някои от данните, преди да ги покажа чрез <dom-repeat>. Например, трябва да превърна някои полета във връзки и също да анализирам някои дати.

И така, трябва да получа данните, след като са готови, да премина през всеки елемент и да променя някои от стойностите.

За да направя това, имам наблюдател на данните, който да открива кога са готови. Не мога обаче да разбера как да превъртя данните от тази JavaScript функция. По някаква причина for(var i in items) не работи, въпреки че елементите съществуват.

Ето компонента:

<dom-module id="cool-stuff">

  <template>

    <firebase-query id="query" path="/items" data="{{items}}"></firebase-query>

    <template is="dom-repeat" items="{{items}}" as="item">
      [[item.name]]<br />
      [[item.date]]<br />
    </template>

  </template>

  <script>
    Polymer({
      is: 'ix-table',
      properties: {
        items: {type: Object, observer: "_itemsChanged"},
      }
      itemsChanged: function(data) {
        // how do I loop through the data received from firebase-query?
        console.log(data);
      }
    });
  </script>

</dom-module>

В идеалния случай всичко, което бих искал да направя във функцията наблюдател, е нещо като:

for(var i in data) {
  obj = data[i];
  obj.name = '<a href="/bg/item/"+obj.key>'+ojb.name+'</a>';
}

Но изглежда не мога да преглеждам данните.

Във функцията наблюдател console.log(data) връща някои странни неща като това:

Array[o]
0: Object (which contains a proper item)
1: Object (same)
2: Object (same)

Актуализация:

Ето екранна снимка на това, което console.log(data) връща (от вътрешността на наблюдателя):

въведете описание на изображението тук

Масивът изглежда е попълнен с всички обекти, но се показва като Array[0]. Така че няма да ми позволи да ги прегледам.

Актуализация 2:

Благодарение на arfost ето решението:

<script>
  Polymer({
    is: 'ix-table',
    properties: {
      items: {type: Object},

    }
    observers: [
      '_itemsChanged(items.splices)'
    ],
    _itemsChanged: function(changeRecord) {
      if (changeRecord) {
        changeRecord.indexSplices.forEach(function(s) {
          for (var i=0; i<s.addedCount; i++) {
            var index = s.index + i;
            var item = s.object[index];
            console.log('Item ' + item.name + ' added at index ' + index);
            // do whatever needed with the item here:
            this.items[index].name = "New name";
          }
        }, this);
      }
    },
  });
</script>

person Hubert    schedule 03.01.2017    source източник
comment
Хубаво, но мисля, че сте направили грешка при изчисляването на индекса, защо добавяте 1 към него? индексът 0 се съпоставя с обекта 0 също и за всеки вече цикъл през защо ще имате друг for цикъл.   -  person TheeBen    schedule 08.04.2017
comment
Честно казано, всъщност не разбирам вътрешностите на този бизнес със снаждане... всичко, което знам, е, че тази част от кода работи и ми позволява да получа елементите върнати от Firebase.   -  person Hubert    schedule 09.04.2017
comment
Мисля, че няма да имате нужда от снаждане, ако пътят ви завършва с възел, който има разклонени възли с вложени деца, но когато пътят ви завършва с непосредствени деца, е необходимо снаждане. Вземете го обаче с щипка сол   -  person TheeBen    schedule 10.04.2017
comment
Не знам дали това е елегантно решение, но вие, сър, решихте проблема ми. Благодаря!   -  person luckyging3r    schedule 21.06.2017


Отговори (3)


Мисля, че се натъкнах на същия проблем като вас.

Той идва от начина, по който заявката на firebase получава масива, начина, по който работи polymer obersvers, и е скрит от факта, че конзолата на javascript е базирана на препратки, когато показва обектите.

Всъщност това, което наистина се случва тук, е, че заявката на firebase създава празен масив, който задейства вашия полимерен наблюдател.

Така че вашата функция се извиква веднага след като масивът е създаден, но все още е празен и не можете да го обхождате, тъй като е празен. След това го регистрирате, където под-свойствата на примитивите се показват правилно (масив [0])

След това firebase започва да попълва масива с данни. Препратката към масивите остава същата, така че polymer няма да задейства отново наблюдателя и в конзолата, когато се опита да покаже масива, тя показва масива, посочен в дневника, който сега съдържа данните.

Препоръчвам ви да използвате наблюдател на мутация на масив вместо вашия прост, както следва

`properties: {
    items: {type: Object},
  },
,
observers: [
       '_itemsChanged(items.splices)'
],`

Той ще се задейства всеки път, когато към вашия масив бъде добавен обект и вие ще можете да вършите работата, от която се нуждаете :)

Имах връзката за документацията за наблюдател на мутация на масив :) polymer наблюдател на мутация на масив

Надявам се, че това ще реши проблема ви, приятен ден.

person Arfost    schedule 04.01.2017
comment
Ах, страхотно, точно това беше решението! Много благодаря, че посочихте правилното място. Актуализирах първата публикация с решението. - person Hubert; 04.01.2017
comment
Аз също се натъквам на това. Не искам да действам на всяко „снаждане“, но да взема целия набор от данни наведнъж, когато приключи със зареждането на всички елементи. Как мога да направя това? - person Riël; 07.04.2017
comment
С възможностите в реално време на firebase никога не разполагате с целия набор от данни, тъй като във всеки момент може да има нов възел в него от други клиенти. Ако искате да го третирате като цяло, а не като списък от X независими елементи, firebase-document е по-подходящ за това според мен - person Arfost; 07.04.2017
comment
Да, ако не е необходимо да преминавате през всеки елемент (което в моя случай направих), тогава е много по-лесно и firebase-document ще бъде по-подходящ - person Hubert; 09.04.2017

<firebase-query> резултати

Имайте предвид, че <firebase-query> води до масив от обекти. Да приемем, че вашата база данни съдържа следните елементи под /notes/<USER_ID>/:

въведете описание на изображението тук

Вашето <firebase-query> ще изглежда подобно на това:

<firebase-query
    id="query"
    app-name="notes"
    path="/notes/[[user.uid]]"
    data="{{notes}}">
</firebase-query>

(където user е свързано с <firebase-auth>.user).

Ако приемем, че потребителят е влязъл, <firebase-query> ще попълни своето data свойство (т.е. обвързано с notes) със следния масив:

въведете описание на изображението тук

Обърнете внимание как всеки обект съдържа свойство $key, което съответства на ключа на елемента, който се вижда в изгледа База данни на конзолата на Firebase.

След това можете да итерирате notes директно с <dom-repeat>:

<template is="dom-repeat" items="[[notes]]">
  <li>
    <div>key: [[item.$key]]</div>
    <div>body: [[item.body]]</div>
    <div>title: [[item.title]]</div>
  </li>
</template>

Свързване към HTML низове

Трябва да знаете, че обвързванията на низови данни се изобразяват буквално в този случай, така че опитът да зададете name на obj.name = '<a href="/bg...">' ще изобрази литералния низ вместо котва. Вместо това трябва да декларирате таговете във вашия шаблон и да обвържете свойствата key и name вътре в тези тагове. Така че вашият наблюдател може да бъде заменен с това:

<template is="dom-repeat" items="{{items}}" as="item">
  <a href$="/item/[[item.key]]">[[item.name]]</a><br />
  [[item.date]]<br />
</template>

Итериране на масив

Следната бележка е уместна само ако предпочитате да промените данните, преди да ги покажете...

Когато итерирате масив, трябва да избягвайте for..in, защото не гарантира ред на итерация и защото може да итерира върху изброими свойства, които може да не ви интересуват непременно. Вместо това можете да използвате for..of (ако приемем, че ES6 е достъпен за вашето приложение):

for (let note of notes) {
  note.title += ' ...';
}

или Array.prototype.forEach():

notes.forEach(function(note) {
  note.title += ' ...';
});
person tony19    schedule 03.01.2017
comment
Благодаря много, това е много информативно и високо ценено. В моя случай трябваше да променя данните преди показване и по някаква причина все още не мога да преглеждам данните от функцията наблюдател. Добавих екранна снимка на това, което console.log(data) показва от наблюдателя в моя оригинален пост. - person Hubert; 04.01.2017

не мисля, че мога да се сетя за сценарий, при който ще трябва да промените данните, като преминете през масива, вместо просто да използвате изчислени обвързвания. като този:

<template is="dom-repeat" items="{{items}}" as="item">
  <child-el date="{{_computeDate(item.date)}}"></child-el><br />
  <child-el attr1="{{_someOtherConversion(item.prop1)}}"></child-el><br />
  <child-el attr2="{{_iPromiseAnyConversionCanBeDoneLikeThis(item.prop2)}}"></child-el><br />
</template>
<script>
  _computeDate: function(item) {
    //do date converstion
}
person Ryan Tyler    schedule 04.01.2017
comment
Най-вече защото предавам данните на дъщерен компонент, който ги показва в хубава таблица. Тъй като дъщерният компонент е общ, трябва да променя някои от данните предварително. - person Hubert; 04.01.2017
comment
Променете го чрез изчислени обвързвания - person Ryan Tyler; 04.01.2017
comment
промених отговора си, за да отговоря на последния ви коментар. - person Ryan Tyler; 05.01.2017