Comparing version 0.16.5 to 0.16.6
# Changelog | ||
## 0.16.6 | ||
### Fixes | ||
* Fixes bug with recycle for keys that weren't set at the beginning. [commit](https://github.com/goatslacker/alt/commit/31f8da1b) | ||
* Fixes isLoading for multiple async calls. [commit](https://github.com/goatslacker/alt/commit/6e4ed23) | ||
## 0.16.5 | ||
@@ -18,3 +25,3 @@ | ||
#### Fixes | ||
### Fixes | ||
@@ -21,0 +28,0 @@ * Bug with react-native. Stop using the Object.assign polyfill since react-native overrides it with a non-spec compliant one. [commit](https://github.com/goatslacker/alt/commit/5ccab76) |
132
dist/alt.js
@@ -910,3 +910,3 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Alt = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
},{"../../utils/functions":14,"../symbols/symbols":10,"es-symbol":1,"eventemitter3":2}],8:[function(require,module,exports){ | ||
},{"../../utils/functions":13,"../symbols/symbols":10,"es-symbol":1,"eventemitter3":2}],8:[function(require,module,exports){ | ||
'use strict'; | ||
@@ -957,13 +957,19 @@ | ||
exportAsync: function exportAsync(asyncMethods) { | ||
this.registerAsync(asyncMethods); | ||
}, | ||
registerAsync: function registerAsync(asyncDef) { | ||
var _this = this; | ||
var _isLoading = false; | ||
var _hasError = false; | ||
var loadCounter = 0; | ||
var asyncMethods = fn.isFunction(asyncDef) ? asyncDef(this.alt) : asyncDef; | ||
var toExport = Object.keys(asyncMethods).reduce(function (publicMethods, methodName) { | ||
var asyncSpec = asyncMethods[methodName](_this); | ||
var desc = asyncMethods[methodName]; | ||
var spec = fn.isFunction(desc) ? desc(_this) : desc; | ||
var validHandlers = ['success', 'error', 'loading']; | ||
validHandlers.forEach(function (handler) { | ||
if (asyncSpec[handler] && !asyncSpec[handler][Sym.ACTION_KEY]) { | ||
if (spec[handler] && !spec[handler][Sym.ACTION_KEY]) { | ||
throw new Error('' + handler + ' handler must be an action function'); | ||
@@ -979,17 +985,16 @@ } | ||
var state = _this.getInstance().getState(); | ||
var value = asyncSpec.local && asyncSpec.local.apply(asyncSpec, [state].concat(args)); | ||
var value = spec.local && spec.local.apply(spec, [state].concat(args)); | ||
var shouldFetch = spec.shouldFetch ? spec.shouldFetch.apply(spec, [state].concat(args)) : !value; | ||
// if we don't have it in cache then fetch it | ||
if (!value) { | ||
_isLoading = true; | ||
_hasError = false; | ||
if (shouldFetch) { | ||
loadCounter += 1; | ||
/* istanbul ignore else */ | ||
if (asyncSpec.loading) asyncSpec.loading(); | ||
asyncSpec.remote.apply(asyncSpec, [state].concat(args)).then(function (v) { | ||
_isLoading = false; | ||
asyncSpec.success(v); | ||
if (spec.loading) spec.loading(); | ||
spec.remote.apply(spec, [state].concat(args)).then(function (v) { | ||
loadCounter -= 1; | ||
spec.success(v); | ||
})['catch'](function (v) { | ||
_isLoading = false; | ||
_hasError = true; | ||
asyncSpec.error(v); | ||
loadCounter -= 1; | ||
spec.error(v); | ||
}); | ||
@@ -1008,6 +1013,3 @@ } else { | ||
isLoading: function isLoading() { | ||
return _isLoading; | ||
}, | ||
hasError: function hasError() { | ||
return _hasError; | ||
return loadCounter > 0; | ||
} | ||
@@ -1109,3 +1111,3 @@ }); | ||
},{"../../utils/functions":14,"../symbols/symbols":10,"es-symbol":1}],9:[function(require,module,exports){ | ||
},{"../../utils/functions":13,"../symbols/symbols":10,"es-symbol":1}],9:[function(require,module,exports){ | ||
'use strict'; | ||
@@ -1285,3 +1287,3 @@ | ||
},{"../../utils/functions":14,"../symbols/symbols":10,"../utils/AltUtils":11,"./AltStore":7,"./StoreMixin":8,"eventemitter3":2}],10:[function(require,module,exports){ | ||
},{"../../utils/functions":13,"../symbols/symbols":10,"../utils/AltUtils":11,"./AltStore":7,"./StoreMixin":8,"eventemitter3":2}],10:[function(require,module,exports){ | ||
'use strict'; | ||
@@ -1433,9 +1435,13 @@ | ||
if (store) { | ||
var config = store.StoreModel.config; | ||
(function () { | ||
var config = store.StoreModel.config; | ||
if (config.onDeserialize) { | ||
obj[key] = config.onDeserialize(value) || value; | ||
} | ||
fn.assign(store[Sym.STATE_CONTAINER], obj[key]); | ||
onStore(store); | ||
var state = store[Sym.STATE_CONTAINER]; | ||
if (config.onDeserialize) obj[key] = config.onDeserialize(value) || value; | ||
fn.eachObject(function (k) { | ||
return delete state[k]; | ||
}, [state]); | ||
fn.assign(state, obj[key]); | ||
onStore(store); | ||
})(); | ||
} | ||
@@ -1478,3 +1484,3 @@ }, [obj]); | ||
},{"../../utils/functions":14,"../symbols/symbols":10}],13:[function(require,module,exports){ | ||
},{"../../utils/functions":13,"../symbols/symbols":10}],13:[function(require,module,exports){ | ||
'use strict'; | ||
@@ -1485,2 +1491,35 @@ | ||
}); | ||
exports.eachObject = eachObject; | ||
exports.assign = assign; | ||
var isFunction = function isFunction(x) { | ||
return typeof x === 'function'; | ||
}; | ||
exports.isFunction = isFunction; | ||
function eachObject(f, o) { | ||
o.forEach(function (from) { | ||
Object.keys(Object(from)).forEach(function (key) { | ||
f(key, from[key]); | ||
}); | ||
}); | ||
} | ||
function assign(target) { | ||
for (var _len = arguments.length, source = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
source[_key - 1] = arguments[_key]; | ||
} | ||
eachObject(function (key, value) { | ||
return target[key] = value; | ||
}, source); | ||
return target; | ||
} | ||
},{}],14:[function(require,module,exports){ | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
var _bind = Function.prototype.bind; | ||
@@ -1774,36 +1813,3 @@ | ||
},{"../utils/functions":14,"./actions":6,"./store":9,"./symbols/symbols":10,"./utils/AltUtils":11,"./utils/StateFunctions":12,"flux":3}],14:[function(require,module,exports){ | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
exports.eachObject = eachObject; | ||
exports.assign = assign; | ||
var isFunction = function isFunction(x) { | ||
return typeof x === 'function'; | ||
}; | ||
exports.isFunction = isFunction; | ||
function eachObject(f, o) { | ||
o.forEach(function (from) { | ||
Object.keys(Object(from)).forEach(function (key) { | ||
f(key, from[key]); | ||
}); | ||
}); | ||
} | ||
function assign(target) { | ||
for (var _len = arguments.length, source = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
source[_key - 1] = arguments[_key]; | ||
} | ||
eachObject(function (key, value) { | ||
return target[key] = value; | ||
}, source); | ||
return target; | ||
} | ||
},{}]},{},[13])(13) | ||
},{"../utils/functions":13,"./actions":6,"./store":9,"./symbols/symbols":10,"./utils/AltUtils":11,"./utils/StateFunctions":12,"flux":3}]},{},[14])(14) | ||
}); |
@@ -27,2 +27,23 @@ --- | ||
You can set your entire app context by wrapping your root component with `withAltContext`. | ||
As a decorator: | ||
```js | ||
import withAltContext from 'alt/utils/withAltContext' | ||
@withAltContext(alt) | ||
export default class App extends React.Component { | ||
render() { | ||
return <div>{this.context.flux}</div> | ||
} | ||
} | ||
``` | ||
As a function: | ||
```js | ||
import withAltContext from 'alt/utils/withAltContext' | ||
export default withAltContext(alt)(App); | ||
``` | ||
# AltClass | ||
@@ -29,0 +50,0 @@ |
@@ -12,3 +12,3 @@ --- | ||
The `alt.bootstrap()` function takes in a snapshot you've saved and reloads every store's state with that the data provided in that snapshot. | ||
The `alt.bootstrap()` function takes in a snapshot you've saved and reloads every store's state with the data provided in that snapshot. | ||
@@ -15,0 +15,0 @@ Bootstrap is great if you're running an isomorphic app, or if you're persisting state to localstorage and then retrieving it on init later on. You can save a snapshot on the server side, send it down, and then bootstrap it back on the client. |
@@ -134,3 +134,3 @@ --- | ||
`BlogPost` in this case will receive all the state of `BlogStore` as props. `this.props.id` and `this.props.title` will be passed through to `BlogPost`. | ||
`BlogPost` in this case will receive all the state of `PostStore` as props. `this.props.id` and `this.props.title` will be passed through to `BlogPost`. | ||
@@ -137,0 +137,0 @@ Just like `stores`, you can define your own custom function to use with `store`. |
@@ -38,3 +38,3 @@ --- | ||
The constructor of your actions receieves the alt instance as its first and only argument. Inside the constructor any instance properties you define will be available as actions. | ||
The constructor of your actions receives the alt instance as its first and only argument. Inside the constructor any instance properties you define will be available as actions. | ||
@@ -41,0 +41,0 @@ ## ActionsClass#generateActions |
@@ -46,13 +46,19 @@ 'use strict'; | ||
exportAsync: function exportAsync(asyncMethods) { | ||
this.registerAsync(asyncMethods); | ||
}, | ||
registerAsync: function registerAsync(asyncDef) { | ||
var _this = this; | ||
var _isLoading = false; | ||
var _hasError = false; | ||
var loadCounter = 0; | ||
var asyncMethods = fn.isFunction(asyncDef) ? asyncDef(this.alt) : asyncDef; | ||
var toExport = Object.keys(asyncMethods).reduce(function (publicMethods, methodName) { | ||
var asyncSpec = asyncMethods[methodName](_this); | ||
var desc = asyncMethods[methodName]; | ||
var spec = fn.isFunction(desc) ? desc(_this) : desc; | ||
var validHandlers = ['success', 'error', 'loading']; | ||
validHandlers.forEach(function (handler) { | ||
if (asyncSpec[handler] && !asyncSpec[handler][Sym.ACTION_KEY]) { | ||
if (spec[handler] && !spec[handler][Sym.ACTION_KEY]) { | ||
throw new Error('' + handler + ' handler must be an action function'); | ||
@@ -68,17 +74,16 @@ } | ||
var state = _this.getInstance().getState(); | ||
var value = asyncSpec.local && asyncSpec.local.apply(asyncSpec, [state].concat(args)); | ||
var value = spec.local && spec.local.apply(spec, [state].concat(args)); | ||
var shouldFetch = spec.shouldFetch ? spec.shouldFetch.apply(spec, [state].concat(args)) : !value; | ||
// if we don't have it in cache then fetch it | ||
if (!value) { | ||
_isLoading = true; | ||
_hasError = false; | ||
if (shouldFetch) { | ||
loadCounter += 1; | ||
/* istanbul ignore else */ | ||
if (asyncSpec.loading) asyncSpec.loading(); | ||
asyncSpec.remote.apply(asyncSpec, [state].concat(args)).then(function (v) { | ||
_isLoading = false; | ||
asyncSpec.success(v); | ||
if (spec.loading) spec.loading(); | ||
spec.remote.apply(spec, [state].concat(args)).then(function (v) { | ||
loadCounter -= 1; | ||
spec.success(v); | ||
})['catch'](function (v) { | ||
_isLoading = false; | ||
_hasError = true; | ||
asyncSpec.error(v); | ||
loadCounter -= 1; | ||
spec.error(v); | ||
}); | ||
@@ -97,6 +102,3 @@ } else { | ||
isLoading: function isLoading() { | ||
return _isLoading; | ||
}, | ||
hasError: function hasError() { | ||
return _hasError; | ||
return loadCounter > 0; | ||
} | ||
@@ -103,0 +105,0 @@ }); |
@@ -26,9 +26,13 @@ 'use strict'; | ||
if (store) { | ||
var config = store.StoreModel.config; | ||
(function () { | ||
var config = store.StoreModel.config; | ||
if (config.onDeserialize) { | ||
obj[key] = config.onDeserialize(value) || value; | ||
} | ||
fn.assign(store[Sym.STATE_CONTAINER], obj[key]); | ||
onStore(store); | ||
var state = store[Sym.STATE_CONTAINER]; | ||
if (config.onDeserialize) obj[key] = config.onDeserialize(value) || value; | ||
fn.eachObject(function (k) { | ||
return delete state[k]; | ||
}, [state]); | ||
fn.assign(state, obj[key]); | ||
onStore(store); | ||
})(); | ||
} | ||
@@ -35,0 +39,0 @@ }, [obj]); |
{ | ||
"name": "alt", | ||
"version": "0.16.5", | ||
"version": "0.16.6", | ||
"description": "A flux implementation", | ||
@@ -12,2 +12,3 @@ "main": "lib", | ||
"devDependencies": { | ||
"alt-search-docs": "1.0.6", | ||
"babel": "^5.3.1", | ||
@@ -22,3 +23,3 @@ "babel-core": "^5.3.1", | ||
"es6-promise": "^2.1.1", | ||
"eslint": "^0.21.0", | ||
"eslint": "0.21.0", | ||
"ghooks": "^0.3.2", | ||
@@ -25,0 +26,0 @@ "immutable": "^3.7.2", |
@@ -85,2 +85,3 @@ # alt | ||
* [React Router Loopback](https://github.com/bkniffler/react-router-alt-loopback) | ||
* [React Webpack Rails Example](https://github.com/justin808/react-webpack-rails-tutorial) | ||
* [React Weather](https://github.com/sapegin/react-weather) | ||
@@ -306,3 +307,3 @@ * [Shopping Cart](https://github.com/voronianski/flux-comparison/tree/master/alt) | ||
`getState` will return a copy of your the current store's state. | ||
`getState` will return a copy of the current store's state. | ||
@@ -309,0 +310,0 @@ ```js |
@@ -41,2 +41,30 @@ import Alt from '../' | ||
} | ||
}, | ||
alwaysFetchUsers: { | ||
remote, | ||
local: () => true, | ||
loading: StargazerActions.fetchingUsers, | ||
success: StargazerActions.usersReceived, | ||
error: StargazerActions.failed, | ||
shouldFetch: () => true | ||
}, | ||
neverFetchUsers: { | ||
remote, | ||
local: () => false, | ||
loading: StargazerActions.fetchingUsers, | ||
success: StargazerActions.usersReceived, | ||
error: StargazerActions.failed, | ||
shouldFetch: () => false | ||
}, | ||
fetchRepos: { | ||
remote() { | ||
return new Promise((resolve, reject) => { | ||
setTimeout(() => resolve('TESTTEST'), 200) | ||
}) | ||
}, | ||
success: StargazerActions.usersReceived, | ||
error: StargazerActions.failed | ||
} | ||
@@ -149,3 +177,2 @@ } | ||
assert.ok(local.calledOnce) | ||
assert.notOk(StargazerStore.hasError(), 'no errors') | ||
assert.notOk(StargazerStore.isLoading()) | ||
@@ -170,3 +197,2 @@ assert(remote.callCount === 0) | ||
assert.match(state.errorMessage, /things broke/) | ||
assert.ok(StargazerStore.hasError(), 'we have an error') | ||
count() | ||
@@ -184,3 +210,66 @@ test() | ||
}, | ||
'shouldFetch is true'() { | ||
StargazerStore.alwaysFetchUsers() | ||
assert.ok(StargazerStore.isLoading()) | ||
assert.ok(remote.calledOnce) | ||
}, | ||
'shouldFetch is false'() { | ||
StargazerStore.neverFetchUsers() | ||
assert.notOk(StargazerStore.isLoading()) | ||
assert(remote.callCount === 0) | ||
}, | ||
'multiple loads'(done) { | ||
const unsub = StargazerStore.listen((state) => { | ||
if (state.users === 'TESTTEST') { | ||
assert.notOk(StargazerStore.isLoading()) | ||
unsub() | ||
done() | ||
} else { | ||
assert.ok(StargazerStore.isLoading()) | ||
} | ||
}) | ||
StargazerStore.fetchUsers() | ||
StargazerStore.fetchRepos() | ||
assert.ok(StargazerStore.isLoading()) | ||
}, | ||
'as a function'() { | ||
const FauxSource = sinon.stub().returns({}) | ||
@datasource(FauxSource) | ||
class FauxStore { | ||
static displayName = 'FauxStore' | ||
} | ||
const store = alt.createStore(FauxStore) | ||
assert(FauxSource.firstCall.args[0] === alt) | ||
assert.isFunction(store.isLoading) | ||
}, | ||
'as an object'() { | ||
const actions = alt.generateActions('test') | ||
const PojoSource = { | ||
justTesting: { | ||
success: actions.test, | ||
error: actions.test, | ||
} | ||
} | ||
@datasource(PojoSource) | ||
class MyStore { | ||
static displayName = 'MyStore' | ||
} | ||
const store = alt.createStore(MyStore) | ||
assert.isFunction(store.justTesting) | ||
assert.isFunction(store.isLoading) | ||
}, | ||
} | ||
} |
@@ -10,5 +10,6 @@ 'use strict'; | ||
function chromeDebug(alt) { | ||
window['goatslacker.github.io/alt/'] = alt; | ||
if (typeof window !== 'undefined') window['alt.js.org'] = alt; | ||
return alt; | ||
} | ||
module.exports = exports['default']; |
Sorry, the diff of this file is too big to display
531453
113
10708
838
21