Db12797
Db12797

Reputation: 31

Using a button to open a dialog box to get some user input

I'm using React and firebase to create a simplified slack and using MDl for styles. I'm trying to integrate a button that opens up a dialog box to get some user input, in this case the name of a new chat room, and then when submitted it will send the data to firebase and store it in the rooms array and display the new room name in the list. I have already set up the form to get user input and then I tried to refactor it to work in a dialog box and I seem stuck on how to get the dialog box to work. Here is my whole component:

import React, { Component } from 'react';
import './RoomList.css';
import dialogPolyfill from 'dialog-polyfill';

class RoomList extends Component {
  constructor(props) {
    super(props);
    this.state = { rooms: [] };
    this.roomsRef = this.props.firebase.database().ref('rooms');
    this.handleChange = this.handleChange.bind(this);
    this.createRoom = this.createRoom.bind(this);
  }

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

  createRoom(e) {
    e.preventDefault();
    this.roomsRef.push({ name: this.state.name });
    this.setState({ name: "" });
  }

  componentDidMount() {
    this.roomsRef.on('child_added', snapshot => {
      const room = snapshot.val();
      room.key = snapshot.key;
      this.setState({ rooms: this.state.rooms.concat( room ) });
    })
  }

  dialogBox(e){
    const dialogButton = document.getElementsByClassName('dialog-
    button');
    const dialog = document.getElementById('dialog');
    if (! dialog.showModal) {
      dialogPolyfill.registerDialog(dialog);
    }
    dialogButton.onClick( (e) => {
      dialog.showModal();
    });
    dialog.document.getElementsByClassName('submit-close').onCLick( 
    (e) => {
      dialog.close();
    });
  }


  render() {
    const roomlist = this.state.rooms.map( (room) =>
      <span className="mdl-navigation__link" key={room.key}>
      {room.name}</span>
    );

    const newListForm = (
      <div id="form">
        <button className="mdl-button mdl-js-button mdl-button--
        raised mdl-js-ripple-effect dialog-button">Add room</button>

        <dialog id="dialog" className="mdl-dialog">
          <h3 className="mdl-dialog__title">Create Room name</h3>
          <div className="mdl-dialog__content">
            <p>Enter a room name</p>
          </div>
          <div className="mdl-dialog__actions">
            <form onSubmit={this.createRoom}>
              <div className="mdl-textfield mdl-js-textfield">
                <input type="text" value={this.state.name} 
                className="mdl-textfield__input" id="rooms" onChange=
                {this.handleChange} />
                <label className="mdl-textfield__label" 
                htmlFor="rooms">Enter room Name...</label>
                <button type="submit" className="mdl-button submit-
                close">Submit</button>
                <button type="button" className="mdl-button submit-
                close">Close</button>
              </div>
            </form>
          </div>
        </dialog>
      </div>

    );
    return (
        <div className="layout mdl-layout mdl-js-layout mdl-layout--
        fixed-drawer mdl-layout--fixed-header">
          <header className="header mdl-layout__header mdl-color--
          grey-100 mdl-color-text--grey-600">
            <div className="mdl-layout__header-row">
              <span className="mdl-layout-title">Bloc Chat</span>
              <div className="mdl-layout-spacer"></div>
            </div>
          </header>
          <div className="drawer mdl-layout__drawer mdl-color--blue-
          grey-900 mdl-color-text--blue-grey-50">
            <header className="drawer-header">
              <span>{newListForm}</span>
            </header>
            <nav className="navigation mdl-navigation mdl-color--
            blue-grey-800">
              <div>{roomlist}</div>
              <div className="mdl-layout-spacer"></div>
            </nav>
          </div>
        </div>
    );
  }
}

export default RoomList;

Upvotes: 0

Views: 2886

Answers (2)

canaan seaton
canaan seaton

Reputation: 6868

Here is a simple sample on how to build a modal with the new portal API provided from React v16.xx

Working demo can be found here. Just use the dropdown to navigate to the simple portal demo. A snapshot of the full code base can be found on github.

Working Code

import React, { Component } from "react";
import { createPortal } from "react-dom";

import "./simple-portal.css";

export default class SimplePortal extends Component {
    constructor() {
        super();

        this.state = {
            list: [],
            input: "",
            showDialog: false
        };

        this._onChange = this._onChange.bind(this);
        this._onSubmit = this._onSubmit.bind(this);
    }

    _onChange(e) {
        let input = e.target.value;

        this.setState({ input });
    }

    _onSubmit(e) {
        e.preventDefault();
        let showDialog = false;

        // Dont Mutate the State!!!
        let list = this.state.list.slice();

        list.push(this.state.input);

        this.setState({ showDialog, list, input: "" });
    }

    render() {
        const { showDialog, list, input } = this.state;

        return (
            <div className="container">
                <div>
                    <button
                        className="btn"
                        onClick={e =>
                            this.setState({
                                showDialog: !showDialog
                            })
                        }
                    >
                        Add Item
                    </button>
                </div>

                {/* Render Items from List */}
                <div>
                    <ul>
                        {list.map(item => {
                            return <li key={item}>{item}</li>;
                        })}
                    </ul>
                </div>

                {/* Show Modal - Renders Outside React Hierarchy Tree via Portal Pattern */}
                {showDialog === true ? (
                    <DialogModal>
                        <div className="dialog-wrapper">
                            <h1>New List Item</h1>
                            <form onSubmit={this._onSubmit}>
                                <input type="text" value={input} onChange={this._onChange} />
                            </form>
                        </div>
                    </DialogModal>
                ) : null}
            </div>
        );
    }
}

class DialogModal extends Component {
    constructor() {
        super();
        this.body = document.getElementsByTagName("body")[0];
        this.el = document.createElement("div");
        this.el.id = "dialog-root";
    }

    componentDidMount() {
        this.body.appendChild(this.el);
    }

    componentWillUnmount() {
        this.body.removeChild(this.el);
    }

    render() {
        return createPortal(this.props.children, this.el);
    }
}

Upvotes: 1

Logan Shoemaker
Logan Shoemaker

Reputation: 4497

I don't see any event listeners on your buttons that would trigger a rendering of the modal. I would approach this by specifying an onClick event that would update the state which would render the modal/dialogue box.

Another solution, which may be the way you are thinking, is to have the state change to render the modal/dialogue box as visible from within the createRoom() function. Remember, updating state or getting new props will trigger a rendering of the component. You are trying to update the state to re-render your component with the modal/dialogue being shown.

Sorry if I misunderstood the question or your goal.

Upvotes: 0

Related Questions