Omikron Theta
Omikron Theta

Reputation: 151

Adding attribute to checkbox list at runtime

So I have some code that dynamically creates an ASP.NET form based on an XML input file. I'm trying to add attributes to the controls at run time and I'm having some weird issues with list items.

My Server Side Code looks something like this:

Me.radioButtonList = New RadioButtonList()
Me.dropDownList = New DropDownList()
Me.listControl = Nothing
If controlType = "dropdown" Then
    Me.listControl = Me.dropDownList
Else
    Me.listControl = Me.radioButtonList
End If
For Each ansElement As Answer In strAnswers
    Dim newListItem = New ListItem(ansElement.AnswerText, ansElement.AnswerText)
    If ansElement.ActionID IsNot Nothing AndAlso ansElement.ActionID <> "" Then
        newListItem.Attributes.Add("actionID", ansElement.ActionID)
    End If
    Me.listControl.Items.Add(newListItem)
Next
Me.listControl.ID = controlID
Me.Controls.Add(Me.listControl)

The problem is when I run the code and the page is render the attributes are being added to the proceeding span tag of the control not the input item itself. So the rendered HTML ends up looking like this.

<span actionID="1">
    <input id="lst_dynamic_MedIllnesses_0" name="ctl00$MainContentPlaceHolder$FormGenerator1$lst_dynamic_MedIllnesses$lst_dynamic_MedIllnesses_0" value="None" type="checkbox">
    <label for="lst_dynamic_MedIllnesses_0">None</label>
</span>

What do I have to do to get the actionID attribute to be added to the actual input control and not the span tag?

Thanks!

Upvotes: 0

Views: 3010

Answers (1)

Sergey Litvinov
Sergey Litvinov

Reputation: 7478

I suppose you are talking about RadioButtonList. The problem with it is that it uses RadioButton control, and it has 3 attributes properties - Attributes, InputAttributes and LabelAttributes. Each of them is used for specific html element.

The problem with RadioButtonList, is that it uses just Attributes property, and doesn't use InputAttributes. Here is code of RadioButtonList.RenderItem method:

protected virtual void RenderItem(ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
{
  if (repeatIndex == 0)
  {
    this._cachedIsEnabled = this.IsEnabled;
    this._cachedRegisterEnabled = this.Page != null && !this.SaveSelectedIndicesViewState;
  }
  RadioButton controlToRepeat = this.ControlToRepeat;
  int index1 = repeatIndex + this._offset;
  ListItem listItem = this.Items[index1];
  controlToRepeat.Attributes.Clear();
  if (listItem.HasAttributes)
  {
    foreach (string index2 in (IEnumerable) listItem.Attributes.Keys)
      controlToRepeat.Attributes[index2] = listItem.Attributes[index2];
  }
  if (!string.IsNullOrEmpty(controlToRepeat.CssClass))
    controlToRepeat.CssClass = "";
  ListControl.SetControlToRepeatID((Control) this, (Control) controlToRepeat, index1);
  controlToRepeat.Text = listItem.Text;
  controlToRepeat.Attributes["value"] = listItem.Value;
  controlToRepeat.Checked = listItem.Selected;
  controlToRepeat.Enabled = this._cachedIsEnabled && listItem.Enabled;
  controlToRepeat.TextAlign = this.TextAlign;
  controlToRepeat.RenderControl(writer);
  if (!controlToRepeat.Enabled || !this._cachedRegisterEnabled || this.Page == null)
    return;
  this.Page.RegisterEnabledControl((Control) controlToRepeat);
}

controlToRepeat is that RadioButton, and it specifies only Attributes property and ignores InputAttributes.

I can suggest way to fix it - you can create new class that inherits RadioButtonList, and use it instead of default. Here is code of that class:

public class MyRadioButtonList : RadioButtonList
{
    private bool isFirstItem = true;

    protected override void RenderItem(ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
    {
        if (isFirstItem)
        {
            // this.ControlToRepeat will be created during this first call, and then it will be placed into Controls[0], so  we can get it from here and update for each item.
            var writerStub = new HtmlTextWriter(new StringWriter());
            base.RenderItem(itemType, repeatIndex, repeatInfo, writerStub);
            isFirstItem = false;
        }

        var radioButton = this.Controls[0] as RadioButton;

        radioButton.InputAttributes.Clear();
        var item = Items[repeatIndex];
        foreach (string attribute in item.Attributes.Keys)
        {
            radioButton.InputAttributes.Add(attribute, item.Attributes[attribute]);                
        }
        // if you want to clear attributes for top element, in that case it's a span, then you need to call
        item.Attributes.Clear();

        base.RenderItem(itemType, repeatIndex, repeatInfo, writer);

    }
}

A bit of description - it has isFirstItem property, as RadioButton control that used by it is created in runtime in the first access, so we need to call RenderItem before we can update InputAttrubutes property. So we call it once and send some stub HtmlTextWriter, so it won't be displayed twice. And then after that we just get this control as Controls[0], and for each ListItem we update InputAttributes values.

PS. Sorry, I didn't use VB.Net so control is written in C#

Upvotes: 4

Related Questions