将URL搜索参数解析为具有编码url的对象数组

时间:2018-10-29 01:20:05

标签: javascript reactjs react-router

当其中一个值中存在空格而不更改该值时,我无法将查询字符串解析为数组:

示例搜索参数:

filters=%7B"value"%3A"test%20ing"%2C"type"%3A"search"%7D%20%7B"dataIndex"%3A"plan"%2C"value"%3A"5b61c72879f4503bfa9e729b"%2C"type"%3A"oid"%7D

分析结果:(字符串)

{"value":"test ing","type":"search"} {"dataIndex":"plan","value":"5b61c72879f4503bfa9e729b","type":"oid"}

所需结果:数组

[
  {"value":"test ing","type":"search"}, 
  {"dataIndex":"plan","value":"5b61c72879f4503bfa9e729b","type":"oid"}
]

尝试的方法

["{"value":"test", "ing","type":"search"}", "{"dataIndex":"plan","value":"5b61c72879f4503bfa9e729b","type":"oid"}"]

我在每个space之间都有一个object,并希望跳到split,但是当使用这种方法时,如果存在空格,它将分裂value见上文。

为达到预期效果,建议的方法是什么?

3 个答案:

答案 0 :(得分:0)

已解析的字符串不是有效的JSON-您必须在} {之间手动插入逗号以使其生效,然后您可以在{{1}内JSON.parse } s:

[]

也就是说,如果可能的话,最好修复生成此输入的代码,这样就不必进行这样的修改,而您只需这样做

const input = 'filters=%7B"value"%3A"test%20ing"%2C"type"%3A"search"%7D%20%7B"dataIndex"%3A"plan"%2C"value"%3A"5b61c72879f4503bfa9e729b"%2C"type"%3A"oid"%7D';
const malformedFilters = new URLSearchParams(input).get('filters');
const fixedFilters = malformedFilters.replace('} {', '}, {');
const arr = JSON.parse('[' + fixedFilters + ']');
console.log(arr);

答案 1 :(得分:0)

嗯...由于您拥有搜索栏和过滤器,因此可以将所有内容组合到一个JSON array中,并将搜索和单个过滤器限制在自己的object中。

工作示例:https://codesandbox.io/s/lx8n5x4w4z

components / SearchForm.js

import filter from "lodash/filter";
import map from "lodash/map";
import React, { Component } from "react";
import ParsedURI from "./parsedURI";
import FilterField from "./filterField";
import SearchField from "./searchField";

// initial form state
const initialState = {
  fieldsCount: 1,
  search: { value: "", type: "search" },
  filters: [{ id: 1, dataIndex: "", value: "", type: "" }]
};

export default class SearchForm extends Component {
  state = { ...initialState };

  // handles search input changes
  handleSearchChange = ({ target: { name, value } }) => {
    this.setState(prevState => ({
      search: { ...prevState.search, [name]: value }
    }));
  };

  // handles all filter changes (select, select and input) by their id
  handleFilterChange = ({ target: { id, name, value } }) => {
    this.setState(prevState => ({
      filters: map(
        prevState.filters,
        item =>
          parseInt(id, 10) === item.id
            ? { ...item, [name]: value }
            : { ...item }
      )
    }));
  };

  // adds a new field to filters and updates a field counter
  addField = () => {
    this.setState(prevState => ({
      filters: [
        ...this.state.filters,
        {
          id: this.state.fieldsCount + 1,
          dataIndex: "",
          value: "",
          type: ""
        }
      ],
      fieldsCount: this.state.fieldsCount + 1
    }));
  };

  // removes selected filter field by id
  deleteField = id => {
    this.setState(prevState => ({
      filters: filter(this.state.filters, field => field.id !== id)
    }));
  };

  // resets form to initial state and updates the URL
  handleReset = () =>
    this.setState(
      {
        encodedJSON: "",
        filtersJSON: "",
        ...initialState
      },
      () => this.props.history.replace("/search/")
    );

  // handles form submission
  handleSubmit = e => {
    e.preventDefault();
    const { search, filters } = this.state;

    const arr = [];

    // flatten search and filter options into a single array
    arr.push({ ...search }, ...filters);

    // convert that array to a JSON array
    const filtersJSON = JSON.stringify(arr);

    // convert JSON array to an encodedURI
    const encodedJSON = `filters=${encodeURI(filtersJSON)}`;

    // set to state and push to URL
    this.setState(
      {
        encodedJSON,
        filtersJSON: arr,
        ...initialState
      },
      () => this.props.history.push(`/search/filters?${encodedJSON}`)
    );
  };

  render = () => (
    <div style={{ padding: "5px 20px" }}>
      <form onSubmit={this.handleSubmit}>
        <SearchField
          value={this.state.search.value}
          handleSearchChange={this.handleSearchChange}
        />
        <p>Select a filter, option, and input a value:</p>
        {map(this.state.filters, ({ id, ...rest }) => (
          <FilterField
            key={id}
            id={id}
            deleteField={this.deleteField}
            filtersLength={this.state.filters.length}
            handleFilterChange={this.handleFilterChange}
            {...rest}
          />
        ))}
        <br />
        <button
          type="button"
          style={{ marginRight: 20, marginBottom: 20 }}
          className="uk-button uk-button-primary"
          onClick={this.addField}
        >
          Add Filter
        </button>
        <br />
        <div style={{ marginTop: 40 }}>
          <button
            type="button"
            style={{ marginRight: 20, marginBottom: 20, float: "left" }}
            className="uk-button uk-button-danger"
            onClick={this.handleReset}
          >
            Reset Form
          </button>
          <button className="uk-button uk-button-secondary" type="submit">
            Submit
          </button>
        </div>
      </form>
      {this.state.encodedJSON && this.state.filtersJSON ? (
        <ParsedURI
          encodedJSON={this.state.encodedJSON}
          filtersJSON={this.state.filtersJSON}
        />
      ) : null}
    </div>
  );
}

编码的URI字符串示例:

%5B%7B%22value%22:%22Test%20ing%22,%22type%22:%22search%22%7D,%7B%22id%22:1,%22dataIndex%22:%22topic%22,%22value%22:%22React%20Local%20State%22,%22type%22:%22name%22%7D,%7B%22id%22:2,%22dataIndex%22:%22subcategory%22,%22value%22:%22123456789%22,%22type%22:%22oid%22%7D%5D

示例解码的URL字符串JSON.stringify(filtersJSON, null, 4)

[
    {
        "value": "Test ing",
        "type": "search"
    },
    {
        "id": 1,
        "dataIndex": "topic",
        "value": "React Local State",
        "type": "name"
    },
    {
        "id": 2,
        "dataIndex": "subcategory",
        "value": "123456789",
        "type": "oid"
    }
]

答案 2 :(得分:0)

通过使用这种方法能够弄清所需的内容:

编码URL助手:

const encodeUrl = filters => filters.reduce((str, filter) => `${str}${URI.encode(JSON.stringify(filter))}&&`, '')

格式查询助手:

const formatQuery = query => compact(query.split('&&') || [])

解析查询:

const filters = URI.decode(this.props.location.search).replace('?filters=', '')

API(将查询过滤器传递给api服务):

${PLANS_API_ENDPOINT}?filters=[${formatQuery(query)}]