PolymerElements / iron-selector

Manages a list of elements that can be selected
32 stars 55 forks source link

"selectable" property only works for immediate children #42

Open bendavis78 opened 9 years ago

bendavis78 commented 9 years ago

I have nested loops that generate the items for my selector, so my markup looks like this (simplified for brevity):

  <iron-selector id="calendarSelector" selectable=".day-item">
    <template is="dom-repeat" items="{{months}}" as="month">
          <template is="dom-repeat" items="{{month.weeks}}" as="week">
            <div class="week">
              <template is="dom-repeat" items="{{week}}" as="day">
                <div label$="{{item.date}}" class="day-item">{{item.day}}</div>
              </template>
            </div>
          </template>
        </div>
    </template>
  </iron-selector>

This type of setup worked fine with core-selector in 0.5, but doesn't work in 1.0.

klebba commented 9 years ago

Just hit this -- surprised to find this disparity between 0.5 and 1.0 -- the iron-selectable docs make no mention of this limitation:

* This is a CSS selector sting.  If this is set, only items that matches the CSS selector
* are selectable.
dwagner4 commented 9 years ago

Seems to have gotten worse. I've been using the below pattern a lot.

<iron-selector selected="{{selectedmyitem}}">
  <template is="dom-repeat" items="{{myitems}}">
    <div>{{item}}</div>
  </template>
</iron-selector> 
<h2>{{selectedmyitem}}</h2>

myitems: {
          type: Array,
          value: function () {
            return ["robert", "john", "sue"];
          }
        },

until recently this worked fine (in fact at the last demo before the customer). Now it is broken while the below works like a champ. Similar issue? dom-repeat templates don't work with iron-selector? Deadlines will force me to jerry-rig around this issue.

<iron-selector selected="{{selectedmyitem2}}">
  <div>Allison</div>
  <div>Cindy</div>
  <div>Kathy</div>
 </iron-selector> 
 <h2>{{selectedmyitem2}}</h2>
govis commented 9 years ago

As a workaround I have been using IronSelectableBehavior directly and overriding its get items() method. I use jQuery, but it might also be doable with Polymer's dom helpers.

behaviors: [
    Polymer.IronSelectableBehavior
],
get items() {
    var nodes = $(this.selectable, this).get();
    return Array.prototype.filter.call(nodes, this._bindFilterItem);
}
            
cdata commented 8 years ago

First, I would like to apologize on behalf of the team for the un-announced regression of functionality from core-selector 0.5 -> iron-selector 1.0. We should have done a better job of communicating the change in behavior.

Second, we are interested in supporting this use case again. Since there are performance costs associated with the old behavior, we are probably going to add it back in as a boolean attribute that you can apply to any iron-selectable implementing element.

Please leave any further feedback on this in this issue!

bicknellr commented 8 years ago

The current implementation uses queryDistributedElements to select items; this means that items can come from any 'lighter' layer of light DOM, as long as those elements would be distributed to a content element that is a child of the iron-selector. With that in mind, does the request to find items by selecting from descendants extend through any number of light DOM layers as well?

In this example, only example-1 and example-3 are selectable in the current implementation. It sounds like the request is to at least make example-2 selectable also, but what about 4-6?

<!-- template for <nested-selector> -->
<iron-selector selectable=".item">
  <example-1 class="item" />
  <div>
    <example-2 class="item" />
  </div>

  <content select=".content-1"></content>
  <div>
    <content select=".content-2"></content>
  </div>

  <content select=".content-3"></content>
  <div>
    <content select=".content-4"></content>
  </div>
</iron-selector>

<!-- somewhere else -->
<nested-selector>
  <example-3 class="content-1 item" />
  <example-4 class="content-2 item" />

  <div class="content-3">
    <example-5 class="item" />
  </div>
  <div class="content-4">
    <example-6 class="item" />
  </div>
</nested-selector>
govis commented 8 years ago

Not sure about the above scenario as my use cases are mostly straightforward with items being rendered by a dom-repeat template and need to be selectable.

I do have a question about queryDistributedElements and a "content element" - what if there's is none? In an element with a dom-repeat template and Polymer.IronSelectableBehavior like the one below queryDistributedElements returns and empty array and paper-items are not selectable:

<dom-module id="selectable-test">
<template>
<paper-material>
<template is="dom-repeat" items="[[itemData]]">
<paper-item>[[item]]</paper-item>
</template>
</paper-material>
</template>
<script>
Polymer({
is: "selectable-test",
properties: {
itemData: {
type: Array,
value: ["Item 1", "Item 2", "Item 3"]
}
},
behaviors: [
Polymer.IronSelectableBehavior
],
selectable: "paper-item",
listeners: {
'iron-activate': '_onIronActivate'
},
_onIronActivate: function (event) {
debugger;
}
});
</script>
</dom-module>

If wrapped in <iron-selector selectable="paper-item"></iron-selector> it seems to be working now.

javier-pepe commented 8 years ago

in version 1.0.8 iron-selector still does not handle the scenario first described by @bendavis78

I'm facing a similar issue with the following structure, iron-selector holding a dom-repeat, Inside another dom-repeat that holds the actual selectable items...

<iron-selector attr-for-selected="target-id" selectable="[selectable]:not(.target-disabled)">

    <template is="dom-repeat" items="{{users}}" as="user" index-as="user_index">

        <div id$="{{user.id}}">

            <template is="dom-repeat" items="{{user.statistics}}" as="stats" index-as="stat_index">

                <user-stats class$="[[stats.properties.class]]" target-id$="[[stats.target.id]]"
                    target="{{stats.target}}"
                    sizing="cover"
                    compact
                    selectable$="[[stats.isEditable]]">

Modifying, https://github.com/PolymerElements/iron-selector/blob/master/iron-selectable.html#L220-L224

_updateItems: function() {
      var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
      nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
      this._setItems(nodes);
    },

Into

 _updateItems: function() {
            var nodes = this.selectable
                ? Polymer.dom(this).querySelectorAll(this.selectable)
                : Polymer.dom(this).queryDistributedElements('*');

            nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
            this._setItems(nodes);
    },

Solved it, please note that extending the behavior did not worked for me, had to directly edit the element, which is not ideal, since when its updated, changes are replaced... it would be great to implement the solution into the component though, thanks

misjob commented 8 years ago

Extending actually works fine (v1.0.8). Also voting for implementing it in the component.

var MySelectableBehaviorImpl = {
  _updateItems: function() {
    var nodes = this.selectable
            ? Polymer.dom(this).querySelectorAll(this.selectable)
            : Polymer.dom(this).queryDistributedElements('*');
    nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
    this._setItems(nodes);
  }      
};
var MySelectableBehavior = [
  Polymer.IronSelectableBehavior,
  MySelectableBehaviorImpl
];

(function() {
  'use strict';

  Polymer({
    is: 'my-selector',
    behaviors: [
      MySelectableBehavior
    ]
});
cdata commented 8 years ago

It is still not decided if iron-selector should support this style of nested items.

bicknellr commented 8 years ago

In the Shadow DOM spec, there's a section about HTMLSlotElement.prototype.getAssignedNodes which mentions that you can optionally pass an object {flatten: true} and get the distributed nodes. However, there's currently no formally documented mechanism for learning about changes to the distributed content of a slot. w3c/webcomponents#288 is tracking this issue and the result of that discussion will probably play a role here since the options they've mentioned have different timing and might require listening in multiple ways to be sure all DOM changes are caught. :/

ergo commented 7 years ago

Any news on this?

I would like to use iron selector like:

<iron-selector selectable="foo > item">
    <slot name="foo"></slot>
</iron-selector>
dman777 commented 6 years ago

Any updates to this? I need it for divs paper-radio-group