Cómo construir una cadena de consulta con Javascript


Respuestas:


-24

Intenté buscar una respuesta a esta pregunta hace algún tiempo, pero terminé escribiendo mi propia función que extrae los valores del formulario.

No es perfecto pero se ajusta a mis necesidades.

function form_params( form )
{
    var params = new Array()
    var length = form.elements.length
    for( var i = 0; i < length; i++ )
    {
        element = form.elements[i]

        if(element.tagName == 'TEXTAREA' )
        {
            params[element.name] = element.value
        }
        else if( element.tagName == 'INPUT' )
        {
            if( element.type == 'text' || element.type == 'hidden' || element.type == 'password')
            {
                params[element.name] = element.value
            }
            else if( element.type == 'radio' && element.checked )
            {
                if( !element.value )
                    params[element.name] = "on"
                else
                    params[element.name] = element.value

            }
            else if( element.type == 'checkbox' && element.checked )
            {
                if( !element.value )
                    params[element.name] = "on"
                else
                    params[element.name] = element.value
            }
        }
    }
    return params;
}

form_params devuelve una asignación (clave -> valor) de los parámetros. la entrada es el elemento de formulario (elemento DOM)

No maneja campos que permiten la selección múltiple.


44
¿Soy solo yo o esto no responde a la pregunta? Estaba pidiendo una cadena de consulta, no una matriz asignada.
Jake Wilson

2
@JakeWilson Sí, esta respuesta solo responde la mitad de la pregunta. La matriz aún necesita entrar en un formato de cadena de consulta.
Hutch Moore

8
wow, debo haber sido un novato en JS en ese entonces. Utilizando new Array()para inicializar un diccionario. Pero, de nuevo, ¡el código se ve mucho más limpio que algunas de las tonterías que escribiría en estos días!
hasen

2
Quizás tengas en cuenta la posibilidad de editar esta respuesta o, bueno, ¿eliminarla? Tiene cada vez más votos negativos cada vez que me desplazo hacia ella = -D (incluso recuerdo el momento en que tenía una relación positiva ...)
Klesun

1
@ArturKlesun sí, no. No me importa Puede intentar pedirle a la persona que hizo la pregunta que no acepte esta respuesta.
Hasen

220

Actualización 2k20: use la solución de Josh con URLSearchParams.toString () .

Vieja respuesta:


Sin jQuery

var params = {
    parameter1: 'value_1',
    parameter2: 'value 2',
    parameter3: 'value&3' 
};

var esc = encodeURIComponent;
var query = Object.keys(params)
    .map(k => esc(k) + '=' + esc(params[k]))
    .join('&');

Para los navegadores que no admiten la sintaxis de la función de flecha que requiere ES5, cambie la .map...línea a

    .map(function(k) {return esc(k) + '=' + esc(params[k]);})

8
La mejor solución que he visto hasta ahora: muy limpia y concisa. Sin embargo, hay un par de advertencias. 1) en .map (), tanto k como params [k] deben codificarse, por ejemplo encodeURIComponent (k) y encodeURIComponent (params [k]). 2) Se le permite tener más de una instancia de un parámetro con nombre en una cadena de consulta. Si desea esa capacidad, tendrá que usar una matriz en lugar de un objeto (la mayoría de las aplicaciones no querrán o necesitarán eso).
John Deighan

9
3) No todos los navegadores admitirán la sintaxis de la función de flecha (que requiere ES5). Si desea admitir todos los navegadores (y codificar las partes), reemplace el .map () anterior con .map (function (k) {return encodeURIComponent (k) + '=' + encodeURIComponent (params [k]);})
John Deighan

1
Hermoso. Verdaderamente hermoso.
Mikko Ohtamaa

9
"No es suficiente jquery"
Eugene Pankov

1
@ user1738579 Edité la respuesta para incluir también su ejemplo para no ES5.
Taylor Edmiston

134

Si está utilizando jQuery, puede consultar jQuery.param() http://api.jquery.com/jQuery.param/

Ejemplo:

var params = {
    parameter1: 'value1',
    parameter2: 'value2',
    parameter3: 'value3' 
};
var query = $.param(params);
document.write(query);

13
¡Esta es realmente la respuesta correcta! La cadena de consulta para un formulario es $.param($('#myform').serializeArray()).
Jesse

77
@Jesse, ese sería el mismo resultado que:$('#myform').serialize()
cuchilla

94
jQuery !== JavaScript
gphilip

14
@gphilip Bueno, por eso comencé la respuesta con "Si estás usando jQuery ...". De lo contrario, si desea implementarlo en vanilla JS, puede examinar la implementación jQuery.param()aquí github.com/jquery/jquery/blob/master/src/serialize.js :)
Klemen Tušar

2
A diferencia de mi respuesta, esta admite objetos anidados comosomeStr=value1&someObj[a]=5&someObj[b]=6&someArr[]=1&someArr[]=2
Klesun

113

La API URLSearchParams está disponible en todos los navegadores modernos. Por ejemplo:

const params = new URLSearchParams({
  var1: "value",
  var2: "value2",
  arr: "foo",
});
console.log(params.toString());
//Prints "var1=value&var2=value2&arr=foo"


3
La mejor respuesta aquí imo. Solo para agregarlo, puede hacerlo params.append(key, value)más tarde para agregar nuevos parámetros de búsqueda en escenarios más complicados.
Mingwei Zhang

44
Tenga en cuenta que los valores indefinidos y nulos se incluyen en la cadena final:x=null&y=undefined
pomber

2
Además, si ya tiene un objeto URL (por ejemplo const url = new URL("https://stackoverflow.com")), puede configurar sus cadenas de consulta url.search = new URLSearchParams({foo: "bar"})ourl.searchParams.append("foo", "bar")
Miguel Pynto

Tenga en cuenta que TS advertirá sobre el uso de un objeto simple, pero no obstante funciona bien
Vadorequest

@pomber ¿Alguna buena idea para filtrar esos elementos indefinidos?
Dan Gayle

53

Esto no responde directamente a su pregunta, pero aquí hay una función genérica que creará una URL que contiene parámetros de cadena de consulta. Los parámetros (nombres y valores) se escapan de forma segura para su inclusión en una URL.

function buildUrl(url, parameters){
  var qs = "";
  for(var key in parameters) {
    var value = parameters[key];
    qs += encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
  }
  if (qs.length > 0){
    qs = qs.substring(0, qs.length-1); //chop off last "&"
    url = url + "?" + qs;
  }
  return url;
}

// example:
var url = "http://example.com/";

var parameters = {
  name: "George Washington",
  dob: "17320222"
};

console.log(buildUrl(url, parameters));
// => http://www.example.com/?name=George%20Washington&dob=17320222

1
¿Hay alguna función incorporada similar a esta en uno de los marcos javascript populares como jquery, mootools, etc.?
Samuel

Una solución JavaScript nativa más sólida está en stackoverflow.com/a/1714899/1269037
Dan Dascalescu

La implementación más extraña de la historia, ¿por qué necesita inicializar un new Arraytiempo mientras realmente la usa como un objeto? o, O
Umut Sirin

@UmutSirin Lol, sí, no sabía mucho sobre Javascript en ese momento. xD Creo que lo estaba tratando como una matriz PHP. Siéntase libre de refactorizar si lo desea.
Michael

@ Michael Jaja, sí. Acabo de enviar una edición. ¡Gracias por la respuesta!
Umut Sirin

22

Con jQuery puedes hacer esto $.param

$.param({ action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' })

// -> "action=ship&order_id=123&fees%5B%5D=f1&fees%5B%5D=f2&label=a+demo"

17

ES2017 (ES8)

Haciendo uso de Object.entries(), que devuelve una matriz de [key, value]pares de objetos . Por ejemplo, porque {a: 1, b: 2}volvería [['a', 1], ['b', 2]]. No es compatible (y no será) solo por IE.

Código:

const buildURLQuery = obj =>
      Object.entries(obj)
            .map(pair => pair.map(encodeURIComponent).join('='))
            .join('&');

Ejemplo:

buildURLQuery({name: 'John', gender: 'male'});

Resultado:

"name=John&gender=male"


10

No, no creo que JavaScript estándar tenga eso incorporado, pero Prototype JS tiene esa función (seguramente la mayoría de los otros frameworks JS también lo tienen, pero no los conozco), lo llaman serializar .

Puedo recomendar Prototype JS, funciona bastante bien. El único inconveniente que realmente he notado es su tamaño (unos pocos cientos de kb) y su alcance (mucho código para ajax, dom, etc.). Por lo tanto, si solo desea un serializador de formularios, es excesivo, y estrictamente hablando, si solo desea su funcionalidad Ajax (que es principalmente para lo que lo usé), es excesivo. A menos que tenga cuidado, puede encontrar que hace demasiado "magia" (como extender cada elemento dom que toca con las funciones de Prototype JS solo para encontrar elementos), lo que lo hace lento en casos extremos.


Solo me pregunto si hay algo incorporado. Parece que debería haberlo. Odio el prototipo, pero no estoy sosteniendo eso contra ti :)

Cuando se diseñó JavaScript, todavía no se descubrió Ajax, por lo tanto, analizar un formulario solo para obtener la cadena de consulta (que se crearía cuando se enviara) probablemente no tenía mucho sentido. Hoy lo hace, difícil ... Por cierto, en comparación con script.aculo.us, el prototipo es bueno . :)
Stein G. Strindhaug el


6

Si no desea utilizar una biblioteca, esto debería cubrir la mayoría / todos los mismos tipos de elementos de formulario.

function serialize(form) {
  if (!form || !form.elements) return;

  var serial = [], i, j, first;
  var add = function (name, value) {
    serial.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
  }

  var elems = form.elements;
  for (i = 0; i < elems.length; i += 1, first = false) {
    if (elems[i].name.length > 0) { /* don't include unnamed elements */
      switch (elems[i].type) {
        case 'select-one': first = true;
        case 'select-multiple':
          for (j = 0; j < elems[i].options.length; j += 1)
            if (elems[i].options[j].selected) {
              add(elems[i].name, elems[i].options[j].value);
              if (first) break; /* stop searching for select-one */
            }
          break;
        case 'checkbox':
        case 'radio': if (!elems[i].checked) break; /* else continue */
        default: add(elems[i].name, elems[i].value); break;
      }
    }
  }

  return serial.join('&');
}

¡Gracias! Estaba enfrentando el mismo problema que el póster original, y su función era exactamente lo que necesitaba.
dagw 03 de

4

En realidad, no necesita un formulario para hacer esto con Prototype. Simplemente use la función Object.toQueryString :

Object.toQueryString({ action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' })

// -> 'action=ship&order_id=123&fees=f1&fees=f2&label=a%20demo'

44
De acuerdo, respondiste hace casi 10 años, pero este código ahora está en desuso.
SEOF

4

Puede hacer eso hoy en día con FormDatay URLSearchParamssin la necesidad de repetir nada.

const formData = new FormData(form);
const searchParams = new URLSearchParams(formData);
const queryString = searchParams.toString();

Sin embargo, los navegadores más antiguos necesitarán un polyfill.


3

No estoy del todo seguro, recuerdo haber visto que jQuery lo hizo hasta cierto punto, pero no maneja los registros jerárquicos en absoluto, y mucho menos de una manera amigable con php.

Una cosa que sí sé con certeza es que al crear URL y pegar el producto en el dom, no solo use string-glue para hacerlo, o se abrirá a un práctico separador de páginas.

Por ejemplo, cierto software de publicidad integra la cadena de versión de lo que sea que ejecute su flash. Esto está bien cuando se trata de una cadena simple genérica de adobes, pero sin embargo, eso es muy ingenuo y explota en un lío vergonzoso para las personas que han instalado Gnash, ya que la cadena de versión de gnash contiene una licencia de copyright GPL completa, completa con URL y etiquetas <a href>. Al usar esto en el generador de anunciantes de pegamento de cadenas, se abre la página y aparece un HTML desequilibrado en el dom.

La moraleja de la historia:

   var foo = document.createElement("elementnamehere"); 
   foo.attribute = allUserSpecifiedDataConsideredDangerousHere; 
   somenode.appendChild(foo); 

No:

   document.write("<elementnamehere attribute=\"" 
        + ilovebrokenwebsites 
        + "\">" 
        + stringdata 
        + "</elementnamehere>");

Google necesita aprender este truco. Traté de informar el problema, parece que no les importa.


Tocar el asunto exacto. Document.write es tan 1995, de todos modos.

2

Como dice Stein, puede utilizar la biblioteca prototipo de JavaScript de http://www.prototypejs.org . Incluya el JS y es muy simple, ¡ $('formName').serialize()le devolverá lo que desea!



2

Puede ser un poco redundante, pero la forma más limpia que encontré se basa en algunas de las respuestas aquí:

const params: {
   key1: 'value1',
   key2: 'value2',
   key3: 'value3',
}

const esc = encodeURIComponent;
const query = Object.keys(params)
  .map(k => esc(k) + '=' + esc(params[k]))
  .join('&');

return fetch('my-url', {
  method: 'POST',
  headers: {'Content-Type': 'application/x-www-form-urlencoded'},
  body: query,
})

Fuente


1

Estas respuestas son muy útiles, pero quiero agregar otra respuesta, que puede ayudarlo a construir una URL completa. Esto le puede ayudar a concat de base url, path, hashy parameters.

var url = buildUrl('http://mywebsite.com', {
        path: 'about',
        hash: 'contact',
        queryParams: {
            'var1': 'value',
            'var2': 'value2',
            'arr[]' : 'foo'
        }
    });
    console.log(url);

Puede descargar a través de npm https://www.npmjs.com/package/build-url

Manifestación:

;(function () {
  'use strict';

  var root = this;
  var previousBuildUrl = root.buildUrl;

  var buildUrl = function (url, options) {
    var queryString = [];
    var key;
    var builtUrl;
    var caseChange; 
    
    // 'lowerCase' parameter default = false,  
    if (options && options.lowerCase) {
        caseChange = !!options.lowerCase;
    } else {
        caseChange = false;
    }

    if (url === null) {
      builtUrl = '';
    } else if (typeof(url) === 'object') {
      builtUrl = '';
      options = url;
    } else {
      builtUrl = url;
    }

    if(builtUrl && builtUrl[builtUrl.length - 1] === '/') {
      builtUrl = builtUrl.slice(0, -1);
    } 

    if (options) {
      if (options.path) {
          var localVar = String(options.path).trim(); 
          if (caseChange) {
            localVar = localVar.toLowerCase();
          }
          if (localVar.indexOf('/') === 0) {
              builtUrl += localVar;
          } else {
            builtUrl += '/' + localVar;
          }
      }

      if (options.queryParams) {
        for (key in options.queryParams) {
          if (options.queryParams.hasOwnProperty(key) && options.queryParams[key] !== void 0) {
            var encodedParam;
            if (options.disableCSV && Array.isArray(options.queryParams[key]) && options.queryParams[key].length) {
              for(var i = 0; i < options.queryParams[key].length; i++) {
                encodedParam = encodeURIComponent(String(options.queryParams[key][i]).trim());
                queryString.push(key + '=' + encodedParam);
              }
            } else {              
              if (caseChange) {
                encodedParam = encodeURIComponent(String(options.queryParams[key]).trim().toLowerCase());
              }
              else {
                encodedParam = encodeURIComponent(String(options.queryParams[key]).trim());
              }
              queryString.push(key + '=' + encodedParam);
            }
          }
        }
        builtUrl += '?' + queryString.join('&');
      }

      if (options.hash) {
        if(caseChange)
            builtUrl += '#' + String(options.hash).trim().toLowerCase();
        else
            builtUrl += '#' + String(options.hash).trim();
      }
    } 
    return builtUrl;
  };

  buildUrl.noConflict = function () {
    root.buildUrl = previousBuildUrl;
    return buildUrl;
  };

  if (typeof(exports) !== 'undefined') {
    if (typeof(module) !== 'undefined' && module.exports) {
      exports = module.exports = buildUrl;
    }
    exports.buildUrl = buildUrl;
  } else {
    root.buildUrl = buildUrl;
  }
}).call(this);


var url = buildUrl('http://mywebsite.com', {
		path: 'about',
		hash: 'contact',
		queryParams: {
			'var1': 'value',
			'var2': 'value2',
			'arr[]' : 'foo'
		}
	});
	console.log(url);


1

Sé que esta es una respuesta muy tardía pero funciona muy bien ...

var obj = {
a:"a",
b:"b"
}

Object.entries(obj).map(([key, val])=>`${key}=${val}`).join("&");

nota: object.entries devolverá clave, pares de valores

la salida de la línea anterior será a = a & b = b

Espero que ayude a alguien.

Feliz codificación ...


0

Probablemente sea demasiado tarde para responder a su pregunta.
Tenía la misma pregunta y no me gustaba seguir agregando cadenas para crear una URL. Entonces, comencé a usar $ .param como explicó Techhouse .
También encontré una biblioteca URI.js que crea las URL fácilmente para usted. Hay varios ejemplos que le ayudarán a: URI.js Documentación .
Aqui esta uno de ellos:

var uri = new URI("?hello=world");
uri.setSearch("hello", "mars"); // returns the URI instance for chaining
// uri == "?hello=mars"

uri.setSearch({ foo: "bar", goodbye : ["world", "mars"] });
// uri == "?hello=mars&foo=bar&goodbye=world&goodbye=mars"

uri.setSearch("goodbye", "sun");
// uri == "?hello=mars&foo=bar&goodbye=sun"

// CAUTION: beware of arrays, the following are not quite the same
// If you're dealing with PHP, you probably want the latter…
uri.setSearch("foo", ["bar", "baz"]);
uri.setSearch("foo[]", ["bar", "baz"]);`

0

var params = { width:1680, height:1050 };
var str = jQuery.param( params );

console.log(str)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.