Skip to content

Latest commit

 

History

History
246 lines (169 loc) · 10.5 KB

collection.md

File metadata and controls

246 lines (169 loc) · 10.5 KB

Collection

A collection is a client-side abstraction for the latest-saved server state of a list of objects (a model, by contrast, represents a single persisted object in that resource). A collection must have one thing: a url. This instance property can be a string literal or a function.

class MyTodos extends Collection<ModelType> {
  url = '/todos'
}

class MyTodos extends Collection<ModelType> {
  url({subtype}) {
    return `/todos/${subtype}`;
  }
}

A collection instance of the class created and registered in your resourcerer config will be returned by every useResources call that uses its model key from the ModelMap. You can read simply from it by using Collection#toJSON (the most common usage), but there are several other methods and properties in its interface you can customize in your collection definition or that you might find useful in rendering your data-hydrated components.

Properties

static comparator

Add this on your Collection definition to tell it how it should sort its models. It can take three forms:

  1. A string. In this case, it represents the model property to sort by.
  2. A function with a single argument. In this case, it takes a model's data as an argument and returns the value by which it should sort.
  3. A function with two arguments. This is used to sort the collection's models via the native Array.sort method.

length

This is an instance property that represents the number of models in the collection.

static Model

Set this property if you want a collection's models to be an instance of a class other than the default Model

static dependencies

This property tells resourcerer how to determine whether to make a new request or to take a collection out of the cache. It is an array of strings or functions from which its cache key is calculated. See the cacheKey section for more info.

static cacheTimeout

number

The number of milliseconds to keep all collections of this class in the cache after all client components stop referencing it. Note that this is on a collection class basis and not an instance basis because the latter can introduce race conditions into your application.

static measure

boolean | (obj: ResourceConfigObject) => boolean

A boolean or function that accepts a resource configuration object and returns a boolean, telling resourcerer to track this collection's request time and report it via the track method setup in configuration.

static idAttribute

Use this as a shortcut when you don't want to define a custom Model class just because the collection doesn't contain the default id field (which is 'id'), ie:

// the collection will index its models based on the `name` property instead of the default `id` property
static idAttribute = 'name'

Methods

constructor

constructor: (models: Array<Record<string, any> | Model>, options: object) => void

The Collection's constructor gets passed any initial models, as well as the options from the executor function. Override this to add some custom logic or instance variables for the collection—just be sure to pass the arguments to its .super() call, as well:

class MyCollection extends Collection<ModelType> {
  constructor(models, options={}) {
    super(models, options);
    
    // initializing some variable to be used later
    this.categoriesList = [];
  }
  
  url({category}) {
    return `/todos/${category}`;
  }
}

Passing in a Model option or a comparator option to an instance's constructor will override the statically defined properties on its constructor. Other path fields (the ones passed from the executor function options property) are passed to the url as shown in the example above.

add

add: (models: Record<string, any> | Model | Array<Record<string, any> | Model>, options: Object) => this

Add a new entry or list of entries into the collection. Each entry can be an object of data or a Model instance. Will trigger an update in all subscribed components unless the trigger: true option is passed. You can also pass a parse: true option to run the model through its parse method before setting its properties. If an entry already exists on the collection, the new properties will get merged into its existing model.

create

create: (model: Record<string, any> | Model, options: Object) => Promise<[Model, Response]>

Adds a new entry to the collection and persists it to the server. This is literally the equivalent to calling collection.add() and then model.save(). Because it also instantiates the new model, be sure to pass any path params you need in your url as the options argument (the same options in the resource config object). The returned Promise is the same as is returned from Model#save. If the request errors, the model is auto-removed from the collection. Pass the wait: true option to wait to add the new model until after the save request returns. Subscribed components will update when the new entry is added as well as when the request returns.

All .create() calls must have a .catch attached, even if the rejection is swallowed. Omitting one risks an uncaught Promise rejection exception if the request fails.

fetch

fetch: (options: object) => Promise<[this, Response]> 

This is the method that resourcerer uses internally to get server data and set its parsed response as models on the collection. This should rarely need to be used in your application. Subscribed components will update when the request returns.

All .fetch() calls must have a .catch attached, even if the rejection is swallowed. Omitting one risks an uncaught Promise rejection exception if the request fails.

get

get: (identifier: string | number) => Model | undefined

Collections index their Model instances by either the Model's idAttribute or, equivalently as a shortcut, by the collection's own static modelIdAttribute property. The .get() method takes an id value and returns the quick-lookup model instance if one exists.

has

has: (identifier: string |number | Model | object) => boolean

Returns whether or not a model exists in a collection. You can pass the model instance itself, a model's data, or a model's id.

parse

parse: (response: any) => Array<Object>

This method takes in the raw server data response and should return the data in the form that should be set on the Collection. It defaults to the identity function, which might suffice for many endpoints. Override this for your custom needs. For example, for some search results with some metadata (in an API that returns a JSON object), we want to set the results as the collection:

parse(response) {
  this.totalResults = response.totalResults;
  this.pageNumber = response.pageNumber;
  this.resultsPerPage = response.resultsPerPage;
  
  return response.results;
}

remove

remove: (models: Record<string, any> | Model | Array<Record<string, any> | Model>, options: Object) => this

Use this to remove a model or models from the collection, which should not often be needed. You can pass in anything or a list of anything that can be accepted via .get(). Pass in silent: true for subscribed components not to get rerendered.

reset

reset: (models: Array<Record<string, any> | Model>, options: Object) => this

Removes all models and their references from a collection and replaces them with the models passed in. Pass in silent: true for subscribed components not to get rerendered, and parse: true to have data get parsed before being set on their respective models.

set

set: (models: Record<string, any> | Model | Array<Record<string, any> | Model>, options: Object) => this

This is the method that many other write methods (add, remove, save, reset, etc) use under the hood, and it should rarely if ever need to be used directly in your application. Sets new data as models and merges existing data with their models, and sorts as necessary. Pass in silent: true for subscribed components not to get rerendered, and parse: true to have data get parsed before being set on their respective models.

sync

This is just a proxy for the sync module. Its behavior shouldn't be overridden, but it may be useful to wrap it for custom behavior, ie:

Collection.sync = Model.sync = function(model, options) {
  // custom logic...
  
  // defer again to the sync module
  return sync(this, options);
}

toJSON

toJSON: () => ModelType[]

Returns each model's data objects in a new array.

Utility instance methods

at

at: (index: number) => Model

Returns the model at a given index in the collection. Index can be negative to count backwards from the end.

filter

filter: (predicate: (Model) => boolean) Model[]

Same signature as Array.prototype.filter across a collection's models.

find

find: (predicate: (Model) => boolean) => Model | undefined

Same signature as Array.prototype.find across a collection's models.

findWhere

findWhere: (attrs: Partial<ModelType>) => Model | undefined

Returns the model matching the attributes passed in, or undefined if no match is found. Like .find but a shorthand that uses matching attribute values instead of a predicate function.

map

map: (predicate: (Model) => any) => any[]

Same signature as Array.prototype.map across a collection's models.

pluck

pluck: (attribute: string) => any[]

Returns a list of the specified attribute value for all models.

slice

slice: (startIndex: number[, endIndex: number]) => Model[]

Same signature as Array.prototype.slice across a collection's models.

where

where: (attrs: Partial<ModelType>) => Model[]

Returns a list of models matching the data values passed in. Like .filter but a shorthand that uses matching data values instead of a predicate function.