Extending DataRepeater

Hey all,

I'm trying to create an enyo.DataRepeater subkind with custom refresh and reset methods.

I thought this would be as simple as creating a subkind and giving it custom reset and refresh methods, but it appears these methods are not actually being called. It seems the constructor method binds the handlers from the enyo.DataRepeater kind rather than the ones from my subkind.

Does anyone know what's the best way to tackle this problem?

Comments

  • Hi @ruben_vreeken, that's odd, can we take a look at how you're implementing this? In enyo.DataList, which is a subkind of enyo.DataRepeater, we have overridden refresh and reset, and I've verified these execute properly in the DataListSample: https://github.com/enyojs/enyo/blob/master/source/ui/data/DataList.js#L176.
  • Sure thing, here ya go:
    enyo.kind({
    name: "hln.ui.PaddedDataRepeater",
    kind: enyo.DataRepeater,
    mixins: [hln.ui.BuildComponentSupport],
    published: {
    minItems: undefined,
    },
    placeholderOptions: undefined,
    minItemsChanged: function() {
    this.refresh();
    },
    //*@public
    /**
    Destroys any existing children in the repeater and creates all new children
    based on the current data.
    */
    reset: function() {
    var minItems = this.get("minItems"),
    curItems = 0,
    data,
    i,
    record;

    // use the facaded dataset because this could be any
    // collection of records
    data = this.get("data");

    // destroy the client controls we might already have
    this.destroyClientControls();

    // and now we create new ones for each new record we have
    if (data) {
    for (i = 0;
    (record = data.at(i)); ++i) {
    this.add(record, i);
    }
    }
    this.padControls();

    this.hasReset = true;
    },
    /**
    Refreshes each control in the dataset.
    */
    refresh: function() {
    if (!this.hasReset) {
    return this.reset();
    }

    this.startJob("refreshing", function() {
    var data,
    controls,
    i,
    record,
    control;

    data = this.get("data");
    controls = this.getClientControls();

    for (i = 0;
    (record = data.at(i)); ++i) {
    control = controls[i];

    if (control) {
    control.set("model", record);
    } else {
    this.add(record, i);
    }
    }
    this.padControls();
    this.prune();
    }, 16);
    },
    //*@protected
    padControls: function() {
    var data,
    numItems,
    minItems,
    placeholder,
    placeholder;

    data = this.get("data");
    minItems = this.get("minItems");
    numItems = this.getClientControls().length;

    while (numItems < minItems) {
    placeholder = this.buildComponentFromProperty("placeholder");
    placeholder.index = numItems;
    placeholder.mixins = placeholder.mixins ? placeholder.mixins.concat(this.childMixins) : this.childMixins;
    placeholder = this.createComponent(placeholder);
    if (this.generated && !this.batching) {
    placeholder.render();
    }
    ++numItems;
    }
    }
    });
    By the way, the BuildComponentSupport mixin is a convenience mixin that implements a buildComponentFromProperty method. The buildComponentFromProperty converts a property on the current instance to an object defining a component that can be created using createComponent.

    I've tried setting breakpoints inside the reset and refresh methods, but they are never reached, but a grid of items is generated. Putting a breakpoint inside the constructor method of enyo.DataRepeater pauses when the handlers get bound (usign bindSafely) and the handler methods seem to reference enyo.DataRepeater methods.
  • Problem solved. Not sure what happens in the constructor exactly, but it turns out I had to look at the modelsAdded and modelsRemoved methods rather than the refresh method.
  • Glad you solved it @ruben_vreeken! Were you more referring to refresh and/or reset not being run at create time?
  • Yes, that's what I was referring to.
  • By the way, I've also implemented a DataRepeater subkind that adds a suffix item at the end of the list. While doing so, I noticed that in order to add a prefix to the start of the list there would be a disconnect between the indexes in the collection, and the indexes of the clientControls of the repeater. (since a prefix doesn't represent a record in the repeaters' collection).

    I'm not sure yet if i'm going to need a prefix item yet, but if I do I might create a repeater that doesn't assume the records and controls share the same index. Would something like that be something worthy of adding to enyo core's DataRepeater kind itself, or is it too specific?
    If it's worthy of enyo core I might as well try to patch the Repeater rather than creating a sub-kind and create a pull-request for it.
  • Hi @ruben_vreeken, great idea! Its one we've had for a while but the demand for it has been moot thus far and we never got around to it. I will say that while adding a cool feature like this would be great in core, some work is being done around DataRepeater that might interfere with the approach you take. I don't know exactly how soon that work will land (and won't interfere with whatever additions you for your kind, hopefully) so I wouldn't wait for it to get started - but just note that we can take a look at lessons learned from your work and can adapt it to the changes after-the-fact. If that makes sense...in other words - go ahead and do what you need to at this moment and we can evaluate how to fit that in when we have final form of the work being done internally.
Sign In or Register to comment.