Open genyded opened 8 years ago
Good point. What would be the best way to handle this? Let the use pass a noResultsComponent
to display when there's no data?
Note that for the ListContainer
it's a bit different, since you can already test results.length
to see if there are results or not.
Yes - List is good to go. For Documents, a no results component could work. It seems like the most important thing is knowing no data was returned though. Once that is there however it's implemented, devs can do whatever they want with that info.
Here is a proposed solution:
import React, { PropTypes, Component } from 'react';
const Subs = new SubsManager();
const DocumentContainer = React.createClass({
mixins: [ReactMeteorData],
getMeteorData() {
// subscribe if necessary
if (this.props.publication) {
const subscribeFunction = this.props.cacheSubscription ? Subs.subscribe : Meteor.subscribe;
this.subscription = subscribeFunction(this.props.publication, this.props.terms);
}
const collection = this.props.collection;
const document = collection.findOne(this.props.selector);
// look for any specified joins
if (document && this.props.joins) {
// loop over each join
this.props.joins.forEach(join => {
if (join.foreignProperty) {
// foreign join (e.g. comments belonging to a post)
// get the property containing the id
const foreignProperty = document[join.foreignProperty];
const joinSelector = {};
joinSelector[join.foreignProperty] = document._id;
document[join.joinAs] = collection.find(joinSelector);
} else {
// local join (e.g. a post's upvoters)
// get the property containing the id or ids
const joinProperty = document[join.localProperty];
const collection = typeof join.collection === "function" ? join.collection() : join.collection;
// perform the join
if (Array.isArray(joinProperty)) { // join property is an array of ids
document[join.joinAs] = collection.find({_id: {$in: joinProperty}}).fetch();
} else { // join property is a single id
document[join.joinAs] = collection.findOne({_id: joinProperty});
}
}
});
}
const data = {
currentUser: Meteor.user(),
ready: this.subscription.ready()
}
data[this.props.documentPropName] = document;
return data;
},
render() {
const loadingComponent = this.props.loading ? this.props.loading : <p>Loading…</p>
const noData = noData ? noData : <p>No data found.</p>
if (this.data.ready) {
if(!this.data[this.props.documentPropName]) {
return noData;
} else {
if (this.props.component) {
const Component = this.props.component;
return <Component {...this.props.componentProps} {...this.data} collection={this.props.collection} />;
} else {
return React.cloneElement(this.props.children, { ...this.props.componentProps, ...this.data, collection: this.props.collection });
}
}
} else {
return loadingComponent;
}
}
});
DocumentContainer.propTypes = {
collection: React.PropTypes.object.isRequired,
selector: React.PropTypes.object.isRequired,
publication: React.PropTypes.string,
terms: React.PropTypes.any,
joins: React.PropTypes.array,
loading: React.PropTypes.func,
noData: React.PropTypes.func,
component: React.PropTypes.func,
componentProps: React.PropTypes.object,
documentPropName: React.PropTypes.string,
cacheSubscription: React.PropTypes.bool
}
DocumentContainer.defaultProps = {
documentPropName: "document",
cacheSubscription: false
}
export default DocumentContainer;
Thanks! But some of this is going to change anyway as I want to replace getMeteorData
with something else. I've been looking at React Komposer, but I can't figure out how to make the component dynamic (see https://github.com/kadirahq/react-komposer/issues/69)
So maybe I'll end up using the "official" createContainer
instead.
Right now when no rows match the query for Documents, the default
Loading...
component displays instead of any children. Do you have any plans to add support for no data and/or error handling? If not, I suppose the earnest is on us to handle that... but not sure how when all we get returned isLoading...
if there is no matching data.