© Lee Naylor 2016

Lee Naylor, ASP.NET MVC with Entity Framework and CSS , 10.1007/978-1-4842-2137-2_17

17. Advanced CSS

Lee Naylor

(1)Newton-le-Willows, Merseyside, UK

This chapter focuses on restyling the navigation bar using more advanced features of CSS using positioning and animations. It also introduces the popular JavaScript library jQuery, to change the main product image when a thumbnail is clicked on in the Product Details page.

Note

To complete this chapter, you must either have completed Chapter 16 or download Chapter 16’s source code from www.apress.com as a starting point. Also note that several of the figures dealing with the navigation bar are zoomed in by using the browser zoom feature. The fonts will appear smaller in reality.

Styling the Navigation Bar

So far, we have not added any specific styles to the navigation bar. It is currently a vertical list with the search box and button styled by the styles we have added in the previous chapters, as shown in Figure 17-1.

A419071_1_En_17_Fig1_HTML.jpg
Figure 17-1. The initial state of the navigation bar

As with previous chapters, we are going to stick with the default HTML generated by the MVC Framework for use with Bootstrap and base the styles around this. The HTML that generates the navigation bar is as follows; I’ve highlighted the CSS classes we’ll be using, as there are quite a few of them used in generating the navigation bar. Don’t worry though, I will break down all the techniques we use step by step so that you can see how each change affects the bar:

<div class="navbar navbar-inverse navbar-static-top">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-
                target=".navbar-collapse">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">MVC Baby Store</a>
       </div>
       <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/Categories">Shop by Category</a></li>
                <li><a href="/Products">View all our Products</a></li>
            </ul>
            <form action="/Products" class="navbar-form navbar-left" method="get">                    
                <div class="form-group">
                    <input class="form-control" id="Search" name="Search"
                       placeholder="Search Products" type="text" value="" />
                </div>
                <button type="submit" class="btn btn-default">Submit</button>
            </form>
            <ul class="nav navbar-nav navbar-right">
                <li>
                   <a href="/Account/Register?returnUrl=%2F" id="registerLink">Register</a>
               </li>
                <li>
                   <a href="/Account/Login?returnUrl=%2F" id="loginLink">Log in</a>
               </li>
               </ul>
            <ul class="nav navbar-nav navbar-right">
                  <li>
                    <a href="/Basket">Your basket: 0 items(s) £0.00</a>
                  </li>
            </ul>
        </div>
    </div>
</div>

The first style to add will style the whole navigation bar to give it a background and the rounded corners similar to the footer. Add this style to the store.css file:

.navbar{
    background-color: deepskyblue;
    border-radius: 5px;
    margin-top: 110px;
    margin-bottom: 10px;
    padding: 0px 5px;
}

This will change the background color of the navigation bar and round the corners using the border-radius property. Two margins are added to the top and bottom of the bar. Some space is added between the text and the left and right edges of the bar. The navigation bar should now appear as shown in Figure 17-2.

A419071_1_En_17_Fig2_HTML.jpg
Figure 17-2. The updated navigation bar with blue background, rounded corners, and margins to the top and bottom

Transforming the Navigation Bar Content to Display Horizontally

We are now going to change the navigation bar to display content horizontally. This requires a combination of techniques we have used previously because the content is made up of a mixture of divs and list elements. To start displaying the items in a line, we are going to float the main containing div elements. Add the following styles to store.css, which will make the elements with the classes navbar-header, nav, and navbar-left float alongside each other.

.navbar-header {
    float: left;
}


.nav {
    float:left;
}


.navbar-left {
    float: left;
}

These style look fine and should make the elements in the nav bar float next to one another; however, there is an unexpected consequence, in that the main navbar div loses all its height and the content is pushed outside, as shown in Figure 17-3.

A419071_1_En_17_Fig3_HTML.jpg
Figure 17-3. The navbar div has disappeared from view and the content flowed outside it

This issue occurs because all the children of the main navbar div are floated. This often causes a big headache for web designers and developers, but there a few simple ways to fix this. You can either apply the Micro Clearfix after the containing element or use the overflow property. We are going to use the Micro Clearfix because later in the chapter we use CSS positioning and using the overflow property is not a good combination with positioning as it causes a scroll bar to appear in the navigation bar. Modify store.css to change the current style that implements the Clearfix as follows. Add a new style to the end of the file to change the color of the links to white:

.row:after, .form-group:after, .navbar:after {
  content: " ";
  display: table;
  clear: both;
}


.navbar a{
    color: white;
}

The navigation bar should now appear as shown in Figure 17-4, with all the content contained inside it and floated next to one another.

A419071_1_En_17_Fig4_HTML.jpg
Figure 17-4. The navigation bar now displays with the divs floated

The navigation bar now looks better but some of the items are still stacked on top of one another. To correct this, we need to add some more styles to lay out the list elements horizontally. Add the following style to make the list elements within the nav class and the form-group class within the navbar-form class display as inline blocks:

.nav li, .navbar-form .form-group {
    display: inline-block;
}

This should now make the lists used for Shop by Category and Shop by Product and the Register Log in links appear side by side, plus the button should now appear next to the search box, as shown in Figure 17-5.

A419071_1_En_17_Fig5_HTML.jpg
Figure 17-5. The navigation bar with all elements horizontally aligned

The elements of the navigation bar are still very squashed together, so add a new style to space out the list elements as follows:

.nav li {
    padding: 5px;
}

Also update the .navbar-heading style as follows to add the same five-pixel padding:

.navbar-header {
    float: left;
    padding: 5px;
}

Finally, we don’t want to display the button with the class navbar-toggle, so set its display property to none by adding a new style as follows:

.navbar-toggle {
    display: none;
}

We should now have a nice basic navigation bar, as shown in Figure 17-6.

A419071_1_En_17_Fig6_HTML.jpg
Figure 17-6. The navigation bar, with everything aligned horizontally

Moving Elements Using Positioning

We are now going to spruce up the navigation bar and use the large margin we added above it earlier in the chapter. To start with, we are going to move the search box and button using CSS so it appears in the margin above the rest of the bar. To achieve this, we are going to use a CSS feature known as positioning, which allows an element to change position. Elements can be positioned using relative or absolute positioning or a combination of the both to position a child element relative to its parent.

  • Absolute positioning sets a fixed position of an element in the page; it is completely removed from the flow of the page.

  • Relative positioning is used to move an element relative to its normal position in the page flow. When you use relative positioning, the space taken up by the element will remain in the page flow. Elements positioned using this technique tend not to move smoothly as the page resizes, and instead jump around the page.

  • Fixed positioning locks an element into a fixed position so that even if the user scrolls, the element always stays in the same position in the screen.

  • By declaring a parent element as relative and a child element as absolute, it is possible to position the child element relative to its parent. When you use this method of positioning, the space occupied by the repositioned element is removed from the page flow. Element positioned using this technique move smoothly as the page resizes.

We are going to use a combination of relative and absolute positioning in this example to position a child element relative to its parent.

To recap, the HTML that generates the search form is as follows:

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
        <li><a href="/Categories">Shop by Category</a></li>
        <li><a href="/Products">View all our Products</a></li>
    </ul>
    <form action="/Products" class="navbar-form navbar-left" method="get">                    
        <div class="form-group">
            <input class="form-control" id="Search" name="Search"
                placeholder="Search Products" type="text" value="" />
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
    </form>

The parent element in this case is the div with the class navbar-collapse and the child element that we are going to reposition is the navbar-form element. Add the following two new styles to store.css and move the search box relative to the div that contains it:

.navbar-collapse {
    position: relative;
}


.navbar-form {
    position: absolute;
    bottom: 40px;
    left: 30%;
}

This will move the search box and button up and out of the navigation bar, as shown in Figure 17-7.

A419071_1_En_17_Fig7_HTML.jpg
Figure 17-7. The search box and button repositioned using CSS positioning

Declaring the div with the navbar-collapse class as having a relative position allows any child elements to be positioned relative to it. Absolute positioning is then used in the navbar-form class to position it in relation to the navbar-collapse element. This is a rather confusing naming convention but it is how CSS works. The space occupied by the search box and button is now removed from the navigation bar. If we had used position: relative in the navbar-form element then the space in the navigation bar would remain. The bottom property moves the element 40 pixels upward and the left property moves it 30% of the page in from the left.

Make the search box and button larger by adding the following styles to store.css:

.navbar .form-control {
    padding: 5px;
    width: 250px;
}


.navbar-form button {
    padding: 5px 20px;
    font-size:1.2em;
}

Now use the relative and absolute positioning technique again to move the MVC BabyStore link with the class navbar-brand out of the div with the class navbar-header as follows. First, update the .navbar-header style to set its position to relative:

.navbar-header {
    float: left;
    padding: 5px;
    position: relative;
}

Then add a new style to store.css to reposition the navbar-brand link:

a.navbar-brand {
    color: hotpink;
    position: absolute;
    bottom: 10px;
}

In this style, we have used a.navbar-brand rather than navbar-brand in order to override the color of the .navbar a style created earlier. The MVC BabyStore text is now repositioned as shown in Figure 17-8.

A419071_1_En_17_Fig8_HTML.jpg
Figure 17-8. The repositioned and recolored MVC BabyStore link

Styling Text

We are now going to restyle the MVC BabyStore text to make it appear more like a branding logo using some more advanced CSS effects, starting with adding some extra styles to the text itself. To start this, first update the a.navbar-brand style to make the font larger and bolder and also remove the underline when a user hovers over the link as follows:

a.navbar-brand {
    color: hotpink;
    position: absolute;
    bottom: 10px;
    font-size: 2.5em;
    font-weight: bold;
    text-decoration: none;
}

Adding a Shadow to Text

CSS features a text-shadow property that can be used to add shadow around text. This property has four attributes for horizontal and vertical offset; a value for the amount of blur applied to the text; and a color value that sets the color of the shadow. If the blur is set to 0, a very sharp shadow appears whereas setting the blur to a value such as 10px creates a light blurred shadow. We are going to add a medium grey shadow to the bottom and right of the text; in order to add this, update the a.navbar-brand style as follows:

a.navbar-brand {
    color: hotpink;
    position: absolute;
    bottom: 10px;
    font-size: 2.5em;
    font-weight: bold;
    text-decoration: none;
    text-shadow: 3px 3px 5px rgba(0,0,0,0.5);
}

The resulting text shadow applied to the MVC BabyStore text is shown in Figure 17-9.

A419071_1_En_17_Fig9_HTML.jpg
Figure 17-9. The effect of applying text-shadow to the MVC Baby Store link (zoomed in)

Styling Letters and Lines of Text Using CSS

CSS features a couple of pseudo-selectors that allow you to style the first letter or first line of text. These are the first-letter and first-line selectors. Note that in order for these to work, there must be more than one letter or line of text; otherwise they have no effect. To make the first line of the MVC BabyStore deepskyblue and further increase the font size, add the following style to store.css:

a.navbar-brand:first-line{
    color: deepskyblue;
    font-size: 1.8em;
}

This will restyle part of the MVC BabyStore text, as shown in Figure 17-10.

A419071_1_En_17_Fig10_HTML.jpg
Figure 17-10. Using the first-line pseudo-selector

Next, add a width and height to the a.navbar-brand style to force the text onto two lines rather than three as follows:

a.navbar-brand {
    color: hotpink;
    position: absolute;
    bottom: 10px;
    font-size: 2.5em;
    font-weight: bold;
    text-decoration: none;
    text-shadow: 3px 3px 5px rgba(0,0,0,0.5);
    height: 86px;
    width: 250px;
}

This should now nicely format the MVC BabyStore text, as shown in Figure 17-11. Note that we have set a specific width and height so that we can use this later, in particular, the space this leaves to the right of the text.

A419071_1_En_17_Fig11_HTML.jpg
Figure 17-11. The effect on the MVC BabyStore text by setting a width and height

Finally, to complete styling the MVC BabyStore text, we are going to add some spacing between the letters. Rather than having to add spans around each letter and then add margins, CSS has a helpful letter-spacing attribute that can be used to accomplish this task. To add some space between the letters of the MVC BabyStore text, update the a.navbar-brand style as follows:

a.navbar-brand {
    color: hotpink;
    position: absolute;
    bottom: 10px;
    font-size: 2.5em;
    font-weight: bold;
    text-decoration: none;
    text-shadow: 3px 3px 5px rgba(0,0,0,0.5);
    height: 86px;
    width: 250px;
    letter-spacing: 5px;
}

Figure 17-12 shows the updated text with spaces between each letter.

A419071_1_En_17_Fig12_HTML.jpg
Figure 17-12. The effect of setting the letter-spacing attribute value for the MVC BabyStore text

Adding Images Using CSS

Throughout the book we have used the HTML <img> tag to display images; however, images can also be displayed using CSS. To add an image to something, you can use the CSS property background-image to set the image you want to display.

Note

In this example, we are going to use the image file baby_logo.jpg. This can be downloaded from the Chapter 17 source code available on apress.com. The file is located in the folder BabyStoreContent.

To set the background image of the MVC BabyStore text to the baby_logo.jpg file, update the a.navbar-brand style with a background-image value as follows:

a.navbar-brand {
    color: hotpink;
    position: absolute;
    bottom: 10px;
    font-size: 2.5em;
    font-weight: bold;
    text-decoration: none;
    text-shadow: 3px 3px 5px rgba(0,0,0,0.5);
    height: 86px;
    width: 250px;
    letter-spacing: 5px;
    background-image: url(baby_logo.jpg);
}

This sets the image, but does not quite have the effect we require, as shown in Figure 17-13.

A419071_1_En_17_Fig13_HTML.jpg
Figure 17-13. Setting a background image

By default, the background image will be repeated and fill the whole width of the element it is added to. We only want one version of the image to display; this can be achieved by using the CSS background-repeat property and setting the value to no-repeat. Add the following attribute to the a.navbar-brand style:

a.navbar-brand {
    color: hotpink;
    position: absolute;
    bottom: 10px;
    font-size: 2.5em;
    font-weight: bold;
    text-decoration: none;
    text-shadow: 3px 3px 5px rgba(0,0,0,0.5);
    height: 86px;
    width: 250px;
    letter-spacing: 5px;
    background-image: url(baby_logo.jpg);
    background-repeat: no-repeat;
}

This now displays one image only, but it is hidden behind the text as shown in Figure 17-14.

A419071_1_En_17_Fig14_HTML.jpg
Figure 17-14. Using background-repeat to only display a single image
Note

The background-repeat also takes other values, in particular the values repeat-x and repeat-y can be used to only display a repeating image horizontally or vertically, respectively.

Positioning a Background Image

At the moment, the baby image is obscured behind the MVC BabyStore text, making both elements difficult to see. CSS allows you to position background elements by using the background-position property. This takes the horizontal and vertical values and accepts both general values (i.e., left, right, top, and bottom) and/or pixel values. For example, you could set something to display in the top left by setting the background-position: left top. In this case, we want to display the image to the right of the a.navbar-brand in the empty space, so add the following to the a.navbar-brand style in store.css:

a.navbar-brand {
    color: hotpink;
    position: absolute;
    bottom: 10px;
    font-size: 2.5em;
    font-weight: bold;
    text-decoration: none;
    text-shadow: 3px 3px 5px rgba(0,0,0,0.5);
    height: 86px;
    width: 250px;
    letter-spacing: 5px;
    background-image: url(baby_logo.jpg);
    background-repeat: no-repeat;
    background-position: right;
}

The updated image and text is shown in Figure 17-15.

A419071_1_En_17_Fig15_HTML.jpg
Figure 17-15. The baby logo right-aligned

Floating Elements to the Right

Earlier in the chapter when we positioned the search box and search button, it had the effect of removing the space in the navigation bar that was occupied by these elements. We want to reposition to Register Log In and Your Basket elements to the right of the navigation bar. To achieve this, we’re going to use the float property again, but this time we are going to set the value to right. This will float the elements to the right of anything that follows them that is not cleared. Earlier we added style that added a Clearfix after the navigation bar so applying a float right to these elements will have the effect of reversing the order of them and moving them to the right of the navigation bar.

The HTML for the elements we want to move to the right is as follows:

<ul class="nav navbar-nav navbar-right">
    <li>
        <a href="/Account/Register?returnUrl=%2F" id="registerLink">Register</a>
    </li>
    <li>
        <a href="/Account/Login?returnUrl=%2F" id="loginLink">Log in</a>
    </li>
</ul>
<ul class="nav navbar-nav navbar-right">
    <li>
        <a href="/Basket">Your basket: 0 items(s) £0.00</a>
    </li>
 </ul>

As you can see, they both have the Bootstrap class navbar-right applied to them. So we will add a style to store.css that targets this class to float the elements to the right as follows:

.navbar-right{
    float: right;
}

This will reverse the order of the element because it will float the first <ul> element to the right of the second <ul> element, as shown in Figure 17-16.

A419071_1_En_17_Fig16_HTML.jpg
Figure 17-16. The Register, Log In, and Basket summary links floated to the right. Note that the Register and Log In links now appear after the basket summary
Tip

Be careful when using float:right and ensure that the order of your HTML is structured correctly so that when it appears onscreen, it is in the order you require.

Adding Animation to Links Using Scaling

I am now going to demonstrate some more advanced CSS to style the links in the navigation bar. First of all, add a new style entry to the store.css file to target the hyperlinks that are contained in the list elements of the navigation bar:

.nav li a{
    display: inline-block;
    background-color: rgb(14, 117, 204);
    border-radius: 2px;
    padding: 5px 10px;
    border: 1px solid rgb(14, 117, 204);
    max-width: 210px;
     -moz-box-shadow: inset 0px 1px 0px rgba(255,255,255,0.7);
    -webkit-box-shadow: inset 0px 1px 0px rgba(255,255,255,0.7);
    box-shadow: inset 0px 1px 0px rgba(255,255,255,0.7);
}

There aren’t any new properties used in this style apart from box-shadow, which acts in a similar fashion to the text-shadow property used earlier. Also note that setting the display to inline-block ensures that the links remain inside the navigation bar. This style changes the links displayed inside the navigation bar to look like rounded blue buttons with a shiny top edge, as shown in Figure 17-17.

A419071_1_En_17_Fig17_HTML.jpg
Figure 17-17. The restyled navigation links

Now add animation to the links when a user hovers over them:

.nav li a:hover {
    background-color: hotpink;
    border: 1px solid hotpink;
    transform: scale(1.1);
    text-decoration:none;
}

This style changes the background color and the border color to change the button to pink but it also uses the CSS transform property to scale the size of the link up by 10% with the code transform: scale(1.1);. Figure 17-18 shows how the links now appear when you hover over them.

A419071_1_En_17_Fig18_HTML.jpg
Figure 17-18. The effect View All Our Products link with color changed and scale applied on hover

The links now change, but the process is rather quick and jerky. To slow the transformation down, modify the .nav li a style to add a transition property with the ease-in set to quarter of a second. This has the effect of fading in the change. Ease-in and ease-out can be used with a transform to slow the transformation down as desired.

.nav li a{
    display: inline-block;
    background-color: rgb(14, 117, 204);
    border-radius: 2px;
    padding: 5px 10px;
    border: 1px solid rgb(14, 117, 204);
    max-width: 210px;
    -moz-box-shadow: inset 0px 1px 0px rgba(255,255,255,0.7);
    -webkit-box-shadow: inset 0px 1px 0px rgba(255,255,255,0.7);
    box-shadow: inset 0px 1px 0px rgba(255,255,255,0.7);
     -webkit-transition: ease-in .25s;
    transition: ease-in .25s;
}

The vendor-specific -webkit-transition property is required in order to make this work in Google Chrome.

Introducing jQuery

I am now going to show you how to use the popular JavaScript library jQuery in order to allow users to click on a thumbnail image in the Product Details page and update the main image with the enlarged version of the thumbnail. The project already has jQuery included in the Scripts folder, as it is used to perform client-side validation. The current version installed in the source code that accompanies the book is version 1.10.2, and at the time of writing the latest version available is either 1.12.4 or 2.2.4. Rather confusingly, there are two branches of jQuery available for download—the difference is that v2.x does not support Internet Explorer 6, 7, or 8.

How the Project References jQuery

Generally, Visual Studio will include jQuery in an MVC project, but if you ever need to download it into a project, then to use it you simply need to ensure it is included in each page that uses it by adding a reference to it in your HTML. To add a reference to jQuery (or indeed to any JavaScript file), you add a script element. For example, in the BabyStore project the script element is <script src="/Scripts/jquery-1.10.2.js"></script>. In the BabyStore project, this script element is generated by the line of code @Scripts.Render("∼/bundles/jquery") located in the ViewsShared\_Layout.cshtml file. This code uses a bundle in the same way that the CSS files are loaded, by referencing the following code in the App_StartBundleConfig.cs file.

bundles.Add(new ScriptBundle("∼/bundles/jquery").Include(
    "∼/Scripts/jquery-{version}.js"));

jQuery Syntax

jQuery is based on JavaScript and therefore uses JavaScript syntax to allow you to write code. jQuery script works by checking that the page was first loaded to ensure that it can process any element within the page. To do this, all the jQuery is included in the surrounding code block:

$(document).ready(function() {
});

This code is known as the document ready event and tells jQuery to wait until the entire HTML document (the document variable) has loaded. Once this has occurred, it will then run any code within the function block. The code function(){} represents an anonymous function; this is a feature of JavaScript that allows functions to be declared without a name. The $ sign is prefixed to any code that is to be run from the jQuery library. Therefore, with the jQuery library included in the HTML source of the page, the code $(document).ready(function() {}); is recognized as jQuery.

There is also shorthand version of the document ready event as follows (although I prefer the longer version):

$(function(){
});

I’ve included jQuery along with CSS because it works on a similar premise to CSS; it uses selectors. We are only touching the tip of the jQuery iceberg in this book, but the basic format of all jQuery code is $(selector).method or $(selector).attribute. Methods and attributes can be chained together so, for example, you can write code in the format $(selector).attribute.method.

Note

The script that loads the jQuery library must be included in the HTML source before the document ready event code in order for the code to work. Otherwise, it will not be recognized as jQuery.

Using jQuery to Update the Main Image in the Product Details Page

We are now going to use jQuery to change the main image in the product details page when a user clicks on a thumbnail image. The HTML that generates the main image and the thumbnail image is as follows (this example shows the bibs product):

<dd>
    <img src="/Content/ProductImages/Bibs1.JPG">
</dd>
<dt></dt>
<dd>
    <a href="/Content/ProductImages/Bibs1.JPG">
        <img src="/Content/ProductImages/Thumbnails/Bibs1.JPG">
    </a>
    <a href="/Content/ProductImages/Bibs2.JPG">
        <img src="/Content/ProductImages/Thumbnails/Bibs2.JPG">
    </a>
</dd>

Based on this HTML, what we need to do in order to update the image is detect a click on any image within an a tag and then change the image that is the immediate child of a dd tag (the main image). We also want to ensure that the user stays on the page and is not redirected to the address of the link.

Note

There are no other images in the Product Details page that follow the pattern of the HTML above. If there were, then we would have to assign an ID to each element we wanted to use and then use each ID in the jQuery selectors.

To start the jQuery code to make this functionality work, update the ViewsProductsDetails.cshtml file to add a new document ready event as follows:

@model BabyStore.Models.Product

@{
    ViewBag.Title = "Product Details";
}


<h2>@ViewBag.Title</h2>

<div>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Category.Name)
        </dt>


        <dd>
            @Html.DisplayFor(model => model.Category.Name)
        </dd>


        <dt>
            @Html.DisplayNameFor(model => model.Name)
        </dt>


        <dd>
            @Html.DisplayFor(model => model.Name)
        </dd>


        <dt>
            @Html.DisplayNameFor(model => model.Description)
        </dt>


        <dd>
            @Html.DisplayFor(model => model.Description)
        </dd>


        <dt>
            @Html.DisplayNameFor(model => model.Price)
        </dt>


        <dd>
            @Html.DisplayFor(model => model.Price)
        </dd>
        @if (Model.ProductImageMappings != null && Model.ProductImageMappings.Any())
        {
            <dt></dt>
            <dd>
                <img src="@(Url.Content(Constants.ProductImagePath) +
                   Model.ProductImageMappings.OrderBy(pim =>  
                   pim.ImageNumber).ElementAt(0).ProductImage.FileName)">
            </dd>
            <dt></dt>
            <dd>
                @foreach (var item in Model.ProductImageMappings.OrderBy(pim =>
                   pim.ImageNumber))
                {
                    <a href="@(Url.Content(Constants.ProductImagePath) +
                        item.ProductImage.FileName)">
                        <img src="@(Url.Content(Constants.ProductThumbnailPath) +
                        item.ProductImage.FileName)">
                    </a>
                }
            </dd>
        }
        <dt>
            Quantity:
        </dt>
        <dd>
            @using (Html.BeginForm("AddToBasket", "Basket"))
            {
                @Html.AntiForgeryToken()
                @Html.HiddenFor(model => model.ID)
                @Html.DropDownList("quantity", Enumerable.Range(1, 10).Select(i => new
                   SelectListItem { Text = i.ToString(), Value = i.ToString() }), new { @class
                   = "form-control" })
                <input type="submit" class="btn btn-primary btn-xs" value="Add to Basket">
            }
        </dd>


    </dl>
</div>
<p>
    @if (Request.IsAuthenticated && User.IsInRole("Admin"))
    {
        @Html.ActionLink("Edit", "Edit", new { id = Model.ID })
        @Html.Raw(" | ")
    }
    @Html.ActionLink("Back to List", "Index")
</p>


@section Scripts {
    <script>
        $(document).ready(function () {
        });
    </script>
}

The @Section Scripts code block ensures that this script is loaded after the jQuery library. If this was not used, then the script would load first and it would not function correctly.

First of all, add a new function that runs when a user clicks on a thumbnail image. Remember that in the HTML code listed previously, we identified a thumbnail image as an img tag within an a tag. To achieve this, add the following to the document ready event code:

@section Scripts {
    <script>
        $(document).ready(function () {
            $('a>img').click(function (evt) {


            });
        });
    </script>
}

This code first uses a jQuery selector to find any img tags that are direct descendants of a tag using the code $('a>img'). The jQuery click event is then called and, when this activates, a new anonymous function is going to run. This function is passed the click event as a parameter using the code function(evt).

Now update the script as follows to prevent the users following the link when they click on a thumbnail image:

@section Scripts {
    <script>
        $(document).ready(function () {
            $('a>img').click(function (evt) {
                evt.preventDefault();
            });
        });
    </script>
}

If you now click on a thumbnail, you will no longer be redirected to another page showing just the large version of the image. Next, add the following bold line of code to obtain the current address of the link that the thumbnail points to:

@section Scripts {
    <script>
        $(document).ready(function () {
            $('a>img').click(function (evt) {
                evt.preventDefault();
                var thumbnailAddress = $(this).parent().attr('href');
            });
        });
    </script>
}

This line of code is more complex than the others, but works on the same principle. It is simply a more complex selector. This selector first finds the parent of the selector we used to find the thumbnail image, which is referenced by using $(this). In this case, $(this) represents the img tag found by the a>img selector, so when we now find the parent we will find the a element. The code then finds the href element of the a tag by using the code $(this).parent().attr('href');.

Finally, add two new lines of code. The first line selects the main image (identified as being an img tag that is the direct descendant of a dd tag) to be replaced by using the dd>img selector. The second line finds the src attribute of this image and replaces it with the address of the thumbnail image that was clicked. This has the effect of replacing the main image with the large version of the thumbnail.

@section Scripts {
    <script>
        $(document).ready(function () {
            $('a>img').click(function (evt) {
                evt.preventDefault();
                var thumbnailAddress = $(this).parent().attr('href');
                var mainImage = $('dd > img');
                mainImage.attr('src', thumbnailAddress);
            });
        });
    </script>
}

To see the effect of this code, start the web site and view the details of any product. You should now be able to click on the thumbnail images and the larger version of the image will now become the main image for the product. Figure 17-19 shows the Pram and Pushchair System product with the main image updated by clicking on the middle thumbnail.

A419071_1_En_17_Fig19_HTML.jpg
Figure 17-19. Updating the main product image with jQuery
Caution

It is possible to chain together lots of jQuery to make the code quite terse and complex looking. For example, we could have written the three lines after the line evt.preventDefault(); as $('dd > img').attr('src', $(this).parent().attr('href'));. It is more compact, but it also becomes more difficult to understand, so when writing jQuery or indeed any JavaScript, try to find a balance between code length and ease of reading. It is also more efficient when using JavaScript to assign an HTML element to a variable if you are going to refer to it more than once.

Note

JQuery is a huge subject area within itself and has been expanded over the years to include other libraries for mobile and advanced UI features. For more information on jQuery, Apress has several other books available such as Beginning jQuery by Jack Franklin and Pro jQuery 2.0 by Adam Freeman.

Summary

This chapter started by styling the navigation bar to appear horizontally. I then introduced how to use CSS positioning to move elements around the page and covered how to use scaling to make elements appear larger. The chapter closed with a brief introduction on to how use jQuery to update the main image of a product when a user clicks on a thumbnail image.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset