Cannot use Material UI with Meteor


#1

I just tried using Meteor + Material UI but I keep on getting multiple errors. Any specific ideas on how I can make it work? Especially, relating to NPM depends and how I import the components, because those are the reasons for most of the errors I get.


#2

Can you give more details? What are the errors exactly? What is it that you do to make the errors occur? And show some codes as well.


#3

type:

meteor npm install --save material-ui

meteor npm install --save react-tap-event-plugin

done.

Don’t forget: Put injectTapEventPlugin(); on meteor.startup (client). . Code Example (main.js)

import React, { Component } from 'react';
import {cyan500} from 'material-ui/styles/colors';
import ReactDOM from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import Header from './components/Header';
import injectTapEventPlugin from 'react-tap-event-plugin';
// Customiza Colores (test)
const muiTheme = getMuiTheme({
  palette: {
    primary1Color: cyan500
  },
});
class App extends Component {
  render() {
    return (
      <MuiThemeProvider muiTheme={muiTheme}>
        <Header />
      </MuiThemeProvider>
    );
  }
}
Meteor.startup(() => {
  injectTapEventPlugin();
  ReactDOM.render(<App />, document.querySelector('.the-container'));
});

Good luck!


#4

Hi,

I did the following…

(1) Have a fontloader.js in the client startup…

// async loader for fonts
// https://github.com/typekit/webfontloader

/* eslint-disable */

import { Meteor } from 'meteor/meteor';

Meteor.startup(() => {
  WebFontConfig = {
    google: { families: ['Roboto:400,300,500:latin'] }
  };

  (() => {
    const wf = document.createElement('script');
    wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
      '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
    wf.type = 'text/javascript';
    wf.async = 'true';
    const s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(wf, s);
    // console.log("async fonts loaded", WebFontConfig);
  })();
});

/* eslint-enable */

(2) Add material ui and react-tap-event-plugin. I also removed all the bootstrap stuff from my project, and used the grid system only from skeleton css. Otherwise it messes up with some of the components. You should not that Matreriul ui has no griding of any kind as far as i can tell. Maybe try materialcss if skeletoncss is no good for you.

"dependencies": {
    "bootstrap": "^3.3.6",
    "jquery": "^2.2.3",
    "jquery-validation": "^1.15.0",
    "material-ui": "^0.15.1",
    "react": "^15.0.2",
    "react-addons-pure-render-mixin": "^15.0.2",
    "react-bootstrap": "^0.29.4",
    "react-dom": "^15.0.2",
    "react-komposer": "^1.8.0",
    "react-router": "^2.4.0",
    "react-router-bootstrap": "^0.23.0",
    "react-tap-event-plugin": "^1.0.0"
  }

(3) Components look like this… the below is a generic text field i use in forms…

import React from 'react';

import TextField from 'material-ui/TextField';

export class Q6ATextField extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      value: '',
      errorText: '',
    };
  }

  handleChange(event) {
    this.setState({ value: event.target.value });

    if (this.state.value !== null) {
      this.props.output(event.target.value);
    }
  }

  handleBlur(event) {
    if (this.props.required) {
      if (event.target.value === '') {
        this.setState({ errorText: 'This field is required' });
      } else {
        this.setState({ errorText: '' });
      }
    }
  }

  render() {
    return (
      <span>
        <TextField
          type={this.props.type}
          value={this.state.value}
          hintText={this.props.label}
          floatingLabelText={this.props.label}
          errorText={this.state.errorText}
          onChange={this.handleChange.bind(this)}
          onBlur={this.handleBlur.bind(this)}
        /><br />
      </span>
    );
  }
}

Q6ATextField.propTypes = {
  required: React.PropTypes.bool.isRequired,
  type: React.PropTypes.oneOf(['text', 'email', 'password']),
  label: React.PropTypes.string.isRequired,
  output: React.PropTypes.func.isRequired,
};

My experience with it has been pretty good so far. The documentation is a bit sketchy, but pretty good overall.

The main downside is you will end up with lots of state management. I think redux is too much, and without state management (i.e. if you are looking to use stateless components) lots of the material ui stuff will be hard to handle, imo.

I’m just starting to try Mobx (unsuccessfully so far) to handle the state related issues better. Thanks so much.

Tat


#5

Thank you all!

It’s working partially now but I still get unknown prop errors for most of the components. Any ideas on how to fix that?


#6

Did you click that link in the warning? https://facebook.github.io/react/warnings/unknown-prop.html

As of React 15.2.0, you can no longer just pass whatever props you want into something that doesn’t recognize it.

@tathagatbanerjee: I definitely wouldn’t put DOM-related code in Meteor.startup! That belongs in a high-level React componentDidMount method (like in a layout component).


#7

Fair enough. I did not know what to do with it originally and left it there. I’ll move it to the main mui component. Thanks for picking up the error and pointing it out. Too many folks would simply have had a laugh at a noob error and not taken the time to point it out. Appreciate it.

Tat


#8

Everyone is a noob, we’re just different levels of noob. :wink: There’s always something more to learn.


#9

I am using Material-UI with meteor 1.4, and I am very happy that I chose to use it. Works pretty much as expected (and even beyond expectations :slight_smile:)

  • As it was pointed out above, there is an issue with the proptypes that ends up in warnings in the latest release of react. These should go away after updating Material-UI though, as this should be addressed in changes for an updated version of Material-UI (I am guessing this should be version 0.15.3). The warning is just a warning though, and for now can also be ignored (although - they are indeed a bit annoying and potentially takes away focus from real issues. , so I will try to update the Material-UI package as soon as possible myself. At the time of writing it seems it was released a few hours ago …)

  • As for fonts: I have chosen to add the roboto font via a statically added link in the /client/head.html file:

      <head>
          ...
         <link rel='stylesheet' type='text/css' href='https://fonts.googleapis.com/css?family=Roboto:400,300,500'>
         ...
      </head>
    
  • I am referring to my MainLayout in my (simplified) /imports/startup/client/routes.jsx file (using FlowRouter):

      import React from 'react';
      import {mount} from 'react-mounter';
    
      import {MainLayout} from '../../ui/layouts/MainLayout.jsx'
    
      import YourComponent from '../../ui/components/YourComponent/YourComponent.jsx'
    
      FlowRouter.route('/', {
          action() {
              mount(MainLayout, {
                  content: <YourComponent />
              })
          }
      });
    
  • And my (simplified) MainLayout.jsx file looks like this:

      import React from 'react';
      import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
      import getMuiTheme from 'material-ui/styles/getMuiTheme';
      import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
      import injectTapEventPlugin from 'react-tap-event-plugin';
      injectTapEventPlugin();
    
      const lightMuiTheme = getMuiTheme(lightBaseTheme);
    
      export const MainLayout = ({content}) => (
          <MuiThemeProvider muiTheme={lightMuiTheme}>
              <main>
                  {content}
              </main>
          </MuiThemeProvider>
      )
    
  • After this any component should be able to use the recipes from the Material-UI wesite, like for instance the FlatButton:

      import React from 'react';
      import FlatButton from 'material-ui/FlatButton';
    
      const FlatButtonExampleSimple = () => (
        <div>
          <FlatButton label="Default" />
          <FlatButton label="Primary" primary={true} />
          <FlatButton label="Secondary" secondary={true} />
          <FlatButton label="Disabled" disabled={true} />
        </div>
      );
    
      export default FlatButtonExampleSimple;
    

Good luck :ok_hand: