Saturday, November 19, 2016

Meteor + React => Adding and deleting rows and better CSS!

There's a default way to add and delete rows in react-bootstrap-table, though I'll have to tweak it for my use-case eventually. Looks like I'll have to add my own "add columns" code too (as well as the ability to specify where the new rows/columns will be inserted). For now though, my app looks like this, which I think is pretty cute!
What I learned:

First off, in order to add/delete a row in react-bootstrap-table, you do this:
<BootstrapTable data={this.state.cellData}
    striped={true}
    insertRow={true}
    deleteRow={true}
    selectRow={{ mode: 'checkbox' }}
    options={{
        onAddRow: this.props.onAddRow,
        onDeleteRow: this.props.onDeleteRow
    }}>
    <TableHeaderColumn width='150px' dataField='id' isKey={true}>Product ID</TableHeaderColumn>
    <TableHeaderColumn width='150px' dataField='name'>Product Name</TableHeaderColumn>
    <TableHeaderColumn width='150px' dataField='price'>Product Price</TableHeaderColumn>
</BootstrapTable>

However, that landed me on multiple warnings that I couldn't figure out... These are the warnings in case you landed here from Google:
Failed to decode downloaded font: http://localhost:3000/fonts/glyphicons-halflings-regular.woff2
(index):1 OTS parsing error: invalid version tag
(index):1 Failed to decode downloaded font: http://localhost:3000/fonts/glyphicons-halflings-regular.woff
(index):1 OTS parsing error: invalid version tag
(index):1 Failed to decode downloaded font: http://localhost:3000/fonts/glyphicons-halflings-regular.ttf
(index):1 OTS parsing error: invalid version tag
(index):1 Failed to decode downloaded font: http://localhost:3000/packages/bootswatch_readable/bootswatch/fonts/glyphicons-halflings-regular.woff2
(index):1 OTS parsing error: invalid version tag
(index):1 Failed to decode downloaded font: http://localhost:3000/packages/bootswatch_readable/bootswatch/fonts/glyphicons-halflings-regular.woff
(index):1 OTS parsing error: invalid version tag
(index):1 Failed to decode downloaded font: http://localhost:3000/packages/bootswatch_readable/bootswatch/fonts/glyphicons-halflings-regular.ttf
(index):1 OTS parsing error: invalid version tag

After a bunch of Googling and trying various solutions there, I ended up looking at the react-bootstrap package, which includes a stylesheet from a link as opposed to a package install. So, I ended up removing bootstrap and adding a link-rel to my app header, like this (in App.jsx)
render() {
    console.log('rendering app');
    return (
        <div className="container">
            <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css" />
            <header>
                <h1>CompareApp Draft</h1>
            </header>
            <br />
//...etc.

I also removed the style imports from client/main.jsx. Please note! Do not remove the import 'react-bootstrap-table/css/react-bootstrap-table.css'; line!

I removed it, and that caused me to realize that all styles imported using <link rel> have higher precedence than the styles in main.css, which is not something we want (probably)...

There are multiple ways to import CSS files in a React app.

  • Previously, we talked about adding it in App.jsx as an import. 
  • Above, we talked about <link rel> in the HTML. 
  • The other way is using @import in main.css.
It seems like I couldn't get @import to work with CSS files from the node_modules/ folder, although it seems like that should be possible (see the link I referenced in my previous post).

@imports go to the top of main.css, and everything defined below them takes higher precedence (as long as they have the same specificity). So, I removed the <link rel> from App.jsx, and now my main.css looks like:
@import "https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css";

That's kind of it for this post.

Friday, November 18, 2016

Meteor + React => react-bootstrap-table

I have this idea to build an app that would help people make decisions by allowing them to move away from making Excel lists and figuring what matters most to them in their heads (or am I the only one who does that?). Anyway, I have a project started here and the readme explains it better than I will now.

After much deliberation I decided to build the app in Meteor, and, since React seems to be so hot right now, make my UI in React. Please note that I have zero experience building web apps from scratch, though I've contributed code to some at work. Still, getting it somewhere where I can just write code is simply not as straight-forward as it should be, especially if you've never used npm before for example.

Meteor version: 1.4.2.3

The versions of the other stuff I'm using:

  • react: 15.4.0
  • react-bootstrap-table: 2.5.8
  • bootstrap: 3.3.7
  • react-dom: 15.4.0
  • react-widgets: 3.4.4


My OS is MacOs Sierra and I'm using iTerm2 because it can do split screen (among other things).

I already did the Meteor tutorial for React, and created my new app. Basically I'm currently between steps 2 and 3 in that tutorial with my new app. Note: console.log works just fine in react, although some of the tutorials were installing other packages for logging (don't do that for now!).

Since my whole app is built on tables, I decided to install react-bootstrap-table. And, since that depends on bootstrap, I also installed that. So you can do:
meteor npm install --save bootstrap react-bootstrap-table
And now, to use it!
The example on the npm packages page was pretty useless for me. Do not install boostrap (yet). We may end up wanting react-bootstrap, but not right now.

It took me a while to find some code that worked, and I found this in an answer, so I'll just paste below. I've put this in a ui/components/App.jsx file instead of the imports/ui/App.jsx file the tutorial suggested. I'll also replace the imports/ui/Task.jsx with a ui/components/Cells.jsx or something of the sort later.

My ui/components/App.jsx file looks like this:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';

var products = [];

function addProducts(quantity) {
  const startId = products.length;
  for (let i = 0; i < quantity; i++) {
    const id = startId + i;
    products.push({
      id: id,
      name: 'Item name ' + id,
      price: 2100 + i
    });
  }
}

addProducts(5);


// App component - represents the whole app
export default class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      ecsData: []
    };
  }

  componentDidMount() {
    this.setState({
      ecsData: products
    });
  }

  render() {
    console.log('rendering app');
    return (
      <div classname="container">
        <header>
          <h1>CompareApp Draft</h1>
        </header>
        <BootstrapTable data="{this.state.ecsData}">
          <TableHeaderColumn datafield="id" iskey="{true}" width="150px">Product ID</TableHeaderColumn>
          <TableHeaderColumn datafield="name" width="220px">Product Name</TableHeaderColumn>
          <TableHeaderColumn datafield="price" width="180px">Product Price</TableHeaderColumn>
        </BootstrapTable>
      </div>
    );
  }
}

Not completely what I want, but baby steps. Remember, I have absolutely zero experience with this.

Apparently, the only way to get css files from the node_modules folder into your app currently, is to do one of the things enumerated here. The only one that actually worked for me though, was the import. And the import seems to have to be done in client/main.jsx.

My client/main.jsx file looks like this:
import 'react-bootstrap-table/css/react-bootstrap-table.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';

import App from '../ui/components/App.jsx';
 
Meteor.startup(() => {
  render(<App />, document.getElementById('render-target'));
});

And the app, running at http://localhost:3000/, looks like this: