Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Using jQuery Plugins Add a Sticky Navigation Bar The Plugin Challenge

Chris Shaffer
Chris Shaffer
12,030 Points

My Solution: Plugin Challenge "Sticky.js"

I just wanted to provide my solution to this challenge. It's a bit different than what is shown in the video, but probably because the video focuses on a literal solution without any JQuery shortcuts.

Here I'm selecting a single element, which would more ideally be done using an ID instead of a sub-element; but as this is a simple HTML project, it's okay.

$(".grid-full h5").sticky({
    topSpacing:64
});

$(".grid-full h5").on('sticky-start', function(){
    $(this).html('Want us to work on your project?' + '<a href="mailto" class="email-link"> Email Us</a>');
    $(this).on('sticky-end', function(){
        $(this).html('Want us to work on your project?');
    });
});

I then offset the variation in header height in the CSS:

@media (max-width: 852px) {
  .grid-full h5 {
    margin-top: 56px;
  }
}

@media (max-width: 700px) {
  .grid-full h5 {
    margin-top: 50px;
  }
}

I used 852px because Chrome now applies a break point automatically at this level. There's no need to adjust on the @media at 1000px, and 700px just needs a small tweak.

Hope that helps anyone looking for similar solutions!

4 Answers

Hi Chris Shaffer, I just wanted to mention a couple of things about your solution.

First, because you have the sticky-end event handler nested within the sticky-start one, you'll be binding a new event handler every time the user scrolls back to the top.

Second, while using html in this case works fine, it's much slower than append and remove, which can also have increased performance by using a variable for the new a element.

You can also chain the on methods.

As for the CSS, I found just removing or commenting out the opacity: .95; on the existing .is-sticky h5 rule seemed to do the trick (though your solution might avoid that little jump of the content below when it sticks).

Here was my JS code (I also just stuck in within some script tags on the work.html page, so it doesn't run on every other page).

    var emailLink = $('<a href="mailto:help@teamtreehouse.com">Email us</a>');
      $(document).ready(function(){
        $("h5").sticky({topSpacing:64})
        .on('sticky-start', function() {
          $(this).append(" ").append(emailLink);
        })
        .on('sticky-end', function() {
          emailLink.remove();
        });
      });
Chris Shaffer
Chris Shaffer
12,030 Points

Iain, thanks for the feedback.

True, I hadn't considered the addition of a new event handler each time. Do you if chaining eliminates this?

My understandIng is that JQuery chaining is similar to nesting due to the backend JQuery functions effectively executing as though they are nested, but that might be wrong.

Also, my understanding of the '''.html''' method is that it is effectively the same as $().append(); . If I understand from the JQuery API, ``` $().append();

$().remove(); can be used for exactly what they would appear to be: appending and removing to existing HTML, where in contrasthtml $().html(); is effectively setting the value (almost like $(this). append().val(); ``` in concept.

I'll have to take a closer look at the API docs.

Yes, chaining eliminates the additional event handlers.

Chaining is different from nesting. Chaining is just a shortcut instead of having duplicate selectors for multiple method calls. The below code is the same as my chained code.

$("h5").sticky({topSpacing:64});

$("h5").on('sticky-start', function() {
  $(this).append(" ").append(emailLink);
});

$("h5").on('sticky-end', function() {
    emailLink.remove();
});

Nesting, on the other hand, means that one event handler/function will only be called when the outer function is called, but also every time it is called.

You don't want to bind the event handler every time the sticky-end is fired, you just want to bind it once and run the function every time the sticky-end event is fired.

append and remove will add and remove DOM nodes, whereas html will change a property of the DOM node (presumably the innerHTML). I already mentioned why this is a good thing.

Javier Gandia
seal-mask
.a{fill-rule:evenodd;}techdegree
Javier Gandia
Full Stack JavaScript Techdegree Student 9,153 Points
$(".grid-full h5").on("sticky-start", function(){
    const gridH5 = document.querySelector(".grid-full h5").innerHTML;
    const email = ` <a href="mailto:javierggandia@yahoo.com">Email us</a>`
    $(this).append(email).on("sticky-end",function (){
        $(this).empty(email).append(gridH5);
    });
});

my solution.. works like a charm..

Chris Shaffer
Chris Shaffer
12,030 Points

I marked Ian's answer as best due to the explanation of best practices.

Javier, while your answer uses chaining, it also unnecessarily uses the document.querySelector method in a way that is not recommended due to unpredictable results.

That method should generally only be used when the first element with the class you are targeting is going to change dynamically. jQuery would be able to easily target the element ID which is exact specificity - the preferred method when said element will remain static.