diff --git a/examples/ReactExample/components/styles.js b/examples/ReactExample/components/styles.js
index 47bab8a4..d31ea264 100644
--- a/examples/ReactExample/components/styles.js
+++ b/examples/ReactExample/components/styles.js
@@ -9,6 +9,9 @@ module.exports = React.StyleSheet.create({
alignItems: 'stretch',
backgroundColor: '#ffffff',
},
+ navigator: {
+ flex: 1,
+ },
listItem: {
borderColor: "#c8c7cc",
borderBottomWidth: 0.5,
@@ -18,16 +21,15 @@ module.exports = React.StyleSheet.create({
flex: 1,
height: 44,
},
- listItemCheckboxContainer: {
- paddingLeft: 12,
- paddingRight: 4,
+ listItemLeftSide: {
flexDirection: 'column',
+ alignItems: 'center',
justifyContent: 'center',
+ width: 36,
},
listItemCheckbox: {
borderColor: "#000",
borderWidth: 0.5,
- marginRight: 8,
width: 16,
height: 16,
},
diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js
index afebfc09..e817d8c0 100644
--- a/examples/ReactExample/components/todo-app.js
+++ b/examples/ReactExample/components/todo-app.js
@@ -1,50 +1,85 @@
'use strict';
const React = require('react-native');
-const TodoList = require('./todo-list');
+const TodoItem = require('./todo-item');
+const TodoListView = require('./todo-listview');
const realm = require('./realm');
+const styles = require('./styles');
const { NavigatorIOS } = React;
class TodoApp extends React.Component {
- componentWillMount() {
- let todoLists = realm.objects('TodoList');
+ constructor(props) {
+ super(props);
+ let todoLists = realm.objects('TodoList');
if (todoLists.length < 1) {
realm.write(() => {
realm.create('TodoList', {name: 'Todo List', items: []});
});
}
+ // This is a Results object, which will live-update.
this.todoLists = todoLists;
+ this.state = {};
+ }
+
+ get currentListView() {
+ let refs = this.refs.nav.refs;
+ return refs.listItemView || refs.listView;
}
render() {
- let list = this.todoLists[0];
-
let route = {
- title: list.name,
- component: TodoList,
+ title: 'My Todo Lists',
+ component: TodoListView,
passProps: {
- ref: 'todoList',
- list: list,
+ ref: 'listView',
+ items: this.todoLists,
+ onPressItem: (list) => this._onPressTodoList(list),
},
rightButtonTitle: 'Add',
- onRightButtonPress: () => this._addNewItem(list)
+ onRightButtonPress: () => this._addNewTodoList(),
};
return (
-
+
);
}
- _addNewItem(list) {
+ _addNewTodoItem(list) {
realm.write(() => {
list.items.push({text: ''});
});
- let todoList = this.refs.nav.refs.todoList;
- todoList.setState({editingRow: list.items.length - 1});
+ this._setEditingRow(list.items.length - 1);
+ }
+
+ _addNewTodoList() {
+ realm.write(() => {
+ realm.create('TodoList', {name: '', items: []});
+ });
+
+ this._setEditingRow(this.todoLists.length - 1);
+ }
+
+ _onPressTodoList(list) {
+ this.refs.nav.push({
+ title: list.name,
+ component: TodoListView,
+ passProps: {
+ ref: 'listItemView',
+ items: list.items,
+ rowClass: TodoItem,
+ },
+ rightButtonTitle: 'Add',
+ onRightButtonPress: () => this._addNewTodoItem(list),
+ });
+ }
+
+ _setEditingRow(rowIndex) {
+ // Update the state on the currently displayed TodoList to edit this new item.
+ this.currentListView.setState({editingRow: rowIndex});
}
}
diff --git a/examples/ReactExample/components/todo-item-checkbox.js b/examples/ReactExample/components/todo-item-checkbox.js
deleted file mode 100644
index 6cfbd3cf..00000000
--- a/examples/ReactExample/components/todo-item-checkbox.js
+++ /dev/null
@@ -1,22 +0,0 @@
-'use strict';
-
-const React = require('react-native');
-const styles = require('./styles');
-
-const { Text, TouchableWithoutFeedback, View } = React;
-
-class TodoItemCheckbox extends React.Component {
- render() {
- return (
-
-
-
- {this.props.checked ? '✓' : ''}
-
-
-
- );
- }
-}
-
-module.exports = TodoItemCheckbox;
diff --git a/examples/ReactExample/components/todo-item-delete.js b/examples/ReactExample/components/todo-item-delete.js
deleted file mode 100644
index 4a260d4b..00000000
--- a/examples/ReactExample/components/todo-item-delete.js
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict';
-
-const React = require('react-native');
-const styles = require('./styles');
-
-const { Text, TouchableWithoutFeedback, View } = React;
-
-class TodoItemDelete extends React.Component {
- render() {
- return (
-
-
- 𐄂
-
-
- );
- }
-}
-
-module.exports = TodoItemDelete;
diff --git a/examples/ReactExample/components/todo-item.js b/examples/ReactExample/components/todo-item.js
index 988b7240..d02667b5 100644
--- a/examples/ReactExample/components/todo-item.js
+++ b/examples/ReactExample/components/todo-item.js
@@ -1,97 +1,54 @@
'use strict';
const React = require('react-native');
-const TodoItemCheckbox = require('./todo-item-checkbox');
-const TodoItemDelete = require('./todo-item-delete');
+const TodoListItem = require('./todo-list-item');
const realm = require('./realm');
const styles = require('./styles');
-const { Text, TextInput, View } = React;
+const { Text, TouchableWithoutFeedback, View } = React;
-class TodoItem extends React.Component {
+class TodoItem extends TodoListItem {
constructor(props) {
super(props);
- this._onChangeText = this._onChangeText.bind(this);
this._onPressCheckbox = this._onPressCheckbox.bind(this);
}
- componentDidMount() {
- // The autoFocus prop on TextInput was not working for us :(
- this._focusInputIfNecessary();
+ get done() {
+ return this.props.item.done;
}
- componentDidUpdate() {
- this._focusInputIfNecessary();
+ set done(done) {
+ this.props.item.done = done;
}
- render() {
- let item = this.props.item;
- let deleteButton;
- let contents;
+ get text() {
+ return this.props.item.text;
+ }
- if (this.props.editing) {
- contents = (
-
- );
- } else {
- contents = (
-
- {item.text}
-
- );
-
- deleteButton = (
-
- );
- }
+ set text(text) {
+ this.props.item.text = text;
+ }
+ renderLeftSide() {
return (
-
-
- {contents}
- {deleteButton}
-
+
+
+
+ {this.done ? '✓' : ''}
+
+
+
);
}
- _onChangeText(text) {
- realm.write(() => {
- this.props.item.text = text;
- });
-
- this.forceUpdate();
- }
-
_onPressCheckbox() {
- let item = this.props.item;
realm.write(() => {
- item.done = !item.done;
+ this.done = !this.done;
});
this.forceUpdate();
}
-
- _focusInputIfNecessary() {
- if (!this.props.editing) {
- return;
- }
-
- let input = this.refs.input;
- if (!input.isFocused()) {
- input.focus();
- }
- }
}
module.exports = TodoItem;
diff --git a/examples/ReactExample/components/todo-list-item.js b/examples/ReactExample/components/todo-list-item.js
new file mode 100644
index 00000000..c8a39b32
--- /dev/null
+++ b/examples/ReactExample/components/todo-list-item.js
@@ -0,0 +1,115 @@
+'use strict';
+
+const React = require('react-native');
+const realm = require('./realm');
+const styles = require('./styles');
+
+const { Text, TextInput, TouchableWithoutFeedback, View } = React;
+
+class TodoListItem extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this._onChangeText = this._onChangeText.bind(this);
+ }
+
+ get done() {
+ let items = this.props.item.items;
+ return items.length > 0 && Array.prototype.every.call(items, (item) => item.done);
+ }
+
+ get text() {
+ return this.props.item.name;
+ }
+
+ set text(text) {
+ this.props.item.name = text;
+ }
+
+ componentDidMount() {
+ // The autoFocus prop on TextInput was not working for us :(
+ this._focusInputIfNecessary();
+ }
+
+ componentDidUpdate() {
+ this._focusInputIfNecessary();
+ }
+
+ render() {
+ return (
+
+ {this.renderLeftSide()}
+ {this.renderText()}
+ {this.renderRightSide()}
+
+ );
+ }
+
+ renderLeftSide() {
+ return (
+
+ {this.done ? '✓' : '⁃'}
+
+ );
+ }
+
+ renderRightSide() {
+ // Only show the delete button while not editing the text.
+ return this.props.editing ? null : this.renderDelete();
+ }
+
+ renderText() {
+ if (this.props.editing) {
+ return (
+
+ );
+ } else {
+ return (
+
+ {this.text}
+
+ );
+ }
+ }
+
+ renderDelete() {
+ return (
+
+
+ 𐄂
+
+
+ );
+ }
+
+ _onChangeText(text) {
+ realm.write(() => {
+ this.text = text;
+ });
+
+ this.forceUpdate();
+ }
+
+ _focusInputIfNecessary() {
+ if (!this.props.editing) {
+ return;
+ }
+
+ let input = this.refs.input;
+ if (!input.isFocused()) {
+ input.focus();
+ }
+ }
+}
+
+module.exports = TodoListItem;
diff --git a/examples/ReactExample/components/todo-list.js b/examples/ReactExample/components/todo-list.js
deleted file mode 100644
index af06dacc..00000000
--- a/examples/ReactExample/components/todo-list.js
+++ /dev/null
@@ -1,79 +0,0 @@
-'use strict';
-
-const React = require('react-native');
-const TodoItem = require('./todo-item');
-const realm = require('./realm');
-const styles = require('./styles');
-
-const { ListView, Text, View } = React;
-
-class TodoList extends React.Component {
- constructor(props) {
- super(props);
-
- this.dataSource = new ListView.DataSource({
- rowHasChanged: (row1, row2) => row1 !== row2
- });
-
- this.state = {};
- this._renderRow = this._renderRow.bind(this);
- }
-
- render() {
- let dataSource = this.dataSource.cloneWithRows(this.props.list.items);
-
- return (
-
-
-
- Press Cmd+R to reload,{'\n'}
- Cmd+D for dev menu
-
-
- );
- }
-
- _renderRow(item, sectionIndex, rowIndex) {
- return (
- this._onPressRow(rowIndex)}
- onPressDelete={() => this._onPressDeleteRow(rowIndex)}
- onEndEditing={() => this._onEndEditingRow(rowIndex)} />
- );
- }
-
- _onPressRow(rowIndex) {
- let editingRow = this.state.editingRow;
-
- if (editingRow != null && editingRow != rowIndex) {
- this._onEndEditingRow(editingRow);
- }
-
- this.setState({editingRow: rowIndex});
- }
-
- _onPressDeleteRow(rowIndex) {
- let items = this.props.list.items;
-
- realm.write(() => items.splice(rowIndex, 1));
-
- this.forceUpdate();
- }
-
- _onEndEditingRow(rowIndex) {
- let items = this.props.list.items;
-
- // Delete the todo item if it doesn't have any text.
- if (!items[rowIndex].text) {
- realm.write(() => items.splice(rowIndex, 1));
- }
-
- if (this.state.editingRow == rowIndex) {
- this.setState({editingRow: null});
- }
- }
-}
-
-module.exports = TodoList;
diff --git a/examples/ReactExample/components/todo-listview.js b/examples/ReactExample/components/todo-listview.js
new file mode 100644
index 00000000..00eab958
--- /dev/null
+++ b/examples/ReactExample/components/todo-listview.js
@@ -0,0 +1,97 @@
+'use strict';
+
+const React = require('react-native');
+const TodoListItem = require('./todo-list-item');
+const realm = require('./realm');
+const styles = require('./styles');
+
+const { ListView, Text, View } = React;
+
+class TodoListView extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.dataSource = new ListView.DataSource({
+ rowHasChanged: (row1, row2) => row1 !== row2
+ });
+
+ this.state = {};
+ this.renderRow = this.renderRow.bind(this);
+ }
+
+ componentWillUpdate(nextProps, nextState) {
+ let editingRow = this.state.editingRow;
+
+ if (editingRow != null && editingRow != nextState.editingRow) {
+ let item = this.props.items[editingRow];
+
+ // The item may have already been deleted.
+ if (item) {
+ this._deleteItemIfEmpty(item);
+ }
+ }
+ }
+
+ render() {
+ // Clone the items into a new Array to prevent unexpected errors from changes in length.
+ let items = Array.from(this.props.items);
+ let dataSource = this.dataSource.cloneWithRows(items);
+
+ return (
+
+
+
+ Press Cmd+R to reload,{'\n'}
+ Cmd+D for dev menu
+
+
+ );
+ }
+
+ renderRow(item, sectionIndex, rowIndex) {
+ let RowClass = this.props.rowClass || TodoListItem;
+
+ return (
+ this._onPressRow(item, rowIndex)}
+ onPressDelete={() => this._onPressDeleteRow(item, rowIndex)}
+ onEndEditing={() => this._onEndEditingRow(item, rowIndex)} />
+ );
+ }
+
+ _onPressRow(item, rowIndex) {
+ let onPressItem = this.props.onPressItem;
+ if (onPressItem) {
+ onPressItem(item, rowIndex);
+ return;
+ }
+
+ // If no handler was provided, then default to editing the row.
+ this.setState({editingRow: rowIndex});
+ }
+
+ _onPressDeleteRow(item) {
+ realm.write(() => realm.delete(item));
+
+ this.forceUpdate();
+ }
+
+ _onEndEditingRow(item, rowIndex) {
+ this._deleteItemIfEmpty(item);
+
+ if (this.state.editingRow == rowIndex) {
+ this.setState({editingRow: null});
+ }
+ }
+
+ _deleteItemIfEmpty(item) {
+ // The item could be a TodoList or a Todo.
+ if (!item.name && !item.text) {
+ realm.write(() => realm.delete(item));
+ }
+ }
+}
+
+module.exports = TodoListView;