setData(data, keepDataPath) {
    // parse raw data or keep existing object/array
    let jsonData
    let jsonDataInvalid = false
    if (typeof data === 'string') {
      try {
        jsonData = JSON.parse(data)
      } catch (e) {
        jsonData = null
        jsonDataInvalid = true
      }
    } else {
      jsonData = data
    }

    // create data path
    let dataPath = this.state.options[OPTIONS.DATA_PATH]
    if (!keepDataPath) {
      dataPath = Utils.getArrayStringAccessor(jsonData)
    }

    // if viewing only, data path is already applied
    if (!this.state.viewOnly) {
      // get nested object using data path
      try {
        jsonData = Utils.accessObjectByString(jsonData, dataPath)
      } catch (e) {
        jsonData = null
        jsonDataInvalid = true
      }

      if (!jsonData) {
        jsonDataInvalid = true
      }
    }

    // update state with new data and data path
    this.setState(
      {
        jsonData,
        jsonDataInvalid,
        options: Object.assign({}, this.state.options, {
          [OPTIONS.DATA_PATH]: dataPath
        })
      },
      () => {
        // force update UI
        $(document).trigger('reloadDataPreview')
        $(document).trigger('setTextFieldValue', {
          name: OPTIONS.DATA_PATH,
          value: dataPath
        })

        // stop loading
        setTimeout(() => {
          this.setState({
            loading: false,
            fileDialogOpen: false
          })
        }, 300)
      }
    )
  }
Parses a JSON string and sets the resulting array/object as the current
JSON data for populating