Wednesday, January 9, 2008

jQuery.Collection

This plugin generates generic collection classes, that work almost exactly as jQuery does. These collections include all those jQuery functions, that are used to manipulate the collection itself. The supported functions are:

  add, andSelf, attr, each, end, eq, extend, filter,
  get, implement, include, index, init, is, map, not,
  pushStack, setArray, size and slice.
The init() function included is a basic and generic one. It should be (likely) modified for each collection, to suit the needs. The include() function, is an invention of the plugin, it works similary to extend(), it will copy the listed attributes/methods from target to source. If target's not specified, then it will be the caller(like extend). The arguments are .include([ target,] source, methods ). Every collection will have a build() function, that will create a new collection class, that inherits from the caller. $.collection is a collection class by itself. So other collections will inherit from it, or its subclasses. The filter() function accepts:
  • A function that returns true/false.
  • Anything else will be taken literally and compared. Only those items included pass the filter. The filter can be an array of items.
$.collection(1,2,3,4).filter([2,3]);//--> [ 2, 3 ]
The function .not() works the same way, but matches the opposite.

Links: Downloads: The project page at jQuery includes some examples of its use.
I really advice using the minified versions. The code is optimized for those releases. Source versions should only be used to learn.

12 comments:

Guy said...

Do you have an example of adding custom selectors?

For example, if I have some user objects:

var users = $.collection.build();
users.push({
name: 'Joe',
role: 'Moderator'
});
users.push({
name: 'Sally',
role: 'Administrator'
});

Could I implement a selector that would let me do this:

var admins = users('Administrator');

Flesler said...

Hi Guy
 Yes, you can. But what you wrote is a bit wrong. In your case, users is a collection Class, not an instance. Also collections don't bring push by default, you can add it, or include from array, like in the examples.
Your code could be:

var Users = $.collection.build();
Users.fn.init = function( name, role ){
  return this.setArray([{
    name: name,
    role: role
  }]);
};
Users.fn.getByRole = function( role ){
  return this.filter(function(){
    return this.role == role;
  });
};
var employees = Users('Joe','Moderator')
    .add('Sally','Administrator');
employees.getByRole('Administrator')/* -->[{name:'Sally',role:'Administrator' }]*/

This plugin can be used in many ways, you need to remember it works like jQuery does.
Please upgrade to 1.0.2. There was a small bug that I fixed.

Thatcher said...

Ariel, great plugin. I have decided to refactor a considerable portion of my current project to use $.collections, but because I want to do an early release in march I'm not sure if I should wait. Are you generally available to answer questions if I provide examples or is your schedule pretty crazy?

Thanks
Thatcher

Ariel Flesler said...

Hi Thatcher
  I'm not always free, but I can get back to you at least once a day (probably more).

Cheers

Chad Warner said...

I get a stack overflow in IE at line 62 with JQuery 1.2.6. Any ideas?

Ariel Flesler said...

Yes, It's due to the stack blowing up. Probably from too much recursion.

jQuery does a lot of recursion itself, so probably, you just added some more and it surpassed IE's limits.

It's hard to workaround, try to do less function nesting, if you are doing sort of a loop with recursion, break it with setTimeout.

This is how I fixed this problem for jQuery.Preload, check its source and Troubleshoothing.

Cheers

SANKAI said...

if I have some data objects:
var phonogram = $.collection.build();
phonogram.fn.init = function( index, lowercase, uppercase ){
  return this.setArray([{
   key: index,
   hiragana: lowercase,
   katakana: uppercase
  }]);
};
phonogram.fn.getByKey = function( key ){
  return this.filter(function(){
    return this.key == key;
  });
};
var vowel = phonogram()
  .add('a','あ','ア')
  .add('i','い','イ')
  .add('u','う','ウ');

Could I get one or more random entries from an object that let me do this:
var pick = vowel.getRandom.attr('hiragana');

the result maybe is あ or い or う

Ariel Flesler said...

Sure:

phonogram.fn.getRandom = function(){
var index = Math.floor(Math.random() * (this.length - 1));

return this.eq( index );
};

I haven't tried it, but that should do.

timmfin said...

I had problems with this plugin in Safari 4. The issue was that calling unshift on the array-like implicit arguments variable wasn't actually altering the arguments passed recusively, and resulted in an infinite loop.

I changed these two lines:

[].unshift.call( arguments, this );//insert 'this' first
return this.include.apply(this,arguments);//call again with fixed arguments

to:

var args = Array.prototype.slice.call(arguments);
args.unshift(this); //insert 'this' first
return this.include.apply(this,args);//call again with fixed arguments

Lewis Litanzios said...

Yo Ariel,

I suggest you make this part of the download screen for loaclScroll a LOT more obvious. Just wasted an hour messing around with localScroll on it's own trying to get it to work:

'jQuery.LocalScroll 1.2.x requires jQuery.ScrollTo 1.3.1 or higher.
Since 1.2.5, you can combine with jQuery.SerialScroll(+1.2.0).
I really advice using the minified versions. The code is optimized for those releases. Source versions should only be used to learn. '

Put it in red or something because I was about 10mins away from giving up.

Thanks,
L

Ariel Flesler said...

Hi
That note is pretty old actually... if you download any of the plugins' last versions, you'll have it all good.

Why do you post on jQuery.Collection's post ?

Bruce said...

error "this.setArray is not a function"

var Selections = $.collection.build();
Selections.fn.init = function (listProperty, value) {
return this.setArray([{
listProperty: listProperty,
value: value
}]);
};

What am I doing wrong here? Using jQuery 2.0.2.