Titanium JIRA Archive
Alloy (ALOY)

[ALOY-602] Nested collection bindings don't work as expected

GitHub Issuen/a
TypeBug
Priorityn/a
StatusClosed
ResolutionCannot Reproduce
Resolution Date2013-04-22T22:47:47.000+0000
Affected Version/sn/a
Fix Version/sn/a
Componentsn/a
Labelsn/a
ReporterPedro Enrique
AssigneeTony Lukasavage
Created2013-03-16T17:01:07.000+0000
Updated2014-01-29T00:07:25.000+0000

Description

First things first: I'm using the current master of alloy and titanium SDK (as of right now). I don't use Titanium Studio. I only use the CLI. I'm only developing for Android (API level 14) right now. I have two simple backbone collections defined in alloy.js:
var CharacterCollection = Backbone.Collection.extend({
	comparator: function(model){
		return model.get('name');
	}
});
var SystemCollection = Backbone.Collection.extend({
	comparator: function(model){
		return model.get('system');
	}
});

var characters = new CharacterCollection([
	{name: 'Name1', system:'System1'},
	{name: 'Name2', system:'System2'},
	{name: 'Name3', system:'System3'}
]);

var systems = new SystemCollection([
	{system:'System1'},
	{system:'System2'},
	{system:'System3'}
]);

Alloy.Collections.characters = characters;
Alloy.Collections.systems = systems;
I want to display a table with all characters, but grouped in TableViewSections for each system they belong to. So I created the following views: _index.xml_
<Alloy>
    <TableView id="characterTable" dataCollection="systems">
        <Require src="charactersBySystem" system="{system}" />
    </TableView>
</Alloy>
_charactersBySystem.xml_
<Alloy>
    <TableViewSection id="tableSection" dataCollection="characters" dataFilter="filterCharactersBySystem">
        <Require src="characterTableRow" characterName="{name}"/>
    </TableViewSection>
</Alloy>
_characterTableRow.xml_
<Alloy>
    <TableViewRow/>
</Alloy>
For those views I have the following controllers: _index.js_
var CharacterModel = Backbone.Model.extend(),
    characterCollection = Alloy.Collections.characters,
    systemCollection = Alloy.Collections.systems;

$.index.open();

systemCollection.trigger("change");
_charactersBySystem.js_
var arguments = arguments || {},
    args = arguments[0] || {},
    systemName = args.system || 'None',
    characterCollection = Alloy.Collections.characters;

function filterCharactersBySystem(collection) {
    return collection.where({system: systemName});
}

$.tableSection.headerTitle = systemName;

characterCollection.trigger("change");
_characterTableRow.js_
var arguments = arguments || {},
    args = arguments[0] || {},
    characterName = args.characterName || 'None';

$.characterTableRow.title = characterName;
Now if I run this code I get a table that looks like this: ||System1|| |Name1| |Name1| |Name1| ||System2|| |Name2| |Name2| ||System3|| |Name3| But I would expect to see: ||System1|| |Name1| ||System2|| |Name2| ||System3|| |Name3| This seems to be a bug. Or am I missing something?

Comments

  1. Davide Cassenti 2013-03-19

    Hello, It looks like the problem is due to the fact that you are firing the change manually inside charactersBySystem.js; the problem here is that this code is executed multiple times, while it should only be called once:
       characterCollection.trigger("change");
       
    By moving the trigger in index.js, the problem looks fixed to me.
  2. Steven Weingärtner 2013-03-19

    Hi, I tried that right now, but it didn't work. When I move
       characterCollection.trigger("change");
       
    to index.js, it doesn't seem to do anything. I just get the empty sections, without the actual table rows. And this seems kind of counter intuitive, too. I might trigger the change event multiple times, but shouldn't it recognize which elements within the collection have already been processed? What would happen if I add an element to the collection? That would just trigger the change event again, wouldn't it? So would it add ALL elements within the collection again without removing the old ones first? Thanks!
  3. Tony Lukasavage 2013-03-19

    No, it processes the current state of the collection. It doesn't keep track of what your code does or does not do leading up to the execution of the triggered change event. If you add an element to the collection the binding will be triggered and an "add" event will be triggered as stated in the [Backbone documentation for add()](http://backbonejs.org/#Collection-add). Each time the binding is triggered the target UI element is emptied and then repopulated with the current state of the collection. davide, could you share your modified code to show how the proper state can be achieved?
  4. Davide Cassenti 2013-03-20

    My code is simple: _index.js_
       var CharacterModel = Backbone.Model.extend(),
           characterCollection = Alloy.Collections.characters,
           systemCollection = Alloy.Collections.systems;
       
       $.index.open();
       
       systemCollection.trigger("change");
       characterCollection.trigger("change");
       
    _charactersBySystem.js_
       var arguments = arguments || {},
           args = arguments[0] || {},
           systemName = args.system || 'None',
           characterCollection = Alloy.Collections.characters;
       
       function filterCharactersBySystem(collection) {
           return collection.where({system: systemName});
       }
       
       $.tableSection.headerTitle = systemName;
       
    _characterTableRow.js_
       var arguments = arguments || {},
           args = arguments[0] || {},
           characterName = args.characterName || 'None';
       
       $.characterTableRow.title = characterName;
       
  5. Steven Weingärtner 2013-03-21

    Ok, just some more tests: I used the code I posted above (with the addition of a window element, which I forget to add to the index.xml file above). Then I copy/pasted Davids code and replaced mine with it. First I tried it on SDK version 3.1.0.v20130315162454. This only gives me the empty table view sections, sying System1, System2 and System3, but without any characters listed beneath. Then I tried to fall back to SDK version 3.0.2.GA, which gives me a blank page with nothing but the action bar that shows the title and icon of my app. Then I tried to updated to master (SDK version 3.1.0.v20130321102915). This gives me an error when I try to build the app:
       [ERROR] :  TypeError: Cannot read property 'length' of undefined
       
    Anyway, I'll try to figure that last error out. But what exact SDK version did you use?
  6. Tony Lukasavage 2013-04-05

    @Davide, can you make sure you and Steven are using the same environment? See if you guys can get synced up on why he can't get your sample working.
  7. Davide Cassenti 2013-04-10

    I've been using the GA version. Can you post the last version of your files, so I can give it another look at?
  8. Tony Lukasavage 2013-04-22

    Closing this ticket until more details are provided for Davide to test.

JSON Source