====================================================== ReactJS to toggle the list of visible data sources ====================================================== In this sample we will write a simplistic web page utilizing ReactJS to show two lists of available and visible data sources side by side and toggle items between them. - We focus on applying ReactJS for a complex data structure. - We will use the :ref:`POST_connection/loadRemoteSchema` and :ref:`POST_connection` APIs. Prerequisites ------------- #. This sample is a continuation of :doc:`code_react_manage_the_list_of_categories`. #. This sample re-uses the folder structure created in :doc:`code_react_manage_the_list_of_categories`. #. The uncompressed, development version of react.js and react-dom.js has been put into "ui\_react\_examples/vendor" folder. (They are in the starter kit available at https://facebook.github.io/react/downloads.html) Thinking in React ----------------- That is the name of a `ReactJS guide `__ about building apps. In this sample we will follow the same process to build the page to toggle visible data sources. Start with a mock ----------------- .. figure:: /_static/images/Connection_Move_Data_Source_to_Visible_List.jpg :width: 611px Move data sources between the two lists For simplicity in this sample, we will skip the search boxes and the Table, View, Stored Procedure and Function groups and only keep the schema and data sources. The response from the API is detailed in :ref:`POST_connection/loadRemoteSchema`. Basically the ``response.dBSource.querySources`` is an array of schemas, and each schema contains the ``querySources`` which is an array of query sources. Break the UI into a component hierarchy --------------------------------------- We will have two side-by-side lists of schema items, and inside each schema item is a list of query source items. Following would be our component hierarchy: - App - List of SchemaItems - List of available QuerySourceItems - List of SchemaItems - List of visible QuerySourceItems Available QuerySourceItem and visible QuerySourceItem differ only in the checking condition for ``selected`` value, so we can use a single component code and pass "Available" or "Visible" to each instance via ``props``. Build a static version in React ------------------------------- #. In "ui\_react\_examples" folder, create a blank text file and name it "ReactJS to toggle the list of visible data sources.html". #. Edit the file with a text editor such as Notepad or Notepad++ and paste the following HTML code: .. comment: pygments code highlighting does not support React jsx yet .. code-block:: text
Identify the minimal UI state ----------------------------- The pieces of data in our application: - The API url - The connection string - The server type id - The data returned from the API - The value of selected field Our state would be the dBSource.querySources part of the response since it contains the list of schemas and also the selected value. The API url, connection string and server type id would be passed in via props. .. code-block:: javascript ReactDOM.render(, document.getElementById('app')); Identify where the state should live ------------------------------------ The state should be in the root App since all other components only need a part of that state. Now we can implement getInitialState, componentDidMount and fetchData methods inside the root App. .. code-block:: javascript getInitialState: function() { return { schemaArray: new Array() }; }, componentDidMount: function() { this.fetchData(); }, fetchData: function() { var postData = new Object(); postData.connectionString = this.props.connectionString; postData.serverTypeId = this.props.serverTypeId; $.ajax({ url: this.props.rootUrl + "connection/loadRemoteSchema/", type: "POST", data: JSON.stringify(postData), contentType: "application/json", success: function(response) { if (response.success) { this.setState({ schemaArray: response.dBSource.querySources }); } else { console.log(JSON.stringify(response)); } }.bind(this), error: function(response) { console.log(JSON.stringify(response)); } }) }, Add inverse data flow --------------------- Because the state is in the parent component App, a toggle action that happens inside a QuerySourceItem cannot update it directly. Instead, App needs to pass a callback to QuerySourceItem to update the state whenever a toggle happens. For our hierarchy, the callback would be passed from App to SchemaItem first, then from SchemaItem to QuerySourceItem. We will name the callback ``reflectChangedData`` as normal: .. comment: pygments code highlighting does not support React jsx yet .. code-block:: text // .. in App return // .. in SchemaItem return // .. in QuerySourceItem return (
  • {this.props.querySource.name}
  • ) // .. in QuerySourceItem reflectChangedData: function(querySourceId) { // the callback passed in by SchemaItem this.props.reflectChangedData(querySourceId); } // .. in SchemaItem reflectChangedData: function(querySourceId) { // the callback passed in by App this.props.reflectChangedData(this.props.schema.id, querySourceId); } // .. in App reflectChangedData: function(schemaId, querySourceId) { var schemas = this.state.schemaArray; var schemaPos = schemas.map(function(x) {return x.id; }).indexOf(schemaId); var querySources = schemas[schemaPos].querySources; var querySourcePos = querySources.map(function(x) {return x.id; }).indexOf(querySourceId); schemas[schemaPos].querySources[querySourcePos].selected = ! schemas[schemaPos].querySources[querySourcePos].selected; this.setState({schemaArray : schemas}); } #. The inverse flow begins in QuerySourceItem where we bind the id of the query source to the callback function in SchemaItem. #. In SchemaItem we bind the id of the schema to the callback function in App. #. In App we use the id of the schema and the id of the query source to find the updated item to toggle its selected value. #. The setState call in App will render all the components. Implement pushData ------------------ We will also add a Save button and implement pushData method to save the connection together with visible data sources. .. code-block:: javascript pushData: function() { var postData = { id: null, name: this.props.connectionName, serverTypeId: this.props.serverTypeId, connectionString: this.props.connectionString, visible: true, dBSource: { querySources: this.state.schemaArray.map(function(schema){ schema.querySources = schema.querySources.filter(function(querySource){ return querySource.selected; }); return schema; }) } }; $.ajax({ url: this.props.rootUrl + "connection/", type: "POST", data: JSON.stringify(postData), contentType: "application/json", success: function(response) { if (!response.success) { console.log(JSON.stringify(response)); } else { console.log("connectionId: "+response.connectionId); } }, error: function(response) { console.log(JSON.stringify(response)); } }) } Summary ------- In this sample, we followed the recommended ReactJS design approach to implement the list of visible data sources. .. container:: toggle .. container:: header Full source code in this sample: .. comment: pygments code highlighting does not support React jsx yet .. code-block:: text