0

I have a list of records. Each record has a button that sends the current records id to a toggle function for editing. The function receives the id of the record, but when it tries to set a state value using that id, it returns null. I need it for use in another functions, the handleEditField() and handleEditItem() functions.

import React, { Component, PropTypes} from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
import { reduxForm } from 'redux-form';
import { updateTerritoryGeography } from '../actions/index.js';

import { getTerritoryGeographies, deleteTerritoryGeography } from '../actions/index';

import TerritoryTabs from './territory-tabs';

class TerritoryGeographyList extends Component {

  constructor(props) {
    super(props);

    this.state = {
      editing: null
    };

    this.toggleEditing = this.toggleEditing.bind(this);
  }

  componentWillMount() {
    this.props.getTerritoryGeographies(this.props.params.id);
    this.setState({editing : null});
  }

  toggleEditing( recordId ) {
     console.log("the current id of the record being edited");
     console.log( recordId );

     this.setState({editing : recordId});

     console.log("the editing value from state")
     console.log(this.state.editing);
  }

  // used when a single field is edited and enter is pressed
  handleEditField( event ) {
    if ( event.keyCode === 13) {
      console.log("handleEditField");
      console.log(event);
      let target = event.target,
      update = {};

      console.log("state value being called int handleEditField()");
      console.log(this.state.editing);
      update.id = this.state.editing;
      update[ target.name ] = target.value;

      this.updateTerritoryGeography( update, update.id );
    }
  }

  // used when multiple fields are edited
  handleEditItem() {
    let itemId = this.state.editing;

    this.updateTerritoryGeography({
      tpslead__Country__c: this.refs[ `Country_${ itemId }`].value,
      tpslead__State__c: this.refs[ `State/Province_${ itemId }`].value,
      tpslead__Zip_Start__c: this.refs[ `Postal_Start_${ itemId }`].value,
      tpslead__Zip_End__c: this.refs[ `Postal_End_${ itemId }`].value
    }, itemId)

  }


  onDeleteClick(id) {
    this.props.deleteTerritoryGeography(id);
  }

  static contextTypes = {
    router: PropTypes.object
  }

  return this.props.territoryGeographies.map((geography) => {

      // edit mode
      if (this.state.editing === geography.Id ) {
          return (

        <tr key={ geography.Id }>
          <th scope="row" data-label="Country">
            <div className="slds-truncate">
              <input onKeyDown={ this.handleEditField }
                className="slds-input inline"
                type="text"
                ref={`Country_${geography.Id}`}
                title="Country"
                defaultValue={geography.tpslead__Country__c}
              />
            </div>
          </th>
          <td data-label="State/Provice">
            <div className="slds-truncate">
              <input onKeyDown={ this.handleEditField}
                className="slds-input"
                type="text"
                ref={`State/Province_${geography.Id}`}
                title="State/Province"
                defaultValue={geography.tpslead__State__c}
              />
            </div>
          </td>
          <td data-label="Postal Start">
            <div className="slds-truncate">
              <input onKeyDown={ this.handleEditField}
               className="slds-input"
                type="text"
                ref={`Postal_Start_${geography.Id}`}
                title="Postal Start"
                defaultValue={geography.tpslead__Zip_Start__c}
              />
            </div>
          </td>
          <td data-label="Postal End">
            <div className="slds-truncate">
              <input onKeyDown={ this.handleEditField}
                className="slds-input"
                type="text"
                ref={`Postal_End_${geography.Id}`}
                title="Postal End"
                defaultValue={geography.tpslead__Zip_End__c}
              />
            </div>
          </td>
          <td className="slds-text-align--right" data-label="Action">
            <button onClick={this.handleEditItem} className="slds-button slds-button--icon" title="edit">
            <svg className="slds-button__icon" aria-hidden="true">
              <use xlinkHref={checkIcon}></use>
            </svg>
                  <span className="slds-assistive-text">Update</span>
                </button>
                <button onClick={ this.toggleEditing.bind(null, geography.Id)} className="slds-button slds-button--icon" title="delete" data-aljs="modal" data-aljs-show="PromptConfirmDelete">
            <svg className="slds-button__icon" aria-hidden="true">
              <use xlinkHref={closeIcon}></use>
            </svg>
                  <span className="slds-assistive-text">Cancel</span>
                </button>
          </td>
        </tr>

      );
      }
      // view mode
      else {
        return (
          <tr key={geography.Id} onClick={ this.toggleEditing.bind(null, geography.Id) }>
              <th scope="row" data-label="Country">
                <div className="slds-truncate">{geography.tpslead__Country__c}</div>
              </th>
              <td data-label="State/Provice">
                <div className="slds-truncate">{geography.tpslead__State__c}</div>
              </td>
              <td data-label="Postal Start">
                <div className="slds-truncate">{geography.tpslead__Zip_Start__c}</div>
              </td>
              <td data-label="Postal End">
                <div className="slds-truncate">{geography.tpslead__Zip_End__c}</div>
              </td>
              <td className="slds-text-align--right" data-label="Action">
                <button onClick={ this.toggleEditing.bind(null, geography.Id)} className="slds-button slds-button--icon" title="edit">
                      <svg className="slds-button__icon" aria-hidden="true">
                        <use xlinkHref={editIcon}></use>
                      </svg>
                      <span className="slds-assistive-text">Edit</span>
                    </button>
                    <button onClick={() => this.onDeleteClick(geography.Id)} className="slds-button slds-button--icon" title="delete" data-aljs="modal" data-aljs-show="PromptConfirmDelete">
                      <svg className="slds-button__icon" aria-hidden="true">
                        <use xlinkHref={deleteIcon}></use>
                      </svg>
                      <span className="slds-assistive-text">Delete</span>
                    </button>
              </td>
          </tr>
      );
      }
  });
  }

  render() {
    return (
    <TerritoryTabs id={this.props.params.id} listTab="geography">
          <Link to={"territory/" + this.props.params.id + "/geography/new"} className="slds-button slds-button--brand">
            Add New Geography
          </Link>
          <table className="slds-table slds-table--bordered slds-table--cell-buffer slds-m-top--large">
              <thead>
                <tr className="slds-text-title--caps">
                  <th scope="col">
                    <div className="slds-truncate" title="Country">Country</div>
                  </th>
                  <th scope="col">
                    <div className="slds-truncate" title="State/Provice">State/Provice</div>
                  </th>
                  <th scope="col">
                    <div className="slds-truncate" title="Postal Start">Postal Start</div>
                  </th>
                  <th scope="col">
                    <div className="slds-truncate" title="Postal End">Postal End</div>
                  </th>
                  <th className="slds-text-align--right" scope="col">
                    <div className="slds-truncate" title="Action">Action</div>
                  </th>
                </tr>
              </thead>
              <tbody>
            {this.renderTerritoryGeographyList()}
              </tbody>
            </table>
    </TerritoryTabs>
    );
  }
}

function mapStateToProps(state) {
  console.log(state);
  return { territoryGeographies: state.territoryGeographies.all
        };
}

export default connect(mapStateToProps, { getTerritoryGeographies, deleteTerritoryGeography, updateTerritoryGeography })(TerritoryGeographyList);

Here is a screenshot from the console.

enter image description here

enter image description here

Tyler Zika
  • 1,144
  • 2
  • 14
  • 25
  • *"`setState()` does not immediately mutate `this.state` but creates a pending state transition. Accessing `this.state` after calling this method can potentially return the existing value."* https://facebook.github.io/react/docs/react-component.html#setstate – Felix Kling Feb 07 '17 at 21:03
  • @FelixKling how do I access the state value after it has been set in other functions of my component? – Tyler Zika Feb 07 '17 at 21:07
  • Changing the state will trigger a rerender (i.e. `render` will be called again) at which point `this.state` will have the updated value. There is nothing special you have to do, it just works. – Felix Kling Feb 07 '17 at 21:09
  • @FelixKling it's returning null in other function. Check updated post. – Tyler Zika Feb 07 '17 at 21:11
  • this.setState({value: event.target.value}, function () { console.log(this.state.value); }); – Hajji Tarik Feb 07 '17 at 21:11
  • That's an unrelated error (has nothing to do with your original question). That means the value of `this` is `null`, not that `this.state.editing` is `null`. That means that the function you are calling doesn't have access to the component instance. Your code doesn't actually look valid. It seems you have a `return` statement directly in the `class` body, which is not valid. It's difficult to suggest what is wrong if the code you posted shouldn't work at all. – Felix Kling Feb 07 '17 at 21:12
  • @HajjiTarik I don't want to call another function right away though. I want to call the functions after the user is done editing with enter or clicking an button – Tyler Zika Feb 07 '17 at 21:13
  • @FelixKling you are right. I updated my question. – Tyler Zika Feb 07 '17 at 21:17
  • 1
    Regarding the error in your screenshot, you have to do the same thing with `handleEditField` that you do with `toggleEditing` in the constructor. See [Unable to access React instance (this) inside event handler](http://stackoverflow.com/q/29577977/218196) – Felix Kling Feb 07 '17 at 21:18
  • @FelixKling I get no errors on using return in my code. I do get an error for `this.state.editing` being null – Tyler Zika Feb 07 '17 at 21:19
  • No! The error means that **`this`** is `null`. "Cannot read property 'state' of null" means that somewhere you do `foo.state`, where `foo` has the value `null`. You are doing `this.state` in your code, hence `this` is `null`. See my previous comment for how to fix that. That error has *nothing* to do with `editing` or your state changes. – Felix Kling Feb 07 '17 at 21:19

0 Answers0