Class: UWA.Class.Collection

UWA/Class/Collection. UWA.Class.Collection

new UWA.Class.Collection(models, options)

When creating a Collection, you may choose to pass in a model instance or an array of model instances. However, if the collection being created has a reference (via model property) to a model constructor, the collection can internally instantiate models by passing a raw attribute/data object or an array of raw attributes/data objects.

You can also choose not to pass any initial model, in this case, the created instance of collection will be empty.

It is not recommended to override this method for the construction of an instance of a collection. If you want to run some initialization code when an instance of your collections is constructed, you should rather implement the setup method, which will be invoked when the collection is created.

Example
var tabs, spaces;

// provided that you have already defined a class TabSet
// inheriting from UWA.Class.Collection :
tabs = new TabSet([tab1, tab2, tab3]);

// Another example using the base Collection class,
// starting with no data
spaces = new UWA.Class.Collection([], {
  model: Space,
  url: '/spaces'
});
Parameters
Name Type Argument Description
models Void <optional>

Can be one of the following :

  • an array of instances of UWA.Class.Model
  • an array of raw attributes/data objects, if the collection being created has a reference (via model property) to a model constructor
  • a single instance of UWA.Class.Model
  • a raw attribute/data object, if the collection being created has a reference (via model property) to a model constructor
options Object <optional>

an hash of options. Next to your custom options, you can use :

Properties
Name Type Argument Default Description
url Function | String <optional>
null

Allow to override url at construction time

model Constructor <optional>
null

Allow to override model at construction time

comparator Function | String <optional>
null

Allow to override comparator at construction time

Index

Members

comparator :String|Function

Override this property to maintain the collection in order.

By default there is no comparator for a collection. If you define a comparator property, it will be used to maintain the collection in sorted order. This means that as models are added, they are inserted at the correct index in the internal container of models. A comparator can be defined :

  • as a function that takes a model as single argument and return a numeric or string value by which the model should be ordered relative to others,
  • as a comparator function that expects two models, and returns -1 if the first model should come before the second, 0 if they are of the same rank and 1 if the first model should come after.
  • or as a string indicating the attribute to sort by.

Note how even though all of the chapters in this example are added backwards, they come out in the proper order:

var Chapter, chapters;
Chapter = UWA.Class.Model;
chapters = new UWA.Class.Collection();
chapters.comparator = 'page';
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));

chapters.pluck('title'); // returns ["The Beginning", "The Middle", "The End"]

Collections with a comparator will not automatically re-sort if you later change model attributes, so you may wish to call sort after changing model attributes that would break the sorting logic.

Automatic re-sorting on a model attribute change can also be easily added on a per-collection basis, but be aware of the performance hit ! :

var collection = new UWA.Class.Collection([], {
   comparator: 'attrName'
});
collection.addEvent('onChange:' + collection.comparator, function (model, val, options) {
    this.sort(options);
});

Changing the value of this comparator property at runtime will not re-sort the collection. Call sort to force the re-sorting of the collection if necessary.

Type
  • String | Function

model :UWA/Class/Model

Override this property to specify the model class the collection contains.

Override this property to specify the model class that the collection contains. If defined, you can pass raw attributes objects (and arrays) to init, add, push, unshift, create, set and reset, and the attributes will be converted into a model of the proper type.

The default model for a collection is just a UWA.Class.Model. This should be overridden in most cases.

Override this property with a value that is:

You can override this property:

  • When sub-classing the UWA.Class.Collection class,
  • When constructing an instance of collection, passing a model option in the options hash of the constructor (see constructor doc)
Type
  • UWA/Class/Model
Example
// provided that you have defined WorkOfArt model class :
var Museum = UWA.Class.Collection.extend({
    model: WorkOfArt
});

// provided that you have defined a Player model class :
var footballTeam = new UWA.Class.Collection([], {
    model: Player
});

// provided that you have defined Triangle and TriangleV2 model classes,
// and a global Application object :
var Mesh = UWA.Class.Collection.extend({
    model: function (attrs, options) {
        if (Application.version >= 2) {
            return new TriangleV2(attrs, options);
        } else {
            return new Triangle(attrs, options);
        }
    }
});

Methods

clone() → {UWA.Class.Collection}

Returns a new instance of the collection with an identical list of models.

Notes:

  • the original collection and its clone share references to the same models (see code example below).
  • the cloned collection does not register any of the listeners registered by the original collection.
Example
var fruits, clonedFruits; // collections of fruits

// five fruits per day !
fruits = new Collection([{
    type: 'Banana'
}, {
    type: 'Orange'
}, {
    type: 'Strawberry'
}, {
    type: 'Apple'
}, {
    type: 'Mango'
}]);

UWA.log(fruits.first().get('type')); // outputs 'Banana'

clonedFruits = fruits.clone();

// A change on a model referenced by the cloned collection
// is also visible to the original collection :

clonedFruits.first().set('type', 'Pinapple');

UWA.log(fruits.first().get('type')); // outputs 'Pinapple'

// Adding models to the cloned collection does not affect
// the original collection :

clonedFruits.push({
    type: 'Lemon'
});

UWA.log(fruits.first().get('type')); // outputs 'Pinapple'
Returns
  • A new instance of the collection with an identical list of models.
Type
UWA.Class.Collection

setup()

Override this method to initialize a newly created instance of collection.

Do not directly call setup in your application code. It is internally used and consequently only meant to be overridden

The default implementation does nothing.

Overriding it with you own initialization logic is optional; however it is a good practice to implement it when sub-classing a collection.

It is passed the same arguments that were passed to the constructor init method.

Example
var TodoList = UWA.Class.Collection.extend({

    // this collection contains Todo models :
    model: Todo,

    // When a TodoList is modified (or its Todos themselves), we want
    // to maintain a reference to the most important todo
    // let's bind our internal callbacks in the implementation of setup,
    // this is the appropriate place for that :
    setup: function (models, options) {
        this.addEvents({
            onRemove: this._onRemove,
            onAdd: this._onAdd,
            'onChange:priority': this._onChange
        }, this);
        this._topTodo = null;
        this._topTodoWeight = UWA.is(options.weightMinorant, 'number') ? options.weightMinorant : -1;
    },

    // ...
});

var Tasks = new TodoList([], {
    weightMinorant: -1
});

sync(method, collection, options) → {Object}

Override this method to implement, customize or fine-tune the manner in which a collection resource data is fetched from the backend.

Do not directly call sync in your application code. It is internally used by fetch and consequently only meant to be overridden

By default, sync makes a GET RESTful Ajax request to the collection's url, using UWA.Data.request API under the cover, to fetch the collection resource data. Consequently an error will be thrown if the collection does not have an URL and no url is passed as an option in the options hash.

Can be overridden for custom behavior. In this case, you have to respond to a "read" operation request (made by fetch) by sending back an array of model attribute objects to options.onComplete success callback and returning a request object that contains a cancel method, allowing to cancel the request made to the backend (if feasible).

Example
  // This is an (uncomplete) implementation reading some data collection
  // from the local storage.

  var MyCollection, myCollec, keys = [], len = 10;

  MyCollection = UWA.Class.Collection.extend({
      sync: function (method, collection, options) {
          var resp, errorMessage, name = 'MyCollection';

          try {
              switch (method) {
              case "read":
                  resp = localStorage.getItem(name).split(',').map(function (id) {
                      data = localStorage.getItem(name + "-" + id);
                      return data && JSON.parse(data);
                  }, this).filter(function (attrs) {
                      return attrs; // Remove all falsy values
                  }, this);
                  break;
              default:
                  throw new Error(UWA.String.format('Unsupported method "{0}"', method));
              }

          } catch (error) {
              errorMessage = error.message;
          }

          if (resp) {
              if (options && options.onComplete) {
                  options.onComplete(resp);
              }
          } else {
              if (options && options.onFailure) {
                  options.onFailure(errorMessage || 'Unknown error');
              }
          }

          // return an obj with a dummy cancel() method,
          // because in this implementation of sync() we synchronously
          // call options.onComplete, cancel is a no-op.
          return {
              cancel: function () {
                  return;
              }
          };
      }
  });

  // Initialize the localStorage content :
  for (i = 1; i <= len; i++) {
      localStorage.setItem(name + '-' + i, JSON.stringify({
          attr: Math.random().toString(36).substring(7);
      }));
      keys.push(i);
  }
  localStorage.setItem(name, keys.join(','));

  // create a collection and fetch its content.
  // This will call our implementation of sync for the operation
  // "read" :
  myCollec = new MyCollection();
  myCollec.fetch({
      onComplete: function (collec, response, options) {
          UWA.log(myCollec.toJSON());
      }
  });
Parameters
Name Type Argument Description
method String

the CRUD method, that should be "read"

collection Object

the collection to be read

options Object <optional>

onComplete and onFailure callbacks, and all other options for UWA.Data.request

Returns
  • a request object that contains the cancel method, allowing to cancel the request made to the backend.
Type
Object

parse(response, options) → {Array}

Override this method to transform the backend response into an array of models.

Do not directly call parse in your application code. It is internally used and consequently only meant to be overridden

parse is called whenever a collection's models are returned by the backend, in fetch. parse is passed the raw response object, and should return the array of model attributes to be added to the collection. The default implementation is a no-op, simply passing through the JSON response.

Override this if you need to work with a preexisting backend API, or better namespace your backend responses

Example
var Tweets = UWA.Class.Collection.extend({
    // Twitter's GET search/tweets API 1.1 returns tweets under "statuses",
    // so let's implement parse() to get the tweets under "statuses" ! :
    parse: function (response) {
        return response.statuses;
    }
});
Parameters
Name Type Argument Description
response Object

the raw response object returned by the backend API.

options Object <optional>

an hash of options passed by caller set

Returns
  • the array of model attributes to be added to the collection.
Type
Array

add(models, options) → {UWA/Class/Model|Array|Boolean}

Insert a model or an array of models inside this collection.

add fires "onAdd" events. You can use the option {silent: true} to suppress the emission of the "onAdd" event(s).

If a model property is defined on this collection, you may also pass raw attributes objects, and have them be vivified as instances of the model.

If this collection is sortable, model(s) is(are) inserted in this collection so that it remains sorted. Pass {sort: false} so that sorting is disabled when the model(s) is(are) added.

Pass {at: index} to splice the model into the collection at the specified index. Note that sorting is disabled with with this option.

If you're adding models to the collection that are already in the collection, they'll be ignored, unless you pass {merge: true}, in which case their attributes will be merged into the corresponding models, firing any appropriate "onChange" events.

Parameters
Name Type Argument Description
models UWA/Class/Model | Array

a model or an array of models. Or raw attributes object(s) if a model property is defined on this collection.

options Object <optional>

an hash of options, see description above. It will also be passed to the listeners of fired "onAdd" events.

Returns
  • the added (or preexisting (potentially merged), if duplicate) model. Or the array of added (or merged) models. add can also return false or an array containing false values if some models did not pass validation.
Type
UWA/Class/Model | Array | Boolean

push(models, options) → {UWA/Class/Model|Array|Boolean}

Add a model or an array of models at the end of this collection.

If a model property is defined on this collection, you may also pass raw attributes objects, and have them be vivified as instances of the model.

An event "onAdd" is fired (several events if an array is passed), unless you pass the option {silent: true}

This method takes the same options as add, though passing {at: index} will have no effect since models will be necessarily added at the end of this collection. (Sorting is necessarily disabled since we want models to be inserted at the end of the collection).

If you're pushing models that are already in the collection, they will be ignored, unless you pass {merge: true}, in which case their attributes will be merged into the corresponding models, firing any appropriate "onChange" events.

Parameters
Name Type Argument Description
models UWA/Class/Model | Array

a model or an array of models. Or raw attributes object(s) if a model property is defined on this collection

options Object <optional>

an hash of options, see add method for a description. It will also be passed to the listeners of fired "onAdd" events.

Returns
  • the added (or merged) model. Or the array of added (or merged) models. push can also return false or an array containing false values if some models to push did not pass validation.
Type
UWA/Class/Model | Array | Boolean
See:
  • {@link module:UWA/Class/Collection.UWA.Class.Collection#unshift|unshift}, add

unshift(models, options) → {UWA/Class/Model|Array|Boolean}

Add a model or an array of models at the beginning of this collection.

If a model property is defined on this collection, you may also pass raw attributes objects, and have them be vivified as instances of the model.

An event "onAdd" is fired (several events if an array is passed), unless you pass the option {silent: true}

This method takes the same options as add, though passing {at: index} will have no effect since models will be necessarily added at the beginning of this collection. (Sorting is necessarily disabled since we want models to be inserted at the beginning of the collection).

If you're unshifting models that are already in the collection, they will be ignored, unless you pass {merge: true}, in which case their attributes will be merged into the corresponding models, firing any appropriate "onChange" events.

Parameters
Name Type Argument Description
models UWA/Class/Model | Array

a model or an array of models. Or raw attributes object(s) if a model property is defined on this collection

options Object <optional>

an hash of options, see add method for a description. It will also be passed to the listeners of fired "onAdd" events.

Returns
  • the added (or merged) model. Or the array of added (or merged) models. push can also return false or an array containing false values if some models to push did not pass validation.
Type
UWA/Class/Model | Array | Boolean
See:

remove(models, options) → {UWA/Class/Model|Array}

remove remove a model or an array of models from the collection. The models are specified by their ids, their cids, or by passing instances of models.

An event "onRemove" is fired (several events if an array is passed). You can use the option {silent: true} to suppress the emission of these "onRemove" events.

The model's index before removal is available to listeners of this "onRemove" event as options.index

Example
var Cyclist, podium1989, logPodium,
    gregLemond, pedroDelgado, laurentFignon,
    laurent_cid;

Cyclist = UWA.Class.Model.extend({
    idAttribute: 'jerseyNumber'
});

gregLemond = new Cyclist({
    name: 'Greg Lemond',
    jerseyNumber: 141,
    team: 'ADR'
});

pedroDelgado = new Cyclist({
    name: 'Pedro Delgado',
    jerseyNumber: 1,
    team: 'Reynolds-Banesto'
});

laurentFignon = new Cyclist({
    name: 'Laurent Fignon',
    jerseyNumber: 41,
    team: 'Systeme U'
});

laurent_cid = laurentFignon.cid;

podium1989 = new UWA.Class.Collection([ gregLemond,
                                        laurentFignon,
                                        pedroDelgado], {
                                            model: Cyclist
                                        });

logPodium = function (removedCyclist, cyclists, options) {
    var removedCyclistName = removedCyclist.get('name');
    UWA.log(UWA.String.format("{0} got removed from classification because of {1}", removedCyclistName, options.reason));
    UWA.log("The podium is now :");
    UWA.log(JSON.stringify(cyclists));
};

podium1989.addEvent('onRemove', logPodium);

podium1989.remove(1, {
    reason: 'doping'
});

// This logs :
//
// Pedro Delgado got removed from classification because of doping :
// The podium is now :
// [{
//      "name":"Greg Lemond",
//      "jerseyNumber":141,
//      "team":"ADR"
//   }, {
//      "name":"Laurent Fignon",
//      "jerseyNumber":41,
//      "team":"Systeme U"
// }]


podium1989.remove([gregLemond, laurent_cid], {
    reason: 'non-compliant equipment'
});

// This logs (2 events fired) :
//
// Greg Lemond got removed from classification because of non-compliant equipment
// The podium is now :
// [{
//      "name":"Laurent Fignon",
//      "jerseyNumber":41,
//      "team":"Systeme U"
// }]
// Laurent Fignon got removed from classification because of non-compliant equipment
// The podium is now :
// []
Parameters
Name Type Argument Description
models UWA/Class/Model | String

an id, an instance of UWA.Class.Model or a cid, identifying a model in the collection. Or an array of any of these types of ids.

options Object <optional>

an hash of options, see available options above. It will also be passed to the listeners of fired "onRemove" events.

Returns
  • the removed model (undefined if model to be removed could not
      be found) or the array of removed models (can contain some
      undefined values if some models to remove could not be found).
Type
UWA/Class/Model | Array

pop(options) → {Object}

Remove and return the last model from the collection.

It takes the same options as remove and also fires an "onRemove" event, unless {silent: true} is passed as an option.

Parameters
Name Type Argument Description
options Object <optional>

an hash of options, see remove method for a description.

Returns
  • The removed model.
Type
Object

shift(options) → {Object}

Remove and return the first model from a collection.

It takes the same options as remove and also fires an "onRemove" event, unless {silent: true} is passed as an option.

Parameters
Name Type Argument Description
options Object <optional>

an hash of options, see remove method for a description.

Returns
  • The removed model.
Type
Object

sort(options) → {Object}

Force the collection to re-sort itself.

You don't need to call this under normal circumstances, as a collection with a comparator will sort itself whenever a model is added.

However, there are two cases where the sort order will not be maintained : Sorting can be disabled when a model is added, if {sort: false} is passed to add. If some attributes values change in a model, the collection's models may not be correctly sorted anymore.

In this cases, you may need to call this sort method, to force the collection to re-sort itself.

Note that in the second case, automatic re-sorting on a model attribute change can be easily added on a per-collection basis, but be aware of the performance hit ! :

var collection = new UWA.Class.Collection([], {
   comparator: 'attrName'
});
collection.addEvent('onChange:' + collection.comparator, function (model, val, options) {
    this.sort(options);
});

Calling sort triggers a "onSort" event on the collection.

This method will throw an error if a comparator property has not been defined on this collection.

Example
var ContactModel, contactData, contacts;

ContactModel = UWA.Class.Model.extend({
    idAttribute: 'lastName'
});

contactData = [{
    firstName: 'John',
    lastName: 'Deere',
    phone: '1-111-1111'
}, {
    firstName: 'Jane',
    lastName: 'Eyre',
    phone: '2-222-2222'
}, {
    firstName: 'Jude',
    lastName: 'Law',
    phone: '3-333-3333'
}];

contacts = new UWA.Class.Collection(contactData, {
    model:ContactModel,
    comparator: 'firstName' // keep models sorted by firstName
});

UWA.log(JSON.stringify(contacts));

// The created collection is sorted, despite original data
// wasn't :
// [{
//     "firstName": "Jane",
//     "lastName": "Eyre",
//     "phone": "2-222-2222"
// }, {
//     "firstName": "John",
//     "lastName": "Deere",
//     "phone": "1-111-1111"
// }, {
//     "firstName": "Jude",
//     "lastName": "Law",
//     "phone": "3-333-3333"
// }]

contacts.get('Deere').set('firstName', 'Zlatan');
contacts.add({
    firstName: 'Jacob',
    lastName: 'Delafon',
    phone: '4-444-4444'
}, {
    sort: false
});

UWA.log(JSON.stringify(contacts));

// At this point, the collection order has not been
// maintained at all :
// [{
//     "firstName": "Jane",
//     "lastName": "Eyre",
//     "phone": "2-222-2222"
// }, {
//     "firstName": "Zlatan",
//     "lastName": "Deere",
//     "phone": "1-111-1111"
// }, {
//     "firstName": "Jude",
//     "lastName": "Law",
//     "phone": "3-333-3333"
// }, {
//     "firstName": "Jacob",
//     "lastName": "Delafon",
//     "phone": "4-444-4444"
//  }]

contacts.sort();

UWA.log(JSON.stringify(contacts));

// The collection has been re-sorted :
// [{
//     "firstName": "Jacob",
//     "lastName": "Delafon",
//     "phone": "4-444-4444"
// }, {
//     "firstName": "Jane",
//     "lastName": "Eyre",
//     "phone": "2-222-2222"
// }, {
//     "firstName": "Jude",
//     "lastName": "Law",
//     "phone": "3-333-3333"
// }, {
//     "firstName": "Zlatan",
//     "lastName": "Deere",
//     "phone": "1-111-1111"
// }]
Parameters
Name Type Argument Description
options Object <optional>

an hash of options, that will be passed to listeners of the "onSort" event.

Returns
  • {this} instance of collection.
Type
Object
See:

set(models, options) → {UWA/Class/Model|Array|Boolean}

Performs a smart update of the collection with the passed list of models.

The set method performs a smart update of the collection with the passed list of models. Its default behavior is the following:

  • if a model in the list isn't yet in the collection it will be added;
  • if the model is already in the collection its attributes will be merged;
  • and if the collection contains any models that are no longer present in the list, they'll be removed.

In other words, using set will attempt to synchronize the array of models passed in with the internal state of the models in the collection by intelligently deciphering the differences and adding, removing, and merging according to the differences.

All of the appropriate "onAdd", "onRemove", and "onChange" events are fired as this happens.

If you want to customize this default behavior, you can tune it with the following options: {add: false}, {remove: false}, or {merge: false}.

Example
var kingCrimson, // the band
    NMEAnnouncement,
    robert, ian, greg, newGreg, michael, peter, mel, keith, // some members
    Member = UWA.Class.Model.extend({
        idAttribute: 'name'
    });

robert = new Member({
    name: 'Robert Fripp',
    position: 'Lead guitarist'
});

ian = new Member({
    name: 'Ian McDonald',
    position: 'Saxophonist'
});

greg = new Member({
    name: 'Greg Lake',
    position: 'Singer & Bassist'
});

michael = new Member({
    name: 'Michael Giles',
    position: 'Drummer'
});

peter = new Member({
    name: 'Peter Sinfield',
    position: 'Lyricist'
});

mel = new Member({
    name: 'Mel Collins',
    position: 'Flutist'
});

keith = new Member({
    name: 'Keith Tippett',
    position: 'Pianist'
});

// Original line-up :
kingCrimson = new UWA.Class.Collection([
    robert,
    ian,
    greg,
    michael,
    peter
], {
    model: Member
});

NMEAnnouncement = function (template) {
    return function (member) {
        UWA.log(UWA.String.format(template,
                                  member.get('name'),
                                  member.get('position')));
    };
};

kingCrimson.addEvents({
    onAdd: NMEAnnouncement("{0} joined King Crimson as {1}"),
    onRemove: NMEAnnouncement("{0} left King Crimson. He/She was the {1} of the band"),
    'onChange:position': function (member) {
        UWA.log(UWA.String.format("{0} (who was previously the {1}) is now the {2} of King Crimson",
                                  member.get('name'),
                                  member.previous('position'),
                                  member.get('position')));
    }
});

// For the second album, Greg no longer plays the bass,
// Ian left the band and Mel & Keith joined the band.
// So the line-up for the second album is :
kingCrimson.set([
    robert, {
        name: 'Greg Lake',
        position: 'Singer'
    },
    michael,
    peter,
    mel,
    keith
]);

// This will output to the console :

// "Greg Lake (who was previously the Singer & Bassist) is now the Singer of King Crimson"
// "Ian McDonald left King Crimson. He/She was the Saxophonist of the band"
// "Mel Collins joined King Crimson as Flutist"
// "Keith Tippett joined King Crimson as Pianist"
Parameters
Name Type Argument Description
models UWA/Class/Model | Array

(optional) a model or an array of models. Or raw attributes object(s) if a model property is defined on this collection.

options Object <optional>

an hash of options, see description above.

Returns
  • Returns the touched models in the collection, that is to say the added (or merged) model. Or the array of added (or merged) models. set can also return false or an array containing false values if some models did not pass validation.
Type
UWA/Class/Model | Array | Boolean

reset(models, options) → {UWA/Class/Model|Array|Boolean}

Replaces the models in the collection with a new set of model(s).

Adding and removing models one at a time is all well and good, but sometimes you have so many models to change that you'd rather just update the collection in bulk. Use reset to replace a collection with a new list of models (or attribute hashes), triggering a single "onReset" event at the end. It is essentially like removing all model(s) in a collection and adding a new model(s).

For convenience, within a "onReset" event, the list of any previous models is available as options.previousModels.

Calling reset without passing any models as arguments will empty the entire collection.

Parameters:

Example
var Even, evens, newlySetModels;

Even = UWA.Class.Model.extend({
    validate: function (attrs) {
        if (attrs.id % 2 !== 0) {
            return "odd";
        }
    }
});

evens = new UWA.Class.Collection([{
    id: 2
}, {
    id: 4
}, {
    id: 6
}], {
    model: Even
});

UWA.log(evens.length); // outputs 3.

newlySetModels = evens.reset([{
    id: 7
}, {
    id: 2
}, {
    id: 10
}], {
    validate: true
});

UWA.log(JSON.stringify(newlySetModels));
// outputs [false,{"id":2},{"id":10}]

UWA.log(evens.length); // outputs 2.
Parameters
Name Type Argument Description
models UWA/Class/Model | Array <optional>

a model or an array of models. Or raw attributes object(s) if a model property is defined on this collection.

options Object <optional>

an hash of options.

Returns
  • the added model. Or the array of added models. reset can also return false or an array containing false values if some models did not pass validation.
Type
UWA/Class/Model | Array | Boolean
See:
  • add, {@link module:UWA/Class/Collection.UWA.Class.Collection#remove|remove}

get(obj) → {UWA/Class/Model|undefined}

Get a model from the collection.

Get a model from the collection, specified by an id, a cid, or by passing in a model.

Example
var contactRawData, contact, contacts;

contactRawData = {
    id: '01',
    firstName: 'John',
    lastName: 'Doe',
    phone: '1-111-1111'
};

contact = new UWA.Class.Model(contactRawData);

contacts = new UWA.Class.Collection([contact]);

// All of the below return a reference to the contact model in
// the contacts collection, using get() :

UWA.log(contacts.get(contact));
UWA.log(contacts.get(contactRawData.id));
UWA.log(contacts.get(contact.cid));
Parameters
Name Type Description
obj String | UWA/Class/Model

an id, an instance of UWA.Class.Model or a cid, identifying a model in the collection.

Returns
  • The model, if found. Undefined, if not found.
Type
UWA/Class/Model | undefined

at(index) → {UWA/Class/Model|undefined}

Return a model from a collection, given a position.

Useful if your collection is sorted, and if your collection isn't sorted, at will still retrieve models in insertion order.

Notes:

  • To retrieve the last item of the collection, use last.
  • To retrieve the first item of the collection, use first.
Parameters
Name Type Description
index Integer

the zero-based index

Returns
  • The model or undefined, if the index is out of bounds.
Type
UWA/Class/Model | undefined
See:

first(n) → {UWA/Class/Model|Array}

Returns the first model of the collection.

Passing N will return the first N models in the collection.

Parameters
Name Type Argument Default Description
n Integer <optional>
1

The number of first models in the collection to return.

Returns
  • The first model of the collection or an array of the first n models.
Type
UWA/Class/Model | Array
See:
  • {@link module:UWA/Class/Collection.UWA.Class.Collection#last|last}

last(n) → {UWA/Class/Model|Array}

Returns the last model of the collection.

Passing N will return the last N models in the collection.

Parameters
Name Type Argument Default Description
n Integer <optional>
1

The number of last models in the collection to return.

Returns
  • the last model of the collection or an array of the last n models.
Type
UWA/Class/Model | Array
See:

toArray() → {Array}

Returns a shallow copy of all the models in the collection, as an array.

toArray returns a new "one-level deep" copy (as an array) that contains copies of references of the models of the collection. Consequently both the collection and the returned array refer to the same models.

  • If a referenced model changes, the changes are visible to both the copy returned by toArray and the original collection.

  • If a new model is added to the collection (with add for example), a copy previously returned by toArray is not affected.

  • If a new model is added to the copy returned by toArray, the collection is not affected.

Returns
  • a shallow copy of all the models in the collection, as an array.
Type
Array
See:

slice(begin, end) → {Array}

Returns a portion of the collection as an array of models.

slice does not alter the collection, but copies reference of models sliced from the collection into the new returned array. Consequently both the collection and the new returned array refer to the same models.

  • If a referenced model changes, the changes are visible to both the returned slice and the original collection.
  • If a new model is added to the collection (with add for example), a previously returned slice is not affected.
  • If a new model is added to returned slice, the collection is not affected.
Example
// A fruity example
var salad1, salad2, salad3, // arrays of fruits
    listSaladIngredients, raspberryIdx,
    fruits; // collection of fruits

// five fruits per day !
fruits = new Collection([{
    type: 'Banana'
}, {
    type: 'Orange'
}, {
    type: 'Strawberry'
}, {
    type: 'Apple'
}, {
    type: 'Mango'
}]);

listSaladIngredients = function (salad) {
    UWA.log(salad.map(function (fruit) {
        return fruit.get('type');
    }).join(' + '));
};

salad1 = fruits.slice(-2);
listSaladIngredients(salad1);
// outputs "Apple + Mango"

salad2 = fruits.slice(1, 4);
listSaladIngredients(salad2);
// outputs "Orange + Strawberry + Apple"

salad3 = fruits.slice(2, -1);
listSaladIngredients(salad3);
// outputs "Strawberry + Apple"

// let's mutate the strawberry into a raspberry in
// our fruits collection :
fruits.findWhere({
    type: 'Strawberry'
}).set('type', 'Raspberry');

listSaladIngredients(salad2);
// outputs "Orange + Raspberry + Apple"

listSaladIngredients(salad3);
// outputs "Raspberry + Apple"

// Oops, we shouldn't play with the genes,
// let's find the raspberry in the latest salad array ...
raspberryIdx = -1;
if (salad3.some(function (fruit, idx, salad) {
    if (fruit.get('type') === 'Raspberry') {
        raspberryIdx = idx;
        return true;
    }
    return false;
})) {
    // ... and mutate it back into a Strawberry :
    salad3[raspberryIdx].set('type', 'Strawberry');
}

fruits.findWhere({
    type: 'Raspberry'
}); // return undefined

UWA.is(fruits.findWhere({
    type: 'Strawberry'
})); // returns true
Parameters
Name Type Argument Default Description
begin Integer <optional>
0

Zero-based index at which to begin extraction. As a negative index, begin indicates an offset from the end of the collection. If begin is omitted, slice begins from index 0.

end Integer <optional>

Zero-based index at which to end extraction. slice extracts up to but not including end. As a negative index, end indicates an offset from the end of the collection. If end is omitted, slice extracts to the end of the collection.

Returns
  • The portion of models sliced from the collection.
Type
Array

rest(n) → {Array}

Returns all but the N first models in the collection.

rest returns the rest of the models of the collection (its tail) as an array. You can pass an index to return the models of the collection from that index onward. The default behavior of rest is to return all models but the first.

Note that rest does not alter the collection, but copies references of models that formed the tail of collection into the new returned array. Consequently both the collection and the new returned array refer to the same models.

  • If a referenced model changes, the changes are visible to both the returned tail and the original collection.
  • If a new model is added to the collection (with {@link module:UWA/Class/Collection.UWA.Class.Collection#add|add} for example), a previously returned tail is not affected.
  • If a new model is added to returned tail, the collection is not affected.
Example
var daltons;

daltons = new UWA.Class.Collection([{
    firstName: 'Joe'
}, {
    firstName: 'Jack'
}, {
    firstName: 'William'
}, {
    firstName: 'Averell'
}]);

UWA.log(JSON.stringify(daltons.rest()));

// This logs (Joe has been arrested) :
// [{"firstName":"Jack"},{"firstName":"William"},{"firstName":"Averell"}]
Parameters
Name Type Argument Description
n Integer <optional>

to return the models of the collection from that index onward.

Returns
  • An array of the rest of the models of the collection.
Type
Array
See:

initial(n) → {Array}

Returns all but the N last models in the collection.

initial returns as an array all models but the last model in the collection (default behavior). You can pass an index N to exclude the last N elements from the result. The default behavior of rest is to return all models but the first (n=1 by default)

Note that initial does not alter the collection, but copies references of models into the new returned array. Consequently both the collection and the new returned array refer to the same models.

  • If a referenced model changes, the changes are visible to both the returned array and the original collection.

  • If a new model is added to the collection (with {@link module:UWA/Class/Collection.UWA.Class.Collection#add|add} for example), a previously returned array is not affected.

  • If a new model is added to returned array, the collection is not affected.

Example
var daltons;

daltons = new UWA.Class.Collection([{
    firstName: 'Joe'
}, {
    firstName: 'Jack'
}, {
    firstName: 'William'
}, {
    firstName: 'Averell'
}]);

UWA.log(JSON.stringify(daltons.initial(2)));

// This logs :
[{"firstName":"Joe"},{"firstName":"Jack"}]
Parameters
Name Type Argument Description
n Integer <optional>

to exclude the last n models from the returned array.

Returns
  • An array of all models but the N last models of the collection.
Type
Array
See:

without() → {Array}

Returns a copy of the collection with all of the passed instances of models removed.

without returns a copy of the collection with all of the passed instances of models removed.

Note that without does not alter the collection (no models are removed from the collection), but return a copy of references of models except the ones that are passed in. Consequently both the collection and the returned array refer to the same models.

  • If a referenced model changes, the changes are visible to both the copy returned by without and the original collection.
  • If a new model is added to the collection (with {@link module:UWA/Class/Collection.UWA.Class.Collection#add|add} for example), a copy previously returned by without is not affected.
  • If a new model is added to the copy returned by without, the collection is not affected.
Example
var daltons,
    joe, bill,
    wanted;

daltons = new UWA.Class.Collection([{
    name: 'Joe'
}, {
    name: 'Jack'
}, {
    name: 'William'
}, {
    name: 'Averell'
}]);

joe = daltons.findWhere({
    name: 'Joe'
});

bill = daltons.findWhere({
    name: 'William'
});

// During the Federal Bank hold-up, Joe and Bill
// were having fun at the saloon :
wanted = daltons.without(joe, bill);

UWA.log(JSON.stringify(wanted));

// this logs :
// [{"name":"Jack"},{"name":"Averell"}]
Parameters
Type Description
UWA/Class/Model | Array

The models not to return.

Returns
  • a copy of the collection with all of the passed instances of models removed.
Type
Array

indexOf(sought, fromIndex) → {Integer}

Returns the first index at which a given model can be found in the collection.

indexOf compares sought model to models of the collection using strict equality (triple-equals operator), and returns the first index at which a given model can be found in the collection, or -1 if it is not present.

Parameters
Name Type Argument Default Description
sought Object

Model to locate in the collection.

fromIndex Integer <optional>
0

The index to start the search at. If the index is greater than or equal to the collection's length, -1 is returned, which means the collection will not be searched. If the provided index value is a negative number, it is taken as the offset from the end of the collection. Note: if the provided index is negative, the collection is still searched from front to back. If the calculated index is less than 0, then the whole collection will be searched. Defaults to 0 (Entire collection is searched)

Returns
  • The first index at which the model is found in the collection, or -1 if not found.
Type
Integer
See:

lastIndexOf(sought, fromIndex) → {Integer}

Returns the last index at which a model can be found.

lastIndexOf returns the last index at which a given model can be found in the collection, or -1 if it is not present. The array is searched backwards, starting at fromIndex.

lastIndexOf compares sought model to models of the collection using strict equality (triple-equals operator).

Parameters
Name Type Argument Description
sought Object

Model to locate in the collection.

fromIndex Integer <optional>

The index to start searching backwards. Defaults to the collection's length, i.e. the whole collection will be searched. If the index is greater than or equal to the collection's length, the whole collection will be searched. If the provided index value is a negative number, it is taken as the offset from the end of the collection. Note that even when the index is negative, the collection is still searched from front to back. If the calculated index is less than 0, -1 is returned, i.e. the collection will not be searched.

Returns
  • The last index at which a given element can be found in the collection, or -1 if it is not present.
Type
Integer
See:

contains(model) → {Boolean}

Returns true if the model is present in the collection.

Parameters
Name Type Description
model UWA/Class/Model

Model to search in the collection.

Returns
  • true if the passed model is present in the collection, false otherwise.
Type
Boolean
See:

size() → {Integer}

Returns the number of models in the collection.

Returns
  • The number of models in the collection.
Type
Integer

isEmpty() → {Boolean}

Returns true if the collection contains no model.

Returns
  • True if the collection contains no model.
Type
Boolean

toJSON(options) → {Array}

Returns an array containing the attributes hash of each model in the collection.

This method returns an array containing the return value of each Model's toJSON method in the collection, which by default will be its attributes hash. This can be used to serialize and persist the collection as a whole.

Note that the name of this method is a bit confusing (since its does not actually returns a JSON string), but it conforms to JavaScript s JSON API at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify, in that way that it will be called by JSON.stringify to determine the collection's JSON representation.

Specified options will be passed to each model's toJSON method.

Example
var collection = new UWA.Class.Collection([
  {name: "Tim", age: 5},
  {name: "Ida", age: 26},
  {name: "Rob", age: 55}
]);

UWA.log(JSON.stringify(collection));
Parameters
Name Type Argument Description
options Object <optional>

an hash of options that will be passed to each model's toJSON method.

Returns
  • An array containing the attributes hash of each model in the collection.
Type
Array

pluck(attrName) → {Array}

Pluck an attribute from each model in the collection.

pluck is a very handy method that picks up an attribute from each model in the collection of models and returns an array of all the values for this specific attribute in the collection. This is equivalent to calling map and returning a single attribute from the callback.

Example
var daltons, msg;

daltons = new UWA.Class.Collection([{
    firstName: 'Joe',
    size: '4ft6in'
}, {
    firstName: 'Jack',
    size: '5ft6in'
}, {
    firstName: 'William',
    size: '6ft4in'
}, {
    firstName: 'Averell',
    size: '7ft'
}]);

msg = "The Daltons are " + daltons.pluck('firstName').join(',');
UWA.log(msg);
Parameters
Name Type Description
attrName String

The name of the attribute to pluck.

Returns
  • An array of all the values in this collection for this specific attribute.
Type
Array

shuffle() → {Array}

Returns a shuffled copy of the collection models as an array.

shuffle returns a shuffled copy of the collection models, as an array, using a version of the Fisher-Yates shuffle.

Returns
  • A shuffled copy of the collection's models.
Type
Array

where(attrs) → {Array}

Return an array of all the models in the collection that match the passed attributes.

Useful for simple cases of filter.

Example
var friends, musketeers;

friends = new UWA.Class.Collection([{
    name: "Athos",
    job: "Musketeer"
}, {
    name: "Porthos",
    job: "Musketeer"
}, {
    name: "Aramis",
    job: "Musketeer"
}, {
    name: "d'Artagnan",
    job: "Guard"
}]);

musketeers = friends.where({
    job: "Musketeer"
});

UWA.log(musketeers.length); // this logs '3'
Parameters
Name Type Description
attrs Object

an hash of attributes to filter the models.

Returns
  • all the models in the collection that match the passed attributes. An empty array if there is no match.
Type
Array
See:

findWhere(attrs) → {Object}

Returns the first model in the collection that matches the passed attributes.

findWhere is just like where, but it directly returns only the first model in the collection that matches the passed attributes.

Parameters
Name Type Description
attrs Object

an hash of attributes to find the model.

Returns
  • The first model in the collection that matches the passed attributes. Undefined if not found.
Type
Object
See:
  • where, {@link module:UWA/Class/Collection.UWA.Class.Collection#find|find}

invoke(methodName, Other) → {Array}

Invoke a provided model method name once per model of the collection.

invoke calls the model method named by methodName on each model in the collection, and returns the array of results. Any extra arguments passed to invoke will be forwarded on to the method invocation.

Example
var shoppingList;

shoppingList = new UWA.Class.Collection([{
    name: 'bananas'
              }, {
                  name: 'washing powder'
              }, {
                  name: 'eggs'
              }, {
                  name: 'pen'
}]);
// This will set the attribute 'quantity' to 1 on all items in
// the shopping list :
shoppingList.invoke('set', 'quantity', 1);
Parameters
Name Type Description
methodName String

the name of a method of the model

Other Void

parameters - parameters passed to the method call.

Returns
  • The list of the results of method call.
Type
Array

forEach(callback, context)

Executes a provided function once per model of the collection.

forEach executes the provided callback function once for each model of the collection.

Notes:

  • If a context parameter is provided to forEach, it will be used as the this value for each callback invocation as if callback.call(context, model, index, models) was called. If context is undefined or null, the this value within the function depends on whether the function is in strict mode or not (passed value (undefined or null) if in strict mode, global object if in non-strict mode).
  • There is no way to stop or break a forEach loop. The solution is to use every or some.
  • To prevent potential unwanted side effects (like corrupting the collection), as a rule of thumb :
    • you should not (in your callback implementation) add or remove models from the list passed as third argument to callback.
    • most of the time, your callback signature should take at most only two arguments (the current model that is visited and its index), this should prevent you from misbehaving.
Example
var daltons;

daltons = new UWA.Class.Collection([{
    name: 'Joe'
}, {
    name: 'Jack'
}, {
    name: 'William'
}, {
    name: 'Averell'
}]);

daltons.forEach(function (dalton, idx) {
    UWA.log(UWA.String.format("Dalton #{0} is {1}", idx+1, dalton.get('name')));
});

// This logs :
// Dalton 1 is Joe
// Dalton 2 is Jack
// Dalton 3 is William
// Dalton 4 is Averell
Parameters
Name Type Description
callback Function

Function to execute for each model. It is invoked with three arguments: - the current model - the index of the current model - the array of models of the collection being traversed (not the collection itself). Please read note above about this argument.

context Object

Object to use as this when executing callback.

map(callback, context) → {Array}

Returns a new array with the results of calling a provided function on every model.

map calls a provided callback function once for each model of the collection, in order, and constructs a new array from the results.

callback is invoked with three arguments:

  • the current model,
  • the index of the current model,
  • and an array of the models being traversed (not the collection itself). Please read notes below about this argument.

callback must return a value of any type.

If a context parameter is provided to map, it will be used as the this for each invocation of the callback. If it is not provided, or is null, the global object associated with callback is used instead.

Notes:

To prevent potential unwanted side effects (like corrupting the collection), as a rule of thumb:

  • you should not (in your callback implementation) add or remove models from the list passed as third argument to callback.
  • most of the time, your callback signature should take at most only two arguments (the current model that is visited and its index), this should prevent you from misbehaving.
Example
var daltons, getSizeInInches,
    cachedRegexp = /^([1-9]\d*)ft(([1-9]\d*)in)?$/,
    footInInches = 12;

daltons = new UWA.Class.Collection([{
    firstName: 'Joe',
    size: '4ft6in'
}, {
    firstName: 'Jack',
    size: '5ft6in'
}, {
    firstName: 'William',
    size: '6ft4in'
}, {
    firstName: 'Averell',
    size: '7ft'
}]);

getSizeInInches = function (dalton) {
    var matchingGroups = dalton.get('size').match(cachedRegexp);
    return parseInt(matchingGroups[1], 10)*footInInches + parseInt(matchingGroups[3] || 0, 10);
};

UWA.log(JSON.stringify(daltons.map(getSizeInInches)));

// This logs :
// [54,66,76,84]
Parameters
Name Type Description
callback Function

Function to execute for each model. It is invoked with three arguments: - the current model - the index of the current model - the array of models of the collection being traversed (not the collection itself). Please read note above about this argument.

context Object

Object to use as this when executing callback.

Returns
  • a new array with the results of calling callback on every model.
Type
Array

every(callback, context) → {Boolean}

Tests whether all models in the collection pass the test implemented by the provided function.

every executes the provided callback function once for each model present in the collection until it finds one where callback returns a falsy value (a value that becomes false when converted to a Boolean). If such a model is found, every immediately returns false. Otherwise, every returns true, meaning that the provided callback function returned true for all models of the collection.

callback is invoked with three arguments:

  • the current model,
  • the index of this current model,
  • and an array of the models being traversed.

If a context parameter is provided to every, it will be used as the this for each invocation of the callback. If it is not provided, or is null, the global object associated with callback is used instead.

Notes:

To prevent potential unwanted side effects (like corrupting the collection), as a rule of thumb:

  • you should not (in your callback implementation) add or remove models from the list passed as third argument to callback.
  • most of the time, your callback signature should take at most only two arguments (the current model that is visited and its index), this should prevent you from misbehaving.
Parameters
Name Type Description
callback Function

Function to execute for each model. It is invoked with three arguments: - the current model - the index of the current model - the array of models of the collection being traversed (not the collection itself). Please read note above about this argument.

context Object

Object to use as this when executing callback.

Returns
  • false if at least one model does not pass the test implemented by callback, true otherwise.
Type
Boolean

some(callback, context) → {Boolean}

Tests whether some model in the collection passes the test implemented by the provided function.

some executes the callback function once for each model present in the collection until it finds one where callback returns a true value. If such a model is found, some immediately returns true. Otherwise, some returns false.

Callback is invoked with three arguments:

  • the current model,
  • the index of this current model,
  • and an array of the models being traversed.

If a context parameter is provided to some, it will be used as the this for each invocation of the callback. If it is not provided, or is null, the global object associated with callback is used instead.

{@link module:UWA/Class/Collection.UWA.Class.Collection#some|some} does not mutate the collection on which it is called (read notes below though), unless of course your callback modifies models.

Notes:

To prevent potential unwanted side effects (like corrupting the collection), as a rule of thumb:

  • you should not (in your callback implementation) add or remove models from the list passed as third argument to callback.
  • most of the time, your callback signature should take at most only two arguments (the current model that is visited and its index), this should prevent you from misbehaving.
Parameters
Name Type Description
callback Function

Function to execute for each model. It is invoked with three arguments: - the current model - the index of the current model - the array of models of the collection being traversed (not the collection itself). Please read note above about this argument.

context Object

Object to use as this when executing callback.

Returns
  • true if at least one model passes the test implemented by callback, false otherwise.
Type
Boolean

sortBy(hash, context) → {Array}

Returns a sorted copy of the collection's models.

sortBy returns a stably sorted copy of the collection's models, ranked in ascending order by the results of running each model through the passed 'hash' function. Hash may also be the string name of a model attribute to sort by.

Note that the collection and the returned sorted array reference the same models

Notes: sortBy does not make use of the comparator property at all.

Example
var daltons,
    daltonsByAscendingName, daltonsByAscendingSize,
    cachedRegexp,
    footInInches = 12;

daltons = new UWA.Class.Collection([{
    firstName: 'Joe',
    size: '4ft6in'
}, {
    firstName: 'Jack',
    size: '5ft6in'
}, {
    firstName: 'William',
    size: '6ft4in'
}, {
    firstName: 'Averell',
    size: '7ft'
}]);

daltonsByAscendingName = daltons.sortBy('firstName');

UWA.log(JSON.stringify(daltonsByAscendingName));

// [{
//      "firstName":"Averell",
//      "size":"7ft"
//  }, {
//      "firstName":"Jack",
//      "size":"5ft6in"
//  }, {
//      "firstName":"Joe",
//      "size":"4ft6in"
//  }, {
//      "firstName":"William",
//      "size":"6ft4in"
//  }]

cachedRegexp = /^([1-9]\d*)ft(([1-9]\d*)in)?$/;
daltonsByAscendingSize = daltons.sortBy(function (dalton) {
    var matchingGroups = dalton.get('size').match(cachedRegexp);
    return parseInt(matchingGroups[1], 10)*footInInches + parseInt(matchingGroups[3] || 0, 10);
});

UWA.log(JSON.stringify(daltonsByAscendingSize));

// [{
//      "firstName":"Joe",
//      "size":"4ft6in"
//  }, {
//      "firstName":"Jack",
//      "size":"5ft6in"
//  }, {
//      "firstName":"William",
//      "size":"6ft4in"
//  }, {
//      "firstName":"Averell",
//      "size":"7ft"
//  }]

// Note that daltons collection remained unchanged.
Parameters
Name Type Description
hash String | Function

The string name of a model attribute to sort by. Or a function to execute on each model in the collection to return a hash value (of any type: numerical, string, logical, or object). Hash takes a model as argument.

context Object

Object to use as this when executing hash.

Returns
  • A sorted copy of the collection's models.
Type
Array

groupBy(hash, context) → {Object}

Splits the collection into sets.

groupBy splits the collection into sets, grouped by the result of running each model through hash.

If hash is a string instead of a function, groups by the property named by hash on each of the model.

The collection and the returned object (associative array) reference the same models

The collection and all its models are left unmodified by this method.

Example
var CartItem, cartList, cartsByComCode;

CartItem = UWA.Class.Model.extend({

    defaults: {
        plucode: 0,
        title: 'cnpdx.cart',
        discount: 100,
        qty: 5,
        price: 100,
        extendcode: 0,
        checked: false,
        salemode: 1,
        comcode: 0,
        guide: '3'
    }
});

// a collection with some cartitems:

cartList = new UWA.Class.Collection([{
    plucode: '123454',
    title: 'coffee drinking',
    discount: 80,
    qty: 5,
    price: 10,
    extendcode: '123451,123452',
    salemode: 2,
    comcode: '7-301',
    guide: 3
}, {
    plucode: '123423',
    title: 'photography',
    discount: 80,
    qty: 5,
    price: 100,
    extendcode: '123421,123422',
    salemode: 2,
    comcode: '7-302',
    guide: 3
}, {
    plucode: '123424',
    title: 'coffee drinking',
    discount: 80,
    qty: 5,
    price: 10,
    extendcode: '123421,123422',
    salemode: 2,
    comcode: '7-302',
    guide: 3
}], {
    model: CartItem
});

cartsByComCode = cartList.groupBy('comcode');

UWA.log(JSON.stringify(cartsByComCode));

// This outputs :
// {
//     "7-301": [{
//         "plucode": "123454",
//         "title": "coffee drinking",
//         "discount": 80,
//         "qty": 5,
//         "price": 10,
//         "extendcode": "123451,123452",
//         "salemode": 2,
//         "comcode": "7-301",
//         "guide": 3,
//         "checked": false
//     }],
//
//     "7-302": [{
//         "plucode": "123423",
//         "title": "photography",
//         "discount": 80,
//         "qty": 5,
//         "price": 100,
//         "extendcode": "123421,123422",
//         "salemode": 2,
//         "comcode": "7-302",
//         "guide": 3,
//         "checked": false
//     }, {
//         "plucode": "123424",
//         "title": "coffee drinking",
//         "discount": 80,
//         "qty": 5,
//         "price": 10,
//         "extendcode": "123421,123422",
//         "salemode": 2,
//         "comcode": "7-302",
//         "guide": 3,
//         "checked": false
//     }]
// }
Parameters
Name Type Description
hash String | Function

The string name of a model attribute to sort by. Or a function to execute on each model in the collection to return a hash value (of any type: numerical, string, logical, or object). Hash takes a model as argument.

context Object

Object to use as this when executing hash.

Returns
  • An object (aka associative array) which keys are the ones computed by the hash argument and which values are arrays of models (the sets/groups).
Type
Object

countBy(hash, context) → {Object}

Sorts the collection into groups and returns a count of models in each group

groupBy is similar to groupBy, but instead of returning a list of models, returns a count for the number of models in that group.

If hash is a string instead of a function, groups by the property named by hash on each of the model.

The collection and the returned object (associative array) reference the same models

The collection and all its models are left unmodified by this method.

Example
var BugReport, Backlog, rawBacklogData, myBacklog;

BugReport = (function () {

    var states, releaseNumberRegExp, ownerTrigramRegExp;

    states = {
        open: 'Open',
        underAnalysis: 'Under Analysis',
        rejected: 'Rejected',
        fixed: 'Fixed'
    };

    // cached RegExp for releases numbers :
    releaseNumberRegExp = /^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/;

    // cached RegExp for owner bi/trigram :
    ownerTrigramRegExp = /^[a-zA-Z][a-zA-Z0-9]{1,2}$/;

    return UWA.Class.Model.extend({
        defaults: {
            abstract: '',
            state: 'open',
            owner: '',
            release: ''
        },
        validate: function(attrs, options) {
            if (!UWA.owns(states, attrs.state)) {
                return UWA.String.format('Invalid state "{0}"', attrs.state);
            }
            if (!releaseNumberRegExp.test(attrs.release)) {
                return UWA.String.format('Invalid release number "{0}"', attrs.release);
            }
            if (!attrs.abstract) {
                return UWA.String.format('Invalid abstract "{0}"', attrs.abstract);
            }
            if (!ownerTrigramRegExp.test(attrs.owner)) {
                return UWA.String.format('Invalid owner trigram "{0}"', attrs.owner);
            }
        }
    });
})();

Backlog = UWA.Class.Collection.extend({
    model: BugReport,

    logStatistics: function () {
        var statLog, stats, attrValues, lastAttrValIdx;
        // This is a way (probably not the cleanest) to access BugReport's metadatas :
        Object.keys(this.model.prototype.defaults).forEach(function (attrName) {
            if (attrName === 'abstract') return; // no stats concerning abstracts !
            statLog = attrName + ': ';
            stats = this.countBy(attrName);
            attrValues = Object.keys(stats);
            lastAttrValIdx = attrValues.length - 1;
            attrValues.forEach(function (attrVal, idx) {
                var count;
                count = stats[attrVal];
                statLog += UWA.String.format('{0} bugs are {1}{2}', count, attrVal, idx < lastAttrValIdx ? ', ' : '.');
            });
            UWA.log(statLog);
        }, this);
    }
});

// some raw json data from osyrix :
rawBacklogData = [{
    abstract: 'UWA.Class.Model is bug-free',
    state: 'open',
    owner: 'XXS',
    release: '2.0.3'
}, {
    abstract: 'UWA.Class.Collection does not make Coffee',
    state: 'underAnalysis',
    owner: 'LRG',
    release: '2.0.4'
}, {
    abstract: 'UWA.Class.Collection of bugs',
    state: 'open',
    owner: 'WTF',
    release: '2.0.0'
}, {
    abstract: 'UWA.Class.Events did not wake me up this morning',
    state: 'fixed',
    owner: 'AAA',
    release: '2.0.1'
}, {
    abstract: 'UWA.Class.View the future',
    state: 'fixed',
    owner: 'BBB',
    release: '2.0.0'
}, {
    abstract: 'UWA.Class.Model kit',
    state: 'rejected',
    owner: 'LRG',
    release: '2.0.1'
}, {
    abstract: 'UWA.Class.Collection is empty',
    state: 'underAnalysis',
    owner: 'LRG',
    release: '2.0.9'
}];

myBacklog = new Backlog([]);

myBacklog.addEvent('onValidationFailure', function (backlog, error, options) {
    UWA.log('failed to create model because ' + error);
});

myBacklog.set(rawBacklogData, {
    validate: true
}).logStatistics();

// this logs :

// state: 2 bugs are open, 2 bugs are underAnalysis, 2 bugs are fixed, 1 bugs are rejected.
// owner: 1 bugs are XXS, 3 bugs are LRG, 1 bugs are WTF, 1 bugs are AAA, 1 bugs are BBB.
// release: 1 bugs are 2.0.3, 1 bugs are 2.0.4, 2 bugs are 2.0.0, 2 bugs are 2.0.1, 1 bugs are 2.0.9.
Parameters
Name Type Description
hash String | Function

The string name of a model attribute to sort by. Or a function to execute on each model in the collection to return a hash value (of any type: numerical, string, logical, or object). Hash takes a model as argument.

context Object

Object to use as this when executing hash.

Returns
  • An object (aka associative array) which keys are the ones computed by the hash argument and which values are the counts of models in each group.
Type
Object

find(filter, context) → {Object}

Returns the first model in the collection for which the provided filtering function 'filter' returns true.

Example
var theBeatles, hasTwoPositions;

theBeatles = new UWA.Class.Collection([{
    name: 'Ringo Starr',
    position: 'drummer'
}, {
    name: 'Paul McCarthney',
    position: 'guitarist & singer'
}, {
    name: 'John Lennon',
    position: 'guitarist & singer'
}, {
    name: 'Georges Harrisson',
    position: 'Bassist'
}]);

hasTwoPositions = function (beatle) {
    return beatle.get('position').split(' & ').length > 1;
};

theBeatles.find(hasTwoPositions);

// returns the first Beatle who has two positions,
// Sir Paul McCarthney :
// {
//      name: 'Paul McCarthney',
//      position: 'guitarist & singer'
//  }
Parameters
Name Type Description
filter Function

Function to test each model of this collection. It is passed three parameters : - model : the current model to test - index : the index of the current model in this collection - models : the array of models of this collection

context Object

Object to use as this when executing filter.

Returns
  • The first model in the collection for which the provided filtering function 'filter' returns true. Undefined if not found.
Type
Object
See:

filter(filter, context) → {Array}

Creates a new array with all the models of this collection for which the provided filtering function 'filter' returns true.

Note that filter does not alter the collection (no models are removed from the collection)

Example
// First example, with the Fab Four
var theBeatles, hasTwoPositions;

theBeatles = new Collection([{
    name: 'Ringo Starr',
    position: 'drummer'
}, {
    name: 'Paul McCarthney',
    position: 'guitarist & singer'
}, {
    name: 'John Lennon',
    position: 'guitarist & singer'
}, {
    name: 'Georges Harrisson',
    position: 'Bassist'
}]);

hasTwoPositions = function (beatle) {
    return beatle.get('position').split(' & ').length > 1;
};

theBeatles.filter(hasTwoPositions);

// returns the second and third models in a new array :
//  [{
//      name: 'Paul McCarthney',
//      position: 'guitarist & singer'
//  }, {
//      name: 'John Lennon',
//      position: 'guitarist & singer'
//  }]

// Second example, where we want to return the names of the audiophiles in a contacts book :
var Contact, myContactsBook;

Contact = UWA.Class.Model.extend({
    idAttribute: 'name',
    isInterestedIn: function (interest) {
        var interests = this.get('interests');
        if (UWA.is(interests, 'array')) {
            return interests.indexOf(interest) > -1;
        }
        return false;
    }
});

// define and instanciation at the same time. Don't do that in your code.
myContactsBook = new (UWA.Class.Collection.extend({
    model: Contact,
    listAudiophilesNames: function () {
        return UWA.Array.invoke(this.filter(function (contact) {
            return contact.isInterestedIn('audio');
        }), 'get', 'name');
    }
}))([{
    name: 'Jen',
    interests: ['audio', 'gaming', 'running']
}, {
    name: 'Ben',
    interests: ['skating', 'eating', 'tap-dancing']
}, {
    name: 'Ken',
    interests: ['partying', 'life in plastic', 'audio']
}]);

myContactsBook.listAudiophilesNames(); // returns ["Jen", "Ken"]
Parameters
Name Type Description
filter Function

Function to test each model of this collection. It must return a boolean and it is passed three parameters : - model : the current model to test - index : the index of the current model in this collection - models : the array of models of this collection

context Object

Object to use as this when executing filter.

Returns
  • Returns a new array of models that pass the filter function
Type
Array

reject(filter, context) → {Array}

Returns the models in this collection without the models that the truth test (filter) passes. The opposite of filter.

Note that reject does not alter the collection (no models are removed from the collection).

Example
var theBeatles, isADrummer;

theBeatles = new UWA.Class.Collection([{
    name: 'Ringo Starr',
    position: 'drummer'
}, {
    name: 'Paul McCarthney',
    position: 'guitarist & singer'
}, {
    name: 'John Lennon',
    position: 'guitarist & singer'
}, {
    name: 'Georges Harrisson',
    position: 'Bassist'
}]);

isADrummer = function (beatle) {
    return beatle.get('position') === 'drummer';
};

theBeatles.reject(isADrummer);
// returns all the models, except Ringo.
Parameters
Name Type Description
filter Function

Function to test each model of this collection. It is passed three parameters : - model : the current model to test - index : the index of the current model in this collection - models : the array of models of this collection

context Object

Object to use as this when executing filter.

Returns
  • Returns a new array of models that do not pass the filter function.
Type
Array

reduce(reducer, initialValue, context) → {UWA/Class/Model}

Apply a function against an accumulator and each model to reduce the collection to a single value.

reduce applies a function (passed as reducer) against an accumulator and each model of this collection (from left-to-right) as to reduce this collection to a single value (that is the final value of the accumulator). Note that this collection and all its models are left unmodified by this method.

Example
var theBeatles, creditor;

theBeatles = new UWA.Class.Collection([{
    name: 'Ringo Starr',
    position: 'drummer'
}, {
    name: 'Paul McCarthney',
    position: 'guitarist & singer'
}, {
    name: 'John Lennon',
    position: 'guitarist & singer'
}, {
    name: 'Georges Harrisson',
    position: 'Bassist'
}]);

creditor = function (credits, currentBeatle, idx) {
    credits += currentBeatle.get('name') + " (" + currentBeatle.get('position') + ")";
    if (idx < 3) {
        credits += " & ";
    }
    return credits;
};

theBeatles.reduce(creditor, "The Beatles are ");
// returns "The Beatles are Ringo Starr (drummer) & Paul McCarthney (guitarist & singer)
// & John Lennon (guitarist & singer) & Georges Harrisson (Bassist)"
Parameters
Name Type Argument Description
reducer Function

Iterator function to execute on each model in the collection against an accumulator. It takes four arguments : - previousValue The value previously returned in the last invocation of the reducer function, or initialValue, if supplied. (See below.) - currentModel The current model being processed in this collection. - index The index of the current model being processed in this collection. - models The list of models being reduced (not the collection itself!)

initialValue Object <optional>

Object to use as the first argument to the first call to the reducer function. That is to say this is the initial value of the accumulator. This parameter is optional : If initialValue is provided in the call to reduce, then, the first time reducer is called, previousValue will be equal to initialValue and currentModel will be equal to the first model in this collection. If no initialValue is provided, then previousValue will be equal to the first model in this collection and currentModel will be equal to the second. (note that in this later case, reducer must be a function taking two models to output a new model)

context Object <optional>

The object the reducer will be bound to when called.

Returns
  • The reduced single value of the collection.
Type
UWA/Class/Model

reduceRight(reducer, initialValue, context) → {UWA/Class/Model}

This is the right-associative version of reduce. See reduce for more details about the behavior of this method.

Parameters
Name Type Argument Description
reducer Function

Iterator function to execute on each model in the collection against an accumulator. It takes four arguments : - - previousValue The value previously returned in the last invocation of the reducer function, or initialValue, if supplied. (See below.) - - currentModel The current model being processed in this collection. - - index The index of the current model being processed in this collection. - - collection The collection reduceRight is called upon.

initialValue Object <optional>

Object to use as the first argument to the first call to the reducer function. That is to say this is the initial value of the accumulator. This parameter is optional : If initialValue is provided in the call to reduceRight, then, the first time reducer is called, previousValue will be equal to initialValue and currentModel will be equal to the last model in this collection. If no initialValue is provided, then previousValue will be equal to the last model in this collection and currentModel will be equal to the second-to-last model. (note that in this later case, reducer must be a function taking two models to output a new model)

context Object <optional>

The object the reducer will be bound to when called.

Returns
  • The reduced single value of the collection.
Type
UWA/Class/Model

max(hash, context) → {Object}

Returns the maximum model in the collection, with regards to a criterion.

max returns the maximum model in the collection. If an hash function is provided, it will be used on each model to generate the criterion by which the model is ranked. The criterion computed by the hash function must be a number (otherwise undefined will be returned). Hash may also be the string name of a model attribute which values are numbers.

If the collection is empty, undefined is returned.

Notes:

To prevent potential unwanted side effects (like corrupting the collection), as a rule of thumb :

  • you should not (in your hash function) add or remove models from the list passed as third argument to the hash function.
  • most of the time, your hash function signature should take at most only two arguments (the current model that is visited and its index), this should prevent you from misbehaving.
Example
var daltons, getSizeInInches, maxName,
    cachedRegexp = /^([1-9]\d*)ft(([1-9]\d*)in)?$/,
    footInInches = 12;

daltons = new UWA.Class.Collection([{
    firstName: 'Joe',
    age: 32,
    size: '4ft6in'
}, {
    firstName: 'Jack',
    age: 37,
    size: '5ft6in'
}, {
    firstName: 'William',
    age: 23,
    size: '6ft4in'
}, {
    firstName: 'Averell',
    age: 27,
    size: '7ft'
}]);

// the hash function, returning an integer :
getSizeInInches = function (dalton) {
    var matchingGroups = dalton.get('size').match(cachedRegexp);
    return parseInt(matchingGroups[1], 10)*footInInches + parseInt(matchingGroups[3] || 0, 10);
};

maxName = daltons.max(getSizeInInches).get('firstName');
UWA.log(UWA.String.format("The taller Dalton is {0}", maxName)); // This logs 'The taller Dalton is Averell'

maxName = daltons.max('age').get('firstName');
UWA.log(UWA.String.format("The eldest Dalton is {0}", maxName)); // This logs 'The eldest Dalton is Jack'
Parameters
Name Type Argument Description
hash String

The string name of a model attribute which type is a number. Or a function used on each model to generate the criterion by which the model is ranked. It is invoked with three arguments: - - the current model - - the index of the current model in the collection - - the array of models of the collection being traversed (not the collection itself). Please read note above about this argument. It must return a criterion which type is number.

context Object <optional>

Object to use as this when executing the hash function.

Returns
  • the maximum model in the collection, with regards to the computed criterion. If there are several maxima, the first found is returned. undefined is returned if criteria are not numbers or if the collection is empty.
Type
Object
See:

min(hash, context) → {Object}

Returns the minimum model in the collection, with regards to a criterion.

min returns the minimum model in the collection. Please see max for a detailed explanation of its behavior.

Notes: Please read notes for method max.

Parameters
Name Type Argument Description
hash String

The string name of a model attribute which type is a number. Or a function used on each model to generate the criterion by which the model is ranked. Please see max for a detailed explanation of its behavior.

context Object <optional>

Object to use as this when executing the hash function.

Returns
  • the minimum model in the collection, with regards to the computed criterion. If there are several minima, the first found is returned. undefined is returned if criteria are not numbers or if the collection is empty.
Type
Object
See:

fetch(options) → {Object}

Fetches the default set of models for this collection from the backend.

fetch fetches the default set of models for this collection from the backend, setting them on the collection when they arrive.

It performs a READ operation on the backend.

The options hash takes onComplete and onFailure callbacks which will both be passed (collection, response, options) as arguments.

When the model data returns from the backend, it uses set to (intelligently) merge the fetched models, unless you pass {reset: true}, in which case the collection will be (efficiently) reset.

Delegates to sync under the covers for custom persistence strategies and returns a request that contains the cancel method, allowing to cancel the request made to the backend.

The backend handler for fetch requests should ideally return a JSON array of models. If not, you can implement the parse method to transform the data returned by the backend into a JSON array of models attributes.

The behavior of fetch can be customized by using the available {@link module:UWA/Class/Collection.UWA.Class.Collection#set|set} options. For example, to fetch a collection, getting an "onAdd" event for every new model, and a "onChange" event for every changed existing model, without removing anything:

collection.fetch({remove: false});

{@link module:UWA/Data.UWA.Data.request|UWA.Data.request} options can also be passed directly as fetch options, so to fetch a specific page of a paginated collection:

documents.fetch({data: {page: 3}})

Notes: Note that fetch should not be used to populate collections on page load — ideally all models needed at load time should already be bootstrapped in to place (for example in a <script> DOM element created in the initial page HTML markup served by the backend).

fetch is intended for lazily-loading models for interfaces that are not needed immediately: for example, documents with collections of notes that may be toggled open and closed.

Example
var MyCollection, mc;

MyCollection = UWA.Class.Collection.extend({
    url: '/Items'
});

mc = new MyCollection();

// This will launch a GET request to /Items?page=1
mc.fetch({
    data: {
        page: 1
    }
});
Parameters
Name Type Argument Description
options Object <optional>

an hash of options. Note that this options hash will be passed to your Model's constructor, but also to the sync method (see code example). Passing {parse: false} disables the parsing of the backend response, but why would you do that ? Passing {reset: true} to reset/empty the collection before fetching models.

Returns
  • An object that contains the cancel method, allowing to cancel the request made to the backend.
Type
Object
See:
  • {@link module:UWA/Class/Collection.UWA.Class.Collection#parse|parse}

create(attributes, options) → {Object|Boolean}

Create a new instance of a model within the collection.

create is a convenience to create a new instance of a model within the collection. It is equivalent to instantiating a model with a hash of attributes, saving the model to the backend, adding the model to the collection after being successfully created and eventually returning the new model.

It performs a CREATE operation on the backend.

If client-side validation failed, the model will be unsaved with validation errors and not added to the collection.

In order for this method create to work properly, you should set the model property of the collection.

This create method can accept either an attributes hash or an existing, unsaved model object.

Creating a model will cause an immediate "onAdd" event to be triggered on the collection, a "onRequest" event as the new model is sent to the backend, as well as a "onSync" event, once the backend has responded with the successful creation of the model.

Pass {wait: true} in the options hash if you'd like to wait for the backend's response before adding the new model to the collection.

create being an asynchonous operation, it accepts onComplete and onFailure callbacks in the options hash, which are both passed (model, response, options) as arguments.

(In the onFailure callback, no matter if you set the wait option to true or false, the model has not been saved in the backend (up to you to try to save it once again). Though if you set the wait option to false, you probably have to eventually remove the model passed to onFailure callback from the collection if you really cannot save it into the backend)

Notes:

Do not pass the identifying attribute Model.idAttribute in the hash of attributes, create is meant to create new models in the collection and in the backend at the same time, not to update existing ones. If you passed the identifying attribute Model.idAttribute in the hash of attributes, you could end up in some situations with a modified model in the backend that is left unmodified in the client application.

Though create is an asynchronous operation, it does not return a request object with a cancel() method, allowing you to cancel it. Whether this create API should return the created model or a request object is subject to debate. Now if you really want to get your hands on the request, here are some tips to cancel XmlHttpRequests :

var request, model;
model = coll.create(attrs, {
    beforeSend: function (_request)  { request = _request; }
});
request.cancel();

// or this way :
coll.addEventOnce('onRequest', function (model, request) {
    request.cancel();
});
model = coll.create(attrs);
Parameters
Name Type Argument Description
attributes Object

the hash of attributes. It should not contain the attribute identifying a model (Model.idAttribute), please read note above about this.

options Object <optional>

the options hash

Returns
  • The new added and saved model if it passed validation and could consequently be built. false if the attributes do not pass validation. (please also read note below)
Type
Object | Boolean