jQuery Selectors (Attributes and more filters)
In the previous part,
I explained basic selectors and basic filters. Now let's try to understand
attribute selectors, content filters, child filters and visibility filters.
Understanding Attribute Selectors
Attribute selectors allow you to match attributes of HTML elements with certain
criteria. It is not just "equal to" kind of matching but several other options
are also available as outlined in the table below. The usage of attribute
selector takes the following general form :
<element_name>[<attribute_name> <operator> <value_to_match>]
e.g.
a[href = "hello"]
Attribute Selector |
Operator |
Description |
Attribute Equals Selector |
= |
Selects element whose specified attribute value exactly equals with
a specific string value. |
Attribute Not Equal Selector |
!= |
Selects element whose specified attribute value doesn't match with a
specific string value OR the specified attribute itself is missing. |
Attribute Starts With Selector |
^= |
Selects element whose specified attribute value begins with a specific
value. |
Attribute Ends With Selector |
$= |
Selects element whose specified attribute value ends with certain
string value. |
Attribute Contains Selector |
*= |
Selects element whose specified attribute value contains a specific
string. |
Attribute Contains Word Selector |
~= |
Selects element whose specified attribute value contains a specific
string as a whole word i.e. the value is separated by white space. |
Attribute Contains Prefix Selector |
|= |
Selects element whose specified attribute value matches exactly equal to the specified
value or that starts with the specified value followed by a - (hyphen).
|
Has Attribute Selector |
|
Selects element if a specified attribute is present. |
Multiple Attribute Selector |
|
Combination of multiple attribute filters |
Now let's develop a simple web form that makes use of some of these attribute
selectors. Our web form will look like this :
The web form contains a GridView with a list of download links. The downloads
include products, white papers and components. At the top of the web form there
is a DropDownList that allows you to filter the download links based on the
category (product, white paper, component etc.). The checkbox governs whether
the links are opened in the same browser window or in a separate window.
The data displayed in the grid is not coming from any database. Rather it is
coming from an object collection. The code behind of the web form defines a
class named Download as shown below :
public class Download
{
public Download()
{
}
public Download(string title,string url)
{
this.Title = title;
this.URL = url;
}
public string Title { get; set; }
public string URL { get; set; }
}
The Download class contains two public properties viz. Title and URL. The
overloaded constructor allows you to quickly instantiate Download instances.
The actual data binding work happens in Page_Load event handler.
protected void Page_Load(object sender, EventArgs e)
{
List<Download> items = new List<Download>();
items.Add(new Download("SQL Server Backup Tool",
"products/Product1.aspx"));
items.Add(new Download("Visual Studio Add-In",
"products/Product2.aspx"));
items.Add(new Download("Understanding DNA Architecture",
"Paper-Topic1.aspx"));
items.Add(new Download("In-depth XML and JSON Serialization",
"Paper-Topic2.aspx"));
items.Add(new Download("Data Access Component",
"Component1-comp.aspx"));
items.Add(new Download("Mass Mailing Component",
"Component2-comp.aspx"));
GridView1.DataSource = items;
GridView1.DataBind();
}
Here, you just create a generic List and fill it with some Download
instances. You then set the DataSource of the grid to this List and call
DataBind() method. Notice the URLs above carefully because later your use of
attribute filters will be based on them.
The GridView consists of a single HyperLinkField whose configuration is shown
below :
The DataNavigateUrlFields property is set to URL and DataTextField property
is set to Title.
Ok. That completes the server side part. Now let's see the jQuery part.
The complete jQuery code behind the functionality that we desire is shown
below :
$(document).ready(function() {
$("#DropDownList1").change(function() {
switch ($("#DropDownList1").val()) {
case "A":
$("#GridView1 tr a").css("visibility", "visible");
$("#GridView1 tr a").css("display", "block");
break;
case "P":
$("#GridView1 tr a[href *= 'products/']").
css("visibility", "visible").css("display", "block");
$("#GridView1 tr a[href |= 'Paper']").
css("visibility", "hidden").css("display", "none");
$("#GridView1 tr a[href $= '-comp.aspx']").
css("visibility", "hidden").css("display", "none");
break;
case "WP":
$("#GridView1 tr a[href *= 'products/']").
css("visibility", "hidden").css("display", "none");
$("#GridView1 tr a[href |= 'Paper']").
css("visibility", "visible").css("display", "block");
$("#GridView1 tr a[href $= '-comp.aspx']").
css("visibility", "hidden").css("display", "none");
break;
case "C":
$("#GridView1 tr a[href *= 'products/']").
css("visibility", "hidden").css("display", "none");
$("#GridView1 tr a[href |= 'Paper']").
css("visibility", "hidden").css("display", "none");
$("#GridView1 tr a[href $= '-comp.aspx']").
css("visibility", "visible").css("display", "block");
break;
}
}),
$("#CheckBox1").change(function() {
if ($("input[name='CheckBox1']").is(":checked")) {
$("#GridView1 a:visible").attr("target", "_blank");
}
else {
$("#GridView1 a:visible").attr("target", "_self");
}
})
})
Let's examine the code.
The code essentially handles change events of DropDownList1 and CheckBox1
controls. The change event handler of DropDownList control consists of a
JavaScript switch statement that checks for the selected value.
If the selected value is "A" i.e. show all downloads then you set the
visibility CSS property of all hyperlinks to visible. This way it ensures that
all types of downloads (products, components, white papers etc.) are shown in
the grid. This code should be familiar to you as we used element selectors and
css() function in the past examples.
If the selected value is "P" i.e. show only products then you use Attribute
Contains selector (*=) to match all the anchor elements whose href attribute contains string "products/".
Our URLs are such that only two entries match this criteria and you then set
visibility of those links to visible.
We then use Attribute Contains Prefix selector (|=) to select white paper
downloads. Notice that our URLs for white papers begin with "Paper-" but we
specified only "Paper" in the selector because Attribute Contains Prefix selector
selects values that are equal to OR begin with specified value plus hyphen (-).
The selected links are kept hidden by setting their visibility property to
hidden and display property to none. Remember that setting display to none is
also necessary. If you don't set the display to none then the hyperlinks will be
hidden but the empty grid rows will be still visible.
Finally, we filter component related links using Attribute Ends With selector
($=) and hide them from the user as with white paper links.
Notice how we have used css() function calls in a "chain" like fashion. It is
important to remember that both of the css() calls are invoked on the return
value of the selector. That means both calls are working on the same resultant
elements. This is bit different than most of the programming languages such as
C#. Consider the following C# code :
objEmployee.GetSalary().ToString()
What happens here? First GetSalary() method is invoked on objEmployee.
ToString() method is then invoked on the return value of GetSalary() method.
jQuery chaining is bit different. That is how all the calls to css() function
are invoked on the returned set of element selector.
The other cases of the switch block i.e. "WP" and "C" are similar to the case
we just discussed. The only difference is that they show the respective links
and hide the remaining ones.
The CheckBox change event handler makes use of some other jQuery selectors.
First, it filters input element whose name attribute is exactly equal to
CheckBox1 using Attribute Equals selector. The is() filter checks if the
checkbox is checked. Notice the use of Form selector :checked (I will cover Form
selectors in detail in later parts) that returns all the checked elements. If
the checkbox is checked we set target attribute of all the visible hyperlinks.
The visibility filter :visible returns elements that are currently visible. The
attr() method allows you to set value of an attribute and accepts two
parameters. The first parameter is the name of the attribute (target in our
case) and the second parameter is its value.
That's it. Run the web form and see how our jQuery code shows/hides the grid
rows based on the DropDownList selection. Also check the behavior with checkbox
checked and unchecked.
Understanding Visibility Filters
Visibility filters allow you to select elements based on their visibility.
Two visibility selectors are :visible and :hidden. The :visible selector returns
all the elements that are visible whereas :hidden selector selects all the
elements that are hidden in the browser. In the preceding example you already
used :visible selector so I won't cover a separate example for visibility
filters.
Understanding Child Filters
Child filters allow you to work with child elements of the selected parent
elements. The four selectors of this category are :first-child, :last-child,
:nth-child() and :only-child. As the names suggest the :first-child filter
returns the first child element, :last-child filters returns the last child
element, :nth-child() filter returns a child element at a specified index and
:only-child filter returns elements that are the sole child element of their
parent.
To understand how child filters work you will develop a web form as shown
below :
The web form displays records from the Employees table of Northwind database.
At the bottom there are four VCR buttons that allow you to navigate through the
grid. The highlighted marker moves to an appropriate row as you click on the VCR
buttons.
The jQuery code responsible for the said functionality is shown below :
var counter = 1;
$(document).ready(function() {
$("#Button1").click(function(event) {
counter = 1;
$("#GridView1 tbody tr").removeClass("HighlightedRow");
$("#GridView1 tbody tr:first-child").
addClass("HighlightedRow");
event.preventDefault();
})
,
$("#Button2").click(function(event) {
if (counter > 1) {
counter--;
}
$("#GridView1 tbody tr").removeClass("HighlightedRow");
$("#GridView1 tbody tr:nth-child(" + counter + ")").
addClass("HighlightedRow");
event.preventDefault();
})
,
$("#Button3").click(function(event) {
if (counter < $("#GridView1 tbody tr").length) {
counter++;
}
$("#GridView1 tbody tr").removeClass("HighlightedRow");
$("#GridView1 tbody tr:nth-child(" + counter + ")").
addClass("HighlightedRow");
event.preventDefault();
})
,
$("#Button4").click(function(event) {
counter = $("#GridView1 tbody tr").length;
$("#GridView1 tbody tr").removeClass("HighlightedRow");
$("#GridView1 tbody tr:last-child").
addClass("HighlightedRow");
event.preventDefault();
})
})
The code essentially handles click events of all the VCR buttons. A global
JavaScript variable counter keeps track of the "current" row. If you click on
the First button (<<) then first <tr> element that is a child of <tbody> element
is returned using tr:first-child filter. The returned table row is then applied
with HighlightedRow CSS class. Similarly, when you click on Last button (>>) the
last row is selected using tr:last-child filter.
The click event handlers of Previous (<) and Next (>) buttons increment or
decrement the counter variable as appropriate. The code then uses nth-child()
selector by passing the counter variable as the child index. Remember that
nth-child takes 1 based index and not 0 based.
The HighlightedRow CSS class used by above code is as follows :
.HighlightedRow
{
background-color:navy;
color:White;
}
Understanding Content Filters
Content filters all you to filter elements based on their content. There are
four selectors in this category namely :contains(), :empty, :has() and :parent.
We used :contains() filter in earlier parts to check whether an element contains
certain text. The :empty selector returns all the elements that have no child
elements (not even text nodes). The :has() selector returns elements that
contain one or more elements matching the specified selector. Finally, the
:parent selector is opposite to :empty and returns all the elements that have at
least one child (that child can be a text node).
To see some of the above content filters in action we will develop a search
web form as shown below :
The web form consists of a GridView that displays records from the Employees
table. There is a TextBox at the top that accepts a search criteria. The entered
text is to be searched only within Notes and not in any other column. The grid
consists of a template column as shown below :
The template column consists of four Label controls. Label1 displays
EmployeeID, Label2 and label4 display FirstName and LastName respectively and
Label3 displays Notes. Notes being a long text paragraphs we include them in <p>
tag so that CSS styling for <p> (if any) gets applied to Notes also.
<td>
<p>
<asp:Label ID="Label3" runat="server"
Text='<%# Eval("Notes") %>'></asp:Label>
</p>
</td>
Now the jQuery part. See the jQuery code below that does the searching using
:contains() and :has selectors.
$(document).ready(function() {
$("#Button1").click(function(event) {
$("#GridView1 tr").removeClass("Highlight");
$("#GridView1 tr:has(p:contains(" + $("#TextBox1").val()
+ "))").addClass("Highlight");
event.preventDefault();
})
})
We are interested to search only notes so we check if the row elements
has paragraph elements containing the search criteria as specified in the
textbox. If any matching rows are found, Highlight CSS class is applied to them.
The Highlight CSS class is shown below :
.Highlight
{
background-color:yellow;
color:red;
font-weight:bold;
}
Because we are restricting our searching only to rows having <p> elements, if
you enter Nancy as search criteria the search will be successful as Notes do
contain the word Nancy. But if you enter Davolio no row is highlighted even if
row containing FirstName and LastName labels contain that word.
So far we have covered majority of jQuery selectors except Form selectors and
Hierarchy selectors. In the next part I will cover both of them before going to
other areas. Stay tuned!