following scenario:
I have a Firebase database containing a list that is used to create a set of "paper-cards" with dom-repeat:
<template is="dom-repeat" items="{{items}}">
<my-element card="{{item}}">
<paper-card id="{{card.id}}">
...
</paper-card>
</my-element>
</template>
In the UI, the user can add or delete paper-cards, so items also get deleted in Firebase.
Now I realized if I change the CSS of an element (e.g. fadeIn, fadeOut animation) and afterwards delete a card and later add one card, the card still has the CSS state as it was before (e.g. for fadeIn/fadeOut animations).
My questions:
How does DOM repeat deal with elements added or removed? Is not all information of this element "deleted"?
If I delete item #5 (out of 10), what happens to elements 6-10, are they deleted and re-created as "5-9" or "moved/altered"?
Besides CSS, are there any other implications that should be considered inside the template tag? Do I need to manually reset anything?
You can read about the dom-repeat on https://www.polymer-project.org/1.0/docs/api/dom-repeat but what it basically tells you that it tries to be too smart without asking the developer if it wants that behavior. The dom-repeat is heavily flawed because of this.
Polymer is saving performance to doing a dirty check, basically looping through everything and only changing the DOM if the checked values (id, in this case) changes. This means that it will inherit other values.
Basically, it wont update sub-properties. This means that dom-repeat isn't really made for any kind of update.
You can possibly go around this issue by using Polymer's this.splice(). It works like the splice in javascript but sends out an event to dom-repeat to update and where to update. Remember however, that arrays in Javascript are references, so if you take this.items and try to modify it, it will automatically update values the dom-repeat (without updating DOM) and then it will dirty check the update with the new values and not change anything at all. If you want to modify the array in the dom-repeat, then use JSON.parse(JSON.stringify(array) first to get rid of the reference.
Another thing you can do is to use the unique id. If the id changes for that specific card, then hard reset all values and initialize that specific card once again with all it's normal properties (including CSS). That's the workaround I use all the time.
The desperate thing to do, when nothing else works, is to nullify the array that keeps track of the cardset, with this.set('items', []) and then set the property with the new array.
The repeater evaluates the number of items in your array on initialization and stamps that many template instances into the DOM. If you delete an item from your array the repeater is presented with a new array that is one element less, removes the last one and propagates data change to elements' instances.
So if you start with 10 elements and order to delete #5 then element's #6 data is inserted via data-binding into the same DOM node that previously contained #5 data, and so on down the list. The last DOM node for which the updated array contains no data will be removed from the DOM tree.
Related
Need help with a concept. Building a custom element that displays data from my database. Using a repeat template and it working great. The report is grouped and so each row in the report contains another level of data that is displayed once you drill into a row. So now I want to be able to "refresh" the report data to reflect sort or grouping changes. The report is based off an "indexing" array that points to the actual data displayed. I sort/group the data in the index array, and use this array as the array for the Template Repeat.
<div id="rptbody">
<template repeat="{{group in groups}}">
<pmg-group groupid={{group.id}} groupval={{group.groupval}} groupobj={{group.groupobj}}></pmg-group>
</template>
</div>
So in this example, the groups array is a list of keys to my data. In this example, the groups array is ordered properly so that [0] contains the first index to the data array, and [length-1] contains the last. I have a sort routine that changes the index value in groups, but it does not add or remove items from the groups array.
So my question is after my resort, how do I trigger the template to rescan the groups list? I have found that I can set groups = [], and then reload groups ( groups.push({idx} ) from my master index, and it will update the template, however that seems kind of wasteful to me.
Is there any way to trigger the template to refresh, or rescan the groups array and reorganize the DOM based on the changes in the values?
In the past I've gotten template repeats to refresh like this:
var template = document.querySelector('template'); // Use specific selector here
template.iterator_.updateIteratedValue(); // Force Polymer to refresh template
It's a hack, but it looks like it still works. Here's a jsbin.
Just stumbled on this and found out we have to use the .set method of the Polymer element data model. Not directly found any docs about this but this seems interesting https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#set-path. Would avoid those hacky things because they could change API over the time.
I'm currently trying to apply a filter to the wxCheckListBox (for a search of specific elements). So far i have no idea how to do it. The Problem with it is, that I don't want to have a copy of the Control and always delete the unnecessary items from the copy, and as soon as the search changes it has to be copied again from the original and delete the items again. I was wondering if there is a way to simply hide some items and not the entire control
You can't hide the items in a wxListBox or wxCheckListBox. To have this sort of dynamic control over the items appearing in the control you need to use wxListCtrl in virtual mode.
However it's not usually really a problem to delete some items from a wxListBox and then insert them back (or, even simpler, store all the items, delete some of them from the control and then, to revert, clear the control and restore all the initially stored items).
I've got a spark list that gets dynamically filled.
So far the new items appear at the bottom of the list. What I'd like to do is to add them at the top.
The items in the list have a unique ID so some kind of sorting mechanism would probably do the trick as the new items have a greater ID than the old ones.
What I'd like to avoid is some complex method behind this as I'm working on a mobile platform and the list can get quite big so I need this to be as efficient as possible.
The list's data provider is an ArrayList that gets updated using binding.
How can that be done?
Thanks in advance!
u can Add the items at the starting index of the datagrid. Flex datagrid automatically renew all the indexes and add 1 to all existing element indexes. So
YourDataGridId.dataprovider.addItemAt(item,0) will do.
I have a list that is mediated by a view mediator, so the data provider is managed by the said mediator (meaning it just calls viewComponent.list.dataProvider.addItemAt([object], 0) when new items are added to the list.
The list has a custom item renderer which has an addedEffect property (a basic fade in effect), which of course is supposed to play every time a new item is added to the list.
The issue is that the first time I add an item it works, but for any subsequent added items, it does not. Does anyone know the cause of this issue, or more preferably a fix?
Thank you in advance.
I'm not 100% sure, but my guess is that when useVirtualLayout is true, only a single item renderer is ever created. Multiple rows are accomplished by changing the itemRenderer's data, validating the component then taking a bitmap snapshot of it. Thus the item renderer is only ever added to the display list once, and the added event in turn is only ever fired once. Turning off useVirtualLayout forces the list to create new instances for each row in the list, so separate added events are dispatched.
I have two different Spark Lists, with two different ItemRenderers, one of them with dragEnabled="true" and the other with dropEnabled="true", in such a way that whenever I drag from one and drop in the other, a copy of the object dropped is created and inserted in the second List's dataProvider.
<s:List id="source"
itemRenderer="componentsRenderers.SourceItemRenderer"
dragEnabled="true"
dataProvider="{elements}"/>
<s:List id="destination"
itemRenderer="componentsRenderers.DestinationItemRenderer"
dragEnabled="false"
dropEnabled="true"
change="destinationChanged(event)"/>
The event handler destinationChanged() is a method that parses the recently added object, removes it, and creates a new one that, among other stuff, has an UIComponent that has to be rendered.
The hole thing works well, except by one thing: as soon as the I load the application, the UIComponent of the first item to be dropped in destination never gets renderer. The full object is there and all the other functionalities related to it work, but the component doesn't get rendered. If I delete the object, making the List empty again, and insert it again, it gets rendered!
Also, after inserting the 'invisible' one, all the following inserts works.
Ideas?
Thanks!
Update: I just found out that the itemRenderer DestinationItemRenderer gets rendered twice for the first element to be dropped.