Разобрать параметры поиска URL в массив объектов с закодированным URL - PullRequest
0 голосов
/ 29 октября 2018

У меня проблемы с анализом строки запроса в массиве, когда в одном из значений присутствует пробел без изменения этого значения:

Пример поискового параметра:

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 голосов
/ 29 октября 2018

Аааа ... так как у вас есть панель поиска и фильтры, вот как вы можете объединить все в один JSON array и ограничить поиск и отдельные фильтры своими object с.

Рабочий пример: https://codesandbox.io/s/lx8n5x4w4z

компоненты / 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"
    }
]
0 голосов
/ 29 октября 2018

С помощью этого подхода удалось выяснить, что было нужно:

Кодирование 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)}]
0 голосов
/ 29 октября 2018

Анализируемая строка недопустима в формате JSON - вам нужно вручную вставить запятую между } { s, чтобы сделать ее действительной, после чего вы можете 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);

Тем не менее, было бы лучше исправить код, который генерирует этот ввод, если это вообще возможно, чтобы такой взлом не был необходим, и чтобы вы могли просто сделать

const arr = JSON.parse(new URLSearchParams(input).get('filters'));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...