|
1 | 1 | // Backbone React Component
|
2 | 2 | // ========================
|
3 | 3 | //
|
4 |
| -// Backbone.React.Component v0.8.0 |
| 4 | +// Backbone.React.Component v0.8.1 |
5 | 5 | //
|
6 | 6 | // (c) 2014 "Magalhas" José Magalhães <[email protected]>
|
7 | 7 | // Backbone.React.Component can be freely distributed under the MIT license.
|
|
45 | 45 | Backbone.React.Component = {};
|
46 | 46 | }
|
47 | 47 | // Mixin used in all component instances. Exported through `Backbone.React.Component.mixin`.
|
48 |
| - Backbone.React.Component.mixin = { |
| 48 | + var mixin = Backbone.React.Component.mixin = { |
49 | 49 | // Types of the context passed to child components. Only
|
50 | 50 | // `hasParentBackboneMixin` is required all of the others are optional.
|
51 | 51 | childContextTypes: {
|
|
167 | 167 | };
|
168 | 168 | // Binds models and collections to a `React.Component`. It mixes `Backbone.Events`.
|
169 | 169 | function Wrapper (component, initialState, nextProps) {
|
| 170 | + // Object to store wrapper state (not the component state) |
| 171 | + this.state = {}; |
170 | 172 | // 1:1 relation with the `component`
|
171 | 173 | this.component = component;
|
172 | 174 | // Use `nextProps` or `component.props` and grab `model` and `collection`
|
|
190 | 192 | collection = props.collection;
|
191 | 193 | }
|
192 | 194 |
|
193 |
| - // Check if `props.model` is a `Backbone.Model` or an hashmap of them |
194 |
| - if (typeof model !== 'undefined' && (model.attributes || |
195 |
| - typeof model === 'object' && _.values(model)[0].attributes)) { |
196 |
| - // The model(s) bound to this component |
197 |
| - this.model = model; |
198 |
| - // Set model(s) attributes on `initialState` for the first render |
199 |
| - this.setStateBackbone(model, void 0, initialState); |
200 |
| - } |
201 |
| - // Check if `props.collection` is a `Backbone.Collection` or an hashmap of them |
202 |
| - if (typeof collection !== 'undefined' && (collection.models || |
203 |
| - typeof collection === 'object' && _.values(collection)[0].models)) { |
204 |
| - // The collection(s) bound to this component |
205 |
| - this.collection = collection; |
206 |
| - // Set collection(s) models on `initialState` for the first render |
207 |
| - this.setStateBackbone(collection, void 0, initialState); |
208 |
| - } |
209 |
| - |
210 |
| - // Start listeners |
211 |
| - this.startModelListeners(); |
212 |
| - this.startCollectionListeners(); |
| 195 | + this.setModels(model, initialState); |
| 196 | + this.setCollections(collection, initialState); |
213 | 197 | }
|
214 | 198 | // Mixing `Backbone.Events` into `Wrapper.prototype`
|
215 | 199 | _.extend(Wrapper.prototype, Backbone.Events, {
|
|
253 | 237 | this.component.setState({isRequesting: false});
|
254 | 238 | }
|
255 | 239 | },
|
| 240 | + // Check if `models` is a `Backbone.Model` or an hashmap of them, sets them |
| 241 | + // to the component state and binds to update on any future changes |
| 242 | + setModels: function (models, initialState, isDeferred) { |
| 243 | + if (typeof models !== 'undefined' && (models.attributes || |
| 244 | + typeof models === 'object' && _.values(models)[0].attributes)) { |
| 245 | + // The model(s) bound to this component |
| 246 | + this.model = models; |
| 247 | + // Set model(s) attributes on `initialState` for the first render |
| 248 | + this.setStateBackbone(models, void 0, initialState, isDeferred); |
| 249 | + this.startModelListeners(models); |
| 250 | + } |
| 251 | + }, |
| 252 | + // Check if `collections` is a `Backbone.Model` or an hashmap of them, |
| 253 | + // sets them to the component state and binds to update on any future changes |
| 254 | + setCollections: function (collections, initialState, isDeferred) { |
| 255 | + if (typeof collections !== 'undefined' && (collections.models || |
| 256 | + typeof collections === 'object' && _.values(collections)[0].models)) { |
| 257 | + // The collection(s) bound to this component |
| 258 | + this.collection = collections; |
| 259 | + // Set collection(s) models on `initialState` for the first render |
| 260 | + this.setStateBackbone(collections, void 0, initialState, isDeferred); |
| 261 | + this.startCollectionListeners(collections); |
| 262 | + } |
| 263 | + }, |
256 | 264 | // Used internally to set `this.collection` or `this.model` on `this.state`. Delegates to
|
257 | 265 | // `this.setState`. It listens to `Backbone.Collection` events such as `add`, `remove`,
|
258 | 266 | // `change`, `sort`, `reset` and to `Backbone.Model` `change`.
|
259 |
| - setStateBackbone: function (modelOrCollection, key, target) { |
| 267 | + setStateBackbone: function (modelOrCollection, key, target, isDeferred) { |
260 | 268 | if (!(modelOrCollection.models || modelOrCollection.attributes)) {
|
261 | 269 | for (key in modelOrCollection)
|
262 | 270 | this.setStateBackbone(modelOrCollection[key], key, target);
|
|
265 | 273 | this.setState.apply(this, arguments);
|
266 | 274 | },
|
267 | 275 | // Sets a model, collection or object into state by delegating to `this.component.setState`.
|
268 |
| - setState: function (modelOrCollection, key, target) { |
| 276 | + setState: function (modelOrCollection, key, target, isDeferred) { |
269 | 277 | var state = {};
|
270 | 278 | var newState = modelOrCollection.toJSON ? modelOrCollection.toJSON() : modelOrCollection;
|
271 | 279 |
|
272 | 280 | if (key) {
|
273 | 281 | state[key] = newState;
|
274 |
| - } else if (modelOrCollection instanceof Backbone.Collection) { |
| 282 | + } else if (modelOrCollection.models) { |
275 | 283 | state.collection = newState;
|
276 | 284 | } else {
|
277 | 285 | state.model = newState;
|
278 | 286 | }
|
279 | 287 |
|
280 | 288 | if (target) {
|
281 | 289 | _.extend(target, state);
|
| 290 | + } else if (isDeferred) { |
| 291 | + this.nextState = _.extend(this.nextState || {}, state); |
| 292 | + _.defer(_.bind(function () { |
| 293 | + if (this.nextState) { |
| 294 | + this.component.setState(this.nextState); |
| 295 | + this.nextState = null; |
| 296 | + } |
| 297 | + }, this)); |
282 | 298 | } else {
|
283 | 299 | this.component.setState(state);
|
284 | 300 | }
|
|
290 | 306 | if (collection.models)
|
291 | 307 | this
|
292 | 308 | .listenTo(collection, 'add remove change sort reset',
|
293 |
| - _.partial(this.setStateBackbone, collection, key, void 0)) |
| 309 | + _.partial(this.setStateBackbone, collection, key, void 0, true)) |
294 | 310 | .listenTo(collection, 'error', this.onError)
|
295 | 311 | .listenTo(collection, 'request', this.onRequest)
|
296 | 312 | .listenTo(collection, 'sync', this.onSync);
|
|
307 | 323 | if (model.attributes)
|
308 | 324 | this
|
309 | 325 | .listenTo(model, 'change',
|
310 |
| - _.partial(this.setStateBackbone, model, key, void 0)) |
| 326 | + _.partial(this.setStateBackbone, model, key, void 0, true)) |
311 | 327 | .listenTo(model, 'error', this.onError)
|
312 | 328 | .listenTo(model, 'request', this.onRequest)
|
313 | 329 | .listenTo(model, 'sync', this.onSync)
|
|
320 | 336 | });
|
321 | 337 |
|
322 | 338 | // Expose `Backbone.React.Component.mixin`.
|
323 |
| - return Backbone.React.Component.mixin; |
| 339 | + return mixin; |
324 | 340 | }));
|
325 | 341 | // <a href="https://github.com/magalhas/backbone-react-component"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://github-camo.global.ssl.fastly.net/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a>
|
0 commit comments