Tag Archives: document.getElementById

CheckBox header to select/deselect all checkBoxes in SPGridView using javascript

So I wanted to have a checkBox header in my SharePoint:SPGridView that checked all the checkboxes in that column of my gridview. I also wanted to do this client-side since it is (at least for me) totally worthless to do a postback to the server just to check the boxes. So I used javascript. I found a couple of solutions out there, and combined two of them to match my needs. Links are at the bottom of this post.

Below is the code I run to perform this task:

The SPGridView control:

<SharePoint:SPGridView ID="mySPGridView" runat="server" AutoGenerateColumns="false" >
 <Columns>
  <asp:TemplateField>
   <ItemTemplate>
    <asp:CheckBox ID="selectionCheckBox" runat="server" />
   </ItemTemplate>
   <HeaderTemplate>
    <asp:CheckBox ID="selectionCheckBoxHeader" runat="server" OnClick="checkAllCheckBoxes(this)" />
   </HeaderTemplate>
   <HeaderStyle HorizontalAlign="Left" />
  </asp:TemplateField>
 </Columns>
</SharePoint:SPGridView>

Not that I call the function by using OnClick because I want it to run on client-side. This does not appear as an option in intellisense when writing the code, instead you get the suggestion to use OnCheckedChanged. Do not use this since that will try to call a method on the server side. Write OnClick instead. It will work (at least it did for me).

The javascript function:

function checkAllCheckBoxes(invoker) {	
	var gridView = document.getElementById('');
	for (var i = 1; i < gridView.rows.length; i++) {
		var rowElement = gridView.rows[i].cells[0];
		for (var j = 0; j < rowElement.childNodes.length; j++) {
			if (rowElement.childNodes[j].type == "checkbox") {
				rowElement.childNodes[j].checked = invoker.checked;
			}
		}            
	}
}

Note: I was a few ppl mention how much easier it was doing this in  jQuery. I really need to start learning jQuery soon.

Source links:

1: Check/uncheck CheckBox in a GridView using Javascript

2: Check/Uncheck checkboxes in GridView using JavaScript

Advertisements

asp:CustomValidator for asp:CheckBoxList with multiple javascript validations

This one I struggled with for a long time. Mostly because I am still inexperienced when it comes to javascript. I wanted to create a CustomValidator which checked if at least one box was checked, if the boxes checked where consecutive, and lastly that the correct number of boxes where checked depending on the selection in another control.

You basically need three things to make this work:

  1. A CheckBoxList (Or any other control you want to validate)
  2. A Custom Validator (I use the already existing asp:CustomValidator, but you can make your own if you want)
  3. A javascript function to handle the logic

I ran into a number of problems, which were mostly due to my own inexperience rather than the problem being too complicated. One issue you run into when validating a CheckBoxList is that the validator won’t work if you use the attribute “ControlToValidate” on your asp:CustomValidator as you do with other controls. Instead you have to retrieve the control inside the javascript function which will be used to validate. The way I found to do this was by using document.getElementById(CheckBoxListID) inside your function.

var timeslotCheckBoxList = document.getElementById('<%=Timeslots.ClientID%>');

The problem with using “<‘%=Timeslots.ClientID%>’ is that you cannot use external javascript files, or at least so I read in some forums. This mean you have to put your functions directly into the page where the controls exist. This only applies when validating CheckBoxList (and other controls not compatible with CustomValidator) though, since you can normally use the  “ControlToValidate” attribute in the validator to retrieve the control into the function:

<asp:CustomValidator ID="myValidator" runat="server" ControlToValidate="myTextBox" ErrorMessage="Run for your lives!" ClientValidationFunction="validateTextBoxTimeslots" ValidationGroup="Test">
</asp:CustomValidator>

In this case you would be able to retrieve the control through the sender parameter in the function, and the value of the control through the args parameter (parameters are shown in the full example code at the end of the post)

I have chosen to keep “ValidationGroup” in the example aswell since it is a great way to make sure you trigger the right validators at the right time. Just give the button or other control you want to trigger the validation the same attribute and value and no other button or control will.

Below is the fully working code example:

Controls:
<asp:CheckBoxList ID="Timeslots" runat="server" >
</asp:CheckBoxList>
<asp:CustomValidator ID="myValidator" runat="server" ErrorMessage="Run for your lives!" ClientValidationFunction="validateCheckBoxListTimeslots" ValidationGroup="Test">
</asp:CustomValidator>
<asp:Button ID="Button1" runat="server" Text="Button" ValidationGroup="Test" /> 

Javascript functions:

The first function creates an array with the number of selected timeslots and checks if at least one slot has been selected. It is also here that the other two checks are made, and the error messages are set.

function validateCheckBoxListTimeslots(sender, args) {
            var timeslotCheckBoxList = document.getElementById('<%=Timeslots.ClientID%>');
            var timeslots = timeslotCheckBoxList.getElementsByTagName("input");
	    var checkedTimeslots = new Array();
            var arrayIndex = 0;
            for (var i = 0; i < timeslots.length; i++) {
                if (timeslots.item(i).checked) {
                    checkedTimeslots[arrayIndex] = timeslots.item(i);
                    arrayIndex++;
                }
            }
            args.IsValid = true;
            if (checkedTimeslots.length == 0) {
                args.IsValid = false;
                sender.innerText = "Select at least one timeslot.";
                return;
            }
            if (checkTimeslotsIfConsecutive(checkedTimeslots) == false) {
                args.IsValid = false;
                sender.innerText = "Timeslots must be consecutive.";
                return;
            }
            if (checkTimeslotsIfCorrectNumberOfSlots(checkedTimeslots) == false) {
                args.IsValid = false;
                sender.innerText = "Incorrect number of timeslots.";
                return;
            }
        }

The second function checks if the selected timeslots are consecutive. The logic is simple. Each checkBox has a text value which represents a time interval, for example (10:00-10:15). All I have done is to split the values on the “-” sign, and compare the end time of the first timeslot with the start time of the second timeslot.

function checkTimeslotsIfConsecutive(checkedTimeslots) {
            var consecutive = true;

            var index = 0;

            while (index < checkedTimeslots.length - 1 && consecutive) {
                var currentTimeslot = checkedTimeslots[index].labels(0).innerText;
                var nextTimeslot = checkedTimeslots[index + 1].labels(0).innerText;

                var currentTimeslotEndTime = currentTimeslot.split("-")[1];
                var nextTimeslotStartTime = nextTimeslot.split("-")[0];
                if (currentTimeslotEndTime != nextTimeslotStartTime) {
                    consecutive = false;
                }
                index++;
            }
            return consecutive;
        }

IMPORTANT EDIT: “var currentTimeslot = checkedTimeslots[index].labels(0).innerText;” Doesn’t work in IE9!
Or atleast not for me. I got an error where the validation didn’t work in IE but worked in FireFox and Chrome. While debugging i found out the problem was that IE interpreted the checkbox as a DispHTMLInputElement rather than a HTMLInputElement as Chrome and FF did, and the Disp object did not have the labels attribute which I used to get the text value. A collegue of mine helped me solve the issue using a small piece of jQuery:

var currentTimeslot = jQuery('label[for=' + checkedTimeslots[timeSlotIndex].id + ']')[0].innerText;

Instead of directly getting the text, you get the label based on the value of its for-attribute, which is the same as the id of the checkbox. When we have the label we can easily get the innerText value from it. Now the solution works in IE9 aswell.

The third function simply checks if the user has selected the correct number of timeslots depending on the selection made in another control (a RadioButtonList).

function checkTimeslotsIfCorrectNumberOfSlots(checkedTimeslots) {
            var valid = false;
            var numberOfSelectedTimeslots = checkedTimeslots.length;
            var meetingTypeList = document.getElementById('<%=myRadioButtonList.ClientID%');
            var meetingTypes = meetingTypeList.getElementsByTagName("input");

            var selectedType;
            var index = 0;
            var checked = false;
            while (index < meetingTypes.length && !checked) {
                if (meetingTypes.item(index).checked == true) {
                     selectedType = meetingTypes.item(index);
                     checked = true;
                }
                index++;
            }
            if (checked == false) {
                return true;
            }
            if (selectedType.value == "Type1") {
                if (numberOfSelectedTimeslots >= 4 && numberOfSelectedTimeslots <= 8) {
                    valid = true;
                }
            }
            else if (selectedType.value == "Type2") {
                if (numberOfSelectedTimeslots >= 1 && numberOfSelectedTimeslots <=4) {
                    valid = true;
                }
            }
            return valid;
        }