ASP.NET Radiobutton mexendo com o nome (nome do grupo)
-
22-08-2019 - |
Pergunta
Recebi um controle modelo (um repetidor) listando algum texto e outra marcação. Cada item possui um radiobutão associado a ele, possibilitando ao usuário selecionar um dos itens criados pelo repetidor.
O repetidor escreve o Radiobutton definindo seu ID e nome gerado com a Convenção de Nomeação Padrão do ASP.NET, tornando cada radiobutton um 'grupo' completo. Isso significa que todos os radiobutões são independentes um do outro, o que, infelizmente, significa que posso selecionar todos os radiobutões ao mesmo tempo. O Radiobutton possui o atributo inteligente 'GroupName' usado para definir um nome comum, para que eles sejam agrupados e, portanto, dependam (para que eu possa selecionar apenas um de cada vez). O problema é: isso não funciona - o repetidor garante que o ID e, portanto, o nome (que controla o agrupamento) são diferentes.
Como eu uso um repetidor (poderia ter sido um ListView ou qualquer outro controle de banco de dados modificado), não posso usar a lista de radiobutton. Então, onde isso me deixa?
Eu sei que já tive esse problema antes e resolvi. Eu sei que quase todo programador ASP.NET deve ter tido isso também, então por que não consigo pesquisar no Google e encontrar uma solução sólida para o problema? Me deparei com soluções para aplicar o agrupamento por JavaScript (feio!) Ou mesmo para lidar com os radiobutões como controles não servidores, forçando-me a fazer um Request.Form[name]
para ler o status. Eu também tentei experimentar o substituto do atributo de nome no PreRender
Evento - Infelizmente, a página e a página principal possuem novamente esse nome para refletir o ID/nome completo, então acabo com o mesmo resultado errado.
Se você não tem uma solução melhor do que eu postei, ainda é muito bem -vindo a postar seus pensamentos - pelo menos vou saber que meu amigo 'Jack' está certo sobre o quão bagunçado asp.net às vezes é;)
Solução
Google-fu: Problema de repetidor de radiobutton asp.net
De fato, uma conseqüência infeliz do idiota de identidade. Minha opinião seria criar um - ou escolher um dos muitos disponíveis - controle personalizado que adiciona suporte para o mesmo nome no cliente.
Outras dicas
ASP.NET DICA: Usando controles de radiobutton em um repetidor
Este é o código para a função JavaScript:
function SetUniqueRadioButton(nameregex, current)
{
re = new RegExp(nameregex);
for(i = 0; i < document.forms[0].elements.length; i++)
{
elm = document.forms[0].elements[i]
if (elm.type == 'radio')
{
if (re.test(elm.name))
{
elm.checked = false;
}
}
}
current.checked = true;
}
O código está vinculado ao repetidor através do evento ItemDatabound. Para que funcione corretamente, você precisa saber o nome do controle do repetidor, bem como o nome do grupo que você está atribuindo aos Radiobuttons. Nesse caso, estou usando o RPTportfolios como o nome do repetidor e os portfólios como nome do grupo:
protected void rptPortfolios_ItemDataBound(object sender,
RepeaterItemEventArgs e)
{
if (e.Item.ItemType != ListItemType.Item && e.Item.ItemType
!= ListItemType.AlternatingItem)
return;
RadioButton rdo = (RadioButton)e.Item.FindControl("rdoSelected");
string script =
"SetUniqueRadioButton('rptPortfolios.*Portfolios',this)";
rdo.Attributes.Add("onclick", script);
}
Ref: http://www.codeguru.com/csharp/csharp/cs_controls/custom/article.php/c12371/
Vladimir Smirnov já criou um ótimo controle personalizado que resolve esse problema. Temos usado o Groupradiobutton Em nossos projetos e tem funcionado perfeitamente com botões de rádio criados dentro de um repetidor e outros fora do repetidor, sendo parte do mesmo grupo.
Eu uso o script jQuery:
<script type="text/javascript">
function norm_radio_name() {
$("[type=radio]").each(function (i) {
var name = $(this).attr("name");
var splitted = name.split("$");
$(this).attr("name", splitted[splitted.length - 1]);
});
};
$(document).ready(function () {
norm_radio_name();
});
// for UpdatePannel
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {
norm_radio_name();
});
</script>
Sei que este é um post antigo, mas eis o que acabei fazendo com uma ListView. Meu ListView está vinculado no VB CodeBehind, então não tenho certeza se isso funcionará bem com um repetidor, mas imagino que possa ser semelhante.
O que eu fiz foi lidar com o evento OncheckChanged dos Radiobuttons com uma função que não selecionava outros botões de rádio. Então procurei o botão de rádio selecionado quando eu naveguei para longe da página.
Esta solução evita JavaScript e JQuery e ignora completamente a questão do nome do grupo. Não é o ideal, mas funciona como (i) esperava. Espero que seja útil para os outros.
Markup:
<asp:ListView ID="lvw" runat="server">
<LayoutTemplate>`
<table>
<th>Radio</th>
<tr id="itemPlaceholder"></tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><asp:RadioButton ID="rdbSelect" runat="server" AutoPostBack="true"
OnCheckedChanged="rdbSelect_Changed"/></td>
</tr>
</ItemTemplate>
</asp:ListView>
Código:
Protected Sub rdbSelect_Changed(ByVal sender As Object, ByVal e As System.EventArgs)
Dim rb1 As RadioButton = CType(sender, RadioButton)
For Each row As ListViewItem In lvw.Items
Dim rb As RadioButton = row.FindControl("rdbSelect")
If rb IsNot Nothing AndAlso rb.Checked Then
rb.Checked = False
End If
Next
rb1.Checked = True
End Sub
E então, quando o botão Enviar é clicado:
Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmit.Click
For Each row As ListViewItem In lvw.Items
Dim rb As RadioButton = row.FindControl("rdbSelect")
Dim lbl As Label
If rb IsNot Nothing AndAlso rb.Checked = True Then
lbl = row.FindControl("StudentID")
Session("StudentID") = lbl.Text
End If
Next
Response.Redirect("~/TransferStudent.aspx")
End Sub
Isso pode ser um pouco melhor ..
Eu tenho um UserControl que é essencialmente um conjunto de radiobutões dentro de um repetidor, cada instância do UserControl possui uma propriedade pública chamada filterTitle, que é exclusiva por instância.
Adicione essas duas propriedades ao seu Radiobutton Substituindo o FilterTitle pelo seu próprio nome de propriedade pública
onclick='<%# "$(\"input[name$=btngroup_" + FilterTitle + "]\").removeAttr(\"checked\"); $(this).attr(\"checked\",\"checked\");" %>' GroupName='<%# "btngroup_" + FilterTitle %>'
mais simplesmente..
onclick="$('input[name$=btngroup1]').removeAttr('checked'); $(this).attr('checked','checked');" GroupName="btngroup1"
Aqui está uma solução pura de JavaScript por uma questão de completude.
Basta adicionar isso onclick
atribuir ao seu RadioButton
elemento (substitua Nome do grupo com o seu RadioButton
GroupName):
<asp:RadioButton ... GroupName="GroupName" onclick="SelectRadioButton('GroupName$',this)" ... />
E inclua este JavaScript em sua página:
<script type="text/javascript">
function SelectRadioButton(regexPattern, selectedRadioButton)
{
regex = new RegExp(regexPattern);
for (i = 0; i < document.forms[0].elements.length; i++)
{
element = document.forms[0].elements[i];
if (element.type == 'radio' && regex.test(element.name))
{
element.checked = false;
}
}
selectedRadioButton.checked = true;
}
</script>
Crie um controle personalizado e substitua exclusivo para o ListView UniqueId + GroupName
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace MYCONTROLS
{
[ToolboxData("<{0}:MYRADIOBUTTON runat=server></{0}:MYRADIOBUTTON >")]
public class MYRADIOBUTTON : RadioButton
{
public override string UniqueID
{
get
{
string uid = base.UniqueID;
//Fix groupname in lisview
if (this.Parent is ListViewDataItem && GroupName != "")
{
uid = this.Parent.UniqueID;
uid = uid.Remove(uid.LastIndexOf('$'));
uid += "$" + GroupName;
}
return uid;
}
}
}
}
É um controle personalizado que herda do Radiobutton (classe pública Myradiobutton: Radiobutton). Se você não faz nada na classe, recebe um radiobutton normal. Substituindo o únicoID, você pode alterar a lógica de como o atributo de nome é renderizado. Para ainda manter o nome exclusivo de outros controles na página (fora do ListView), você pode obter o únicoID do ListView e adicionar o nome do grupo a isso e adicioná -lo ao radiobutton.
Isso corrige o problema com o agrupamento de radiobutões em diferentes linhas em um ListView. Você pode adicionar mais lógica com uma propriedade para ativar/desativar esse recurso, para que ele se comporte como um radiobutton normal.
Sei que essa pergunta é um pouco velha, mas acho que pode ajudar alguém, postando minha solução para esse problema.
Este problema tem 2 partes:
- Para evitar a seleção de mais de um botão de rádio por vez.
- Para saber qual botão de rádio foi clicado no código do lado do servidor.
Eu tive o problema semelhante com o botão de rádio no repetidor. Encontrei solução parcial aqui:Fix simples para controles de botão de rádio em um repetidor de asp.net usando jQuery
Leia o artigo acima para entender o problema. Referi este artigo e foi uma boa ajuda. Como mencionado acima, esse problema tem duas partes, primeiro é impedir a seleção de mais de um botão de rádio por vez. Segundo, para saber qual botão de rádio foi clicado no código do lado do servidor. A solução publicada no artigo acima funcionou para mim apenas para a primeira parte. No entanto, o código escrito lá, bem como atualizações para a solução publicada, não funcionou para mim. Então, eu tive que modificá -lo um pouco para funcionar. Aqui está minha solução.
Eu queria criar enquete com o botão de voto. O nome do meu botão de rádio (ID) é PollGroupValue com o GroupName definido como PollGroup em um repetidor. Lembre -se de que o atributo GroupName no ASP.NET é renderizado como atributo de nome no HTML gerado. Meu código é o seguinte:
<script type="text/javascript">
/* Step-01: */
$(document).ready(function () {
/* Step-02: */
$("[name*='PollGroup']").each(function () {
$(this).attr('ci-name', $(this).attr('name'));
});
/* Step-03: */
$("[name*='PollGroup']").attr("name", $("[name*='PollGroup']").attr("name"));
$('#Poll1_BtnVote').click(function (e) {
/* Step - 04: */
if ($("[name*='PollGroup']").filter(':checked').length == 0) {
alert('Please select an option.');
e.preventDefault();
}
/* Step - 05: */
$("[name*='PollGroup']").each(function () {
$(this).attr('name', $(this).attr('ci-name'));
});
});
});
Etapa 1: Sempre que um botão de rádio é usado no repetidor, seu nome de grupo é alterado, pois o ASP.NET muda para torná -lo exclusivo. Portanto, cada botão de rádio obtém o nome de grupo diferente (atributo de nome na marcação gerada pelo cliente). Devido a isso, o usuário pode selecionar todas as opções ao mesmo tempo. Este problema é resolvido usando o código jQuery, conforme explicado pelos comentários subsequentes.
Etapa 2: Este bloco de código cria um novo atributo Custome chamado CI-name e copia o valor original do atributo de nome neste novo atributo personalizado. Esse processo se repete para cada botão de rádio na pesquisa. Esta etapa nos ajudaria em etapa posterior.
Etapa 3: Este bloco de código define o valor dos atributos de nome de todos os botões de rádio na pesquisa para o valor do atributo de nome do primeiro botão de rádio. Esta etapa impede que o usuário selecione mais de uma opção por vez.
Etapa 4: Este código Inside Event Handler Of Button CLIQUE DO EVENTO DE CLIQUE DA VOLTA Se o usuário verificou pelo menos uma opção. Se ele não tiver, uma mensagem de erro é mostrada.
Etapa 5: Este código Inside Event Handler Of Vote Button Click, define o valor do atributo de nome de todos os botões de rádio para seus valores originais. Isso é conseguido copiando o valor do atributo personalizado CI-name. Isso permite que o código lateral do servidor ASP.NET saiba qual botão foi realmente clicado.
Também fiquei perplexo com esse bug e decidi simplesmente deixar o repetidor em favor de construir dinamicamente uma mesa com os controles dentro. No seu controle do usuário ou na sua página, basta adicionar os seguintes elementos:
<asp:Table ID="theTable" runat="server">
<asp:TableHeaderRow runat="server">
<asp:TableHeaderCell runat="server" Text="Column 1"/>
<asp:TableHeaderCell runat="server" Text="Column 2"/>
<asp:TableHeaderCell runat="server" Text="Column 3"/>
</asp:TableHeaderRow>
</asp:Table>
Em seguida, adicione as linhas de dados no código por trás dos botões de rádio e outros controles necessários. É claro que você pode fazer o mesmo com outros elementos como o div:
<div runat="server" ID=theDiv">
</div>
Mas ainda esperamos que a equipe do ASP.NET corra esse problema infeliz com repetidores e visualizações de listagem. Ainda gosto do controle do repetidor e o uso sempre que possível.
Esta é uma abordagem do lado do servidor puro usando a reflexão. o RadioButton
Control usa o UniqueGroupName
propriedade para determinar o nome do grupo. O nome do grupo é armazenado em cache dentro do _uniqueGroupName
campo. Ao definir esse campo usando a reflexão, podemos substituir o nome do grupo padrão e usar um nome de grupo que é o mesmo em todos os botões de rádio em um repetidor. Observe que este código deve ser executado no evento 'Prerender' do controle 'Radiobutton' para garantir que o novo nome do grupo seja persistido nas postagens.
protected void rbOption_PreRender(object sender, EventArgs e)
{
// Get the radio button.
RadioButton rbOption = (RadioButton) sender;
// Set the group name.
var groupNameField = typeof(RadioButton).GetField("_uniqueGroupName", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
groupNameField.SetValue(rbOption, "MyGroupName");
// Set the radio button to checked if it was selected at the last post back.
var groupValue = Request.Form["MyGroupName"];
if(rbOption.Attributes["value"] == groupValue)
{
rbOption.Checked = true;
}
}
Esta pode não ser a solução ideal para todos, mas fiz o seguinte usando o jQuery.
<asp:RadioButton ID="rbtnButton1" groupName="Group1" runat="server" />
<asp:RadioButton ID="rbtnButton2" groupName="Group1" runat="server" />
etc...
Em seguida, inclua o código a seguir em sua página mestre. (ou todas as suas páginas)
$(function() {
//This is a workaround for Microsoft's GroupName bug.
//Set the radio button's groupName attribute to make it work.
$('span[groupName] > input').click(function() {
var element = this;
var span = $(element).parent();
if (element.checked) {
var groupName = $(span).attr('groupName');
var inputs = $('span[groupName=' + groupName + '] > input')
inputs.each(function() {
if (element != this)
this.checked = false;
});
}
});
});
Um controle/substituição personalizado para contornar o HtmlInputControl.RenderAttributes()
método ignorando o RenderedNameAttribute
propriedade:
/// <summary>
/// HACK: For Microsoft's bug whereby they mash-up value of the "name" attribute.
/// </summary>
public class NameFixHtmlInputRadioButton : HtmlInputRadioButton
{
protected override void RenderAttributes(HtmlTextWriter writer)
{
// BUG: Usage of 'HtmlInputControl.RenderedNameAttribute'
// writer.WriteAttribute("name", this.RenderedNameAttribute);
writer.WriteAttribute(@"name", Attributes[@"Name"]);
Attributes.Remove(@"name");
var flag = false;
var type = Type;
if (! string.IsNullOrEmpty(type))
{
writer.WriteAttribute(@"type", type);
Attributes.Remove(@"type");
flag = true;
}
base.RenderAttributes(writer);
if (flag && DesignMode)
{
Attributes.Add(@"type", type);
}
writer.Write(@" /");
}
}
Eu usei a mesma técnica para desmarcar outro rádio com jQuery, por favor, encontre o código abaixo
<asp:RadioButton ID="rbSelectShiptoShop" runat="server" onchange="UnCheckRadio(this);" CssClass="radioShop" />
e script abaixo
function UnCheckRadio(obj) {
$('.radioShop input[type="radio"]').attr('checked', false);
$(obj).children().attr('checked', true);
}