Estou Tentando fazer uma taglib genérica para combos ajax usando vraptor, e eu preciso que o serialize me retorne sem um padrão de chaves.
O Método do Controlador eh o seguinte:
@Get @Path("/evento/comboAjax.json")
public void loadCidade(String siglaEstado) {
List<Cidade> cidade = cidadeDao.listaPorEstado(siglaEstado);
result.use(Results.json()).withoutRoot().from(cidade)
.exclude("sigla_estado")
.serialize();
}
e ele retorna um json da seguinte forma:
onde codigo e nome são os nomes dos campos desse caso específico, porém esses campos em outros casos poderão ter nomes diferentes, então eu precisava que a função me retornasse sempre algo como
Tem como fazer esse tipo de customização?
Obrigado
Por que que você, ao invés de customizar a JSON, não muda um pouquinho a forma de ler esse JSON:
Imagine a seguinte function que recebe esse JSON ai em cima:
function fazAlgo(json){
for (var i = 0; i < json.length; i++){
var obj = json[i];
console.log(obj[0]);// aqui pega o primeiro valor do obj... tanto faz se é codigo ou value
console.log(obj[1]);// aqui pega o segundo valor do obj... tanto faz se é nome ou text
}
}
é que no caso estou usando a “$.getJSON” do jquery e achei que seria mais “elegante” mudar o json em si, fora que é bom saber se há como customizar o json pois pode ser útil em outros casos tb, mas vlw pela dica também vou tentar dessa forma.
Dá para usar dessa forma sim. Não acho que fique menos elegante, visto que esse é um comportamento bem interessante de um objeto javascript (se comporta igualzinho um Array).
Eu não sei se tem como mudar a forma de serializar o JSON…
Mas dá para você alterar o toString() da sua classe:
public class Cidade {
private int codigo;
private String nome;
@Override
public String toString(){
return "{'value':'"+codigo+"', 'text':'"+nome+"'}";
}
// getters e setters
}
de uma olhadinha na doc do Xstream lá tem como vc customizar como os atributos são serializaveis…
porém como quer algo generico, eu criaria uma classe que recebe 2 params: “value” e “text”, nela vc pode receber seus valores e serializar.
Colocar isso no toString nao me parece uma boa opção, apesar de resolver seu problema.
abrasss
bacana isso, mas fazendo isso nao deixaria de funcionar alguma outra funcao do propio vraptor q pode estar usando essa tostring padrao?
[quote=Rafael Guerreiro]Dá para usar dessa forma sim. Não acho que fique menos elegante, visto que esse é um comportamento bem interessante de um objeto javascript (se comporta igualzinho um Array).
Eu não sei se tem como mudar a forma de serializar o JSON…
Mas dá para você alterar o toString() da sua classe:
[code]
public class Cidade {
private int codigo;
private String nome;
@Override
public String toString(){
return “{‘value’:’”+codigo+"’, ‘text’:’"+nome+"’}";
}
// getters e setters
}
[/code][/quote]
[quote=renanreismartins]de uma olhadinha na doc do Xstream lá tem como vc customizar como os atributos são serializaveis…
porém como quer algo generico, eu criaria uma classe que recebe 2 params: “value” e “text”, nela vc pode receber seus valores e serializar.
Colocar isso no toString nao me parece uma boa opção, apesar de resolver seu problema.
abrasss[/quote]Vou dar uma estudada nesse Xstream vlw pela dica
Não é uma boa opção, embora seja sempre importante a gente sobrescrever o toString(), equals(Object obj), hash()…
É verdade, me esqueci desse cara! Essa é uma boa solução para você.
@rishibashi
Não. É sempre importante sobrescrever esses métodos. Mesmo que não fiquem em formato de objetos JS…
estou começando a considerar a opção de tratar isso no JS como primeiramente vc mencionou, problema eh q meu jquery nao esta muito atualizado, como vcs modificariam a funcao a seguir para aceitar qualquer tipo de chave do json?
[code](function($) {
$.fn.emptySelect = function() {
return this.each(function() {
if(this.tagName == ‘SELECT’)
this.options.length = 0;
});
}
$.fn.loadSelect = function(data) {
return this.emptySelect().each(function() {
if(this.tagName == 'SELECT') {
var selectElement = this;
$.each(data, function(index, optionData) {
var option = new Option(optionData.nome, optionData.codigo);
if($.browser.msie) {
selectElement.add(option);
} else {
selectElement.add(option, null);
}
});
}
});
}
})(jQuery);[/code]
Eu mudaria isso tudo aqui:
// $.each(data, function(index, optionData) {
// data aqui nesse caso é um array, correto?
$(data).each(function() {
// Insere um option dentro do select.
// Assim, você não precisa verificar se é IE...
// O ideal é sempre usar as coisas nativas do jQuery que ele verifica isso e faz da forma certa para você.
$(selectElement).append('<option value="' + this[0] + '">' + this[1] + '</option>');
// var option = new Option(optionData.nome, optionData.codigo);
// if($.browser.msie) {
// selectElement.add(option);
// } else {
// selectElement.add(option, null);
// }
});
[quote=Rafael Guerreiro]Eu mudaria isso tudo aqui:
// $.each(data, function(index, optionData) {
// data aqui nesse caso é um array, correto?
$(data).each(function() {
// Insere um option dentro do select.
// Assim, você não precisa verificar se é IE...
// O ideal é sempre usar as coisas nativas do jQuery que ele verifica isso e faz da forma certa para você.
$(selectElement).append('<option value="' + this[0] + '">' + this[1] + '</option>');
// var option = new Option(optionData.nome, optionData.codigo);
// if($.browser.msie) {
// selectElement.add(option);
// } else {
// selectElement.add(option, null);
// }
});
[/quote]
Gostei desse jeito de montar, fica ateh mais simples que ooutro menos linhas, mas o this[0] nao esta funcionando, fica undefined, ele soh funciona se eu chamar assim: this.nome, this.codigo
O data nesse caso eh passado da seguinte forma
[code]function comboAjax() {
var estadoValue = $("#${comboPai}").val();
var dropdownSet = $("#${id}");
if (estadoValue.length == 0)
{
dropdownSet.attr(“disabled”, true);
dropdownSet.emptySelect();
}
else
{
dropdownSet.attr(“disabled”, false);
var contextoWithoutLastSlash = contexto.substring(0, contexto.length - 1);
$.getJSON(contextoWithoutLastSlash+"${url}", {
siglaEstado : estadoValue
}, function(data) {
dropdownSet.loadSelect(data);
});
}
}[/code]
Isso tudo ai quem tem que fazer é o usuário do seu plugin?
Que tal se a pessoa pudesse fazer algo assim:
function comboAjax() {
var estadoValue = $("#${comboPai}").val();
var dropdownSet = $("#${id}");
if (estadoValue.length == 0) {
dropdownSet.attr("disabled", true);
dropdownSet.emptySelect();
} else {
var contextoWithoutLastSlash = contexto.substring(0, contexto.length - 1);
dropdownSet.loadSelect({
url: contextoWithoutLastSlash + '${url}',
data: {'siglaEstado':estadoValue}
});
// dropdownSet.attr("disabled", false);
// var contextoWithoutLastSlash = contexto.substring(0, contexto.length - 1);
// $.getJSON(contextoWithoutLastSlash+"${url}", {
// siglaEstado : estadoValue
// }, function(data) {
// dropdownSet.loadSelect(data);
// });
}
}
Assim você faz a pessoa chamar pouca coisa e o seu plugin faz o restante (como desabilitar o campo enquanto carrega).
Aqueles valores que eu passei para você são os atributos que precisamos enviar para o $.ajax do jQuery: http://api.jquery.com/jQuery.ajax/.
De uma olhada no jQuery Boilerplate para você ver algumas boas práticas na hora de criar plugins: http://br.jqueryboilerplate.com/
por enquanto eu to soh tentando fazer funcionar ela generica mesmo p/ dpeois organizar, a funcao loadselect nao ehj nem originalmente minha, eu peguei um a biblioteca qe achei em um exemplo antiogo aki mesmo no forum e estou tentando fazer funcionar genericamente
Se vc quer que sempre retorne isso:
[{"value": 5330,"text": "BRASILIA"}]
o jeito mais fácil é criar uma classe:
public class UmNomeAqui {
private Integer value;
private String text;
//construtor/getters
}
e transformar a lista de cidade (ou de qqer outra coisa) na lista dessa classe nova…
assim ele vai fazer direitinho.
[quote=Lucas Cavalcanti]Se vc quer que sempre retorne isso:
[{"value": 5330,"text": "BRASILIA"}]
o jeito mais fácil é criar uma classe:
public class UmNomeAqui {
private Integer value;
private String text;
//construtor/getters
}
e transformar a lista de cidade (ou de qqer outra coisa) na lista dessa classe nova…
assim ele vai fazer direitinho.[/quote]
Hmmm entao criando outra classe, parece uma boa alternativa tb. Vlw.
consegui resolver, nao sei se foi da melhor forma mas funcionou, resolvi por javascript mesmo, gostaria saber da opiniao de vcs pois como se trata de javascript, será que terei problemas com essa implementação em algum navegador?
[code]
//Convertendo objeto json em string
var tmp = JSON.stringify(data);
//extraindo chaves da string do json
var chave = tmp.substring(tmp.search(""")+1,tmp.search("":"));
var valor = tmp.substring(tmp.search(","")+2,tmp.indexOf("":",tmp.search(","")));
//substituindo chaves originais pelas novas chaves “chave” e “valor"
tmp = tmp.split(”""+ chave +"":").join("“chave”:");
tmp = tmp.split("""+ valor + “”:").join("“valor”:");
//convertendo a string em objeto json novamente
data = eval(’(’ + tmp + ‘)’);
//chamando funcao para montar o select
dropdownSet.loadSelect(data);[/code]
o que isso deveria fazer?
Isso faz o q eu precisava, que é generalizar as chaves do Json, eu transformo o objeto json em string, extraio as chaves e colco valores padrao nela, entao todo json que passar por esse codigo as chaves serão “chave” e “valor”, depois eu converto o json novamente em objeto e envio p/ funcao de montaro select, comentei o codigo para melhor compreensao.
jeito mais fácil de fazer isso:
var json = ....
for (var chave in json) {
var valor = json[chave];
//resto do seu código
}
[quote=Lucas Cavalcanti]jeito mais fácil de fazer isso:
[code]
var json = …
for (var chave in json) {
var valor = json[chave];
//resto do seu código
}
[/code][/quote]
vo testar aqui vlw a dica