List item and classes

edited May 2012 in Enyo 2
I have a weird issue with some code I'm writing. on tap I'm doing:

inSender.addClass("selected");

And the dom element is getting styled as I expect, but:

console.log(inSender.classes)

isn't showing the "selected" class. And when I try to remove the class later, nothing happens to the dom element. I can see the node in the enyo.instance object and it has selected listed as a class, but the classes property doesn't.

I was originally using a Scroller and adding the elements using create component, which was working fine. I decided to switch to a List since the scroller didn't perform well on the touchpad. and this problem creeped up.

Any suggestions on where I should look?

Comments

  • edited May 2012
    It's probably because the class is being lost during the row setup. You should do something like this in the tap method:
    this.listData[inSender.rowIndex].isSelected = true
    and then in the row setup method:
    
    if(this.listData[inSender.rowIndex].isSelected){
        this.$.myRow.addClass("theClass");
    }
    
    EDIT: forgot to point it at listData
  • Lists use a flyweight pattern where there isn't a Enyo object left around for each list element, but instead, a specific instance of a node gets locked into a row while it is being rendered or used.

    You need to use calls to prepareRow() and lockRow() around any manipulation in order for this to work outside of the onSetupRow handler.
  • Because of the use of flyweight pattern, if you use @omastudios solution, your code must be something like this:
    setupRow: function(inSender, inEvent) {
          this.$.myRow.addRemoveClass("theClass", this.listData[inEvent.index].isSelected);
    }
    If you just use 'addClass' the myRow instance will have that class on subsequent iterations. By using 'addRemoveClass' you make sure the class is only installed when rendering the desired row.
  • heh, I left a part out. this code is in the ontap event of the row, so, it's not occurring during setupRow. I'm checking out the documentation for prepareRow and lockRow as Ben suggested.

    Thanks
  • edited May 2012
    Yes, that was clear. Let me be a bit more complete:
    setupRow: function(inSender, inEvent) {
        // other setup steps
        ...
        // handle selection
        this.$.myRow.addRemoveClass("theClass", this.listData[inEvent.index].isSelected);
    },
    rowTap: function(inSender, inEvent) {
          var record = this.listData[inEvent.index];
          // toggle selection
          record.isSelected = !record.isSelected;
          // update the row
          this.$.list.renderRow(inEvent.index);
    }
    This way, your row display always reflects your actual data, and vice versa. prepareRow and lockRow are for more specialized cases.

    Fwiw, ironically, List has a selection mechanism built in. To use that all you need to do is this:
    setupRow: function(inSender, inEvent) {
        // other setup steps
        ...
        // handle selection
        this.$.myRow.addRemoveClass("theClass", this.$.list.isSelected(inEvent.index));
    },
    
  • That's more elegant than the nasty code I was about to cut and paste. However, my problem is less with the current row (what's represented in inEvent.index) but with removing the class from the prior selected row.

    I'm going to try your suggested by storing off the prior selected index and call renderRow on that.
  • edited May 2012
    Fwiw, published properties can help with this kind of problem. E.g.
    published: {
      trackedRow: -1
    },
    trackedRowChanged: function(inOld) {
      // fixup the old row (no-op if inOld is out of range)
      this.$.list.renderRow(inOld);
      // mark the new row
      this.$.list.renderRow(this.trackedRow);
    },
    setupRow: function(inSender, inEvent) {
      this.$.row.addRemoveClass("tracked", inEvent.index == this.trackedRow);
    },
    rowTap: function(inSender, inEvent) {
      this.setTrackedRow(inEvent.index);
    }
  • is addRemoveClass similar to jQuery's toggleClass? will tapping the same element a second time remove the class?
  • No, addRemoveClass relies only on the boolean second argument (but won't double apply).

    The implementation is simply:
    
    addRemoveClass: function(inClass, inTrueToAdd) {
    this[inTrueToAdd ? "addClass" : "removeClass"](inClass);
    }
    
Sign In or Register to comment.