Category Archives: javascript

Sibling Rivalry

While working on a new responsive menu, I soon realized the need to be able to close any menu that might be open should the user choose another one. In a wide layout it would look particularly messy and confusing to have multiple menus shown. In a mobile layout that wouldn’t be so bad since there’s an accordion effect. However, the more real estate you can give back to the user the better!

Fortunately, jQuery has a handy selector that will grab all the li elements at the same level as the currently clicked/tapped element:

$(this).siblings().each(function() {
 
 // Animate close
 TweenLite.to($(this).find("ul > li"), speedFactor / 2, { height: 0, opacity: 0, ease: Power3.easeIn });
 TweenLite.to($(this).find(".menuArrow"), speedFactor / 2, { rotation: -90, ease: Power3.easeInOut });
 TweenLite.set($(this).find("ul > li"), { display: "none", delay: speedFactor / 2 });

 // Indicate menu is closed
 $(this).data("menuOpen", false);
});

Similar functionality can and should also be applied to the page as a whole so that pointing somewhere else would close all menus. Or, for that matter, when the user selects an item. Here are the results:

menu_landscape

menu_mobile

Proud to be Back

Run DMCTo borrow from Run DMC:

Listen party people here’s a serious song
It’s right not wrong, I should say right on
I gotta tell you somethin that you all should know
It’s not a mystery it’s history and here’s how it go

While session history management has been around for a few years, it’s not something I’ve needed until recently. Necessity dictates working both with AJAX/Web APIs and SEO as well as the ability to share links via email or social media. And it may well have been that prior to now there could have been gaps in browser coverage. According to http://caniuse.com/#search=Session%20history%20management adoption is widespread. So even an SPA (single-page app) can reasonably mimic traditional web navigation without you having to hang your keister out in the wind as a developer.

After dinking around with a couple HTML5  history navigational examples, and getting bogged down with some unexpected results in my AJAX/WebAPI project I, er, back-tracked and built my own bare-bones navigational example. This covers both real and virtual pages, navigation within and without the page holding the virtual content (e.g. pasting a link or clicking on it from an email or tweet). Feel free to play around and see if you spot any inconsistencies or unexpected behavior.

Navigating from another page (Click on the Virtual page link, then hit any of the buttons or the link back to real.html and the back/forward buttons in the browser. )

See update below!

http://ststates.azurewebsites.net/real.html

Accounts for linking from outside the site:

http://ststates.azurewebsites.net/virt.html?page=2

Looking at Developer Tools > console in your browser will report the history state and what triggered a change (replaceState, pushState, or popState). View the source (including comments) and you’ll see that all three of these are needed to cover the various navigational cases.

Update

Well, not so proud when I found out that just using the out-of-the-box HTML5 implementation of session history management had a nasty problem: Changing the title would also change it in the history. So holding down the back button, for instance, would show the same link for different URLs, e.g. “?page=1” and “?page=2” would share a title. That would truly suck in a production environment where the title is supposed to match a slug.

So I turned to history.js, which solved that problem and (theoretically should work with HTML4, although I don’t have a convenient means of testing that). Additionally, it took care of the problem with Safari popping an event on loading and shortened my code by some 30 lines, simplifying the logic considerably.

http://ststates.azurewebsites.net/virt2.html?page=2

The Beauty of Anonymity

No, not the kind commonly found on the Internet, which is often anything but. Rather, C#’s Anonymous types, introduced way back in 2007 with C# 3.0 and more often than not ignored by me until now.

I used to avoid JSON. Its syntax seemed just like every other delimited format I’d ever seen. In short, a headache to parse. XML is more verbose. Yet (at least for me) more humanly readable. That was until I found two things:

  1. XML parsing across different browsers is an even bigger headache
  2. With JSON I can create almost identical classes on both a C# server and a Javascript client

Later, the relationship was strengthened by the discovery of services like http://json2csharp.com/, which will create a C# class for you out of a JSON sample, as will more recent versions of Visual Studio. That’s great for dealing with someone else’s API output.

But sometimes a class seems like overkill. What if you have just one place where you really, really need to send just a bit of JSON to the client? For example, in one of my SignalR hubs, I need to send three things:

  1. brief message
  2. start time
  3. end time

SignalR, by the way, always sends JSON so all you need is some way to package (enclassulate?)  your data. Enter the Anonymous type, which if you use Linq you’ve probably already seen many times, e.g:

var productQuery =
    from prod in products
    select new { prod.Color, prod.Price };

foreach (var v in productQuery)
{
    Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}

With a var, the usage is basic: “var foo = new { someData = “something” };” Anonymous types support nesting too, so I was able to tidily separate my message data from my duration data. Here’s a sample method in the SignalR hub on the server:

public void AnonTypeDemo(string groupID)
{
    var startTime = DateTime.UtcNow;

    var endTime = startTime + TimeSpan.FromMinutes(10);

    // the anonymous type
    var data = new { message = "started", duration = new { startTime, endTime } };

    Clients.Group(groupID).anonTypeDemo(data);
}

The method sends a JSON string that looks like this:

{
    "message": "started",
    "duration": {
        "startTime": "2015-02-24T18:19:48.8008904Z",
        "endTime": "2015-02-24T18:29:48.8008904Z"
    }
}

On the client side, a Javascript method will be called by the SignalR client to process the received data:


myHub.client.anonTypeDemo = function (data) {

    console.log(data);

    var message = data.message;

    var startTime = data.duration.startTime;
    var endTime = data.duration.endTime;
}

And that’s all he wrote.

Ah, the Suspense

Unless you’re going for pinpoint animation timings it’s really pretty straightforward to create timers on a web page…or so I thought. I threw one together – a simple countdown timer that would get passed a duration, a DIV in which to display the time, a formatter function to make the time pretty, and a callback. It worked well. That is, until I tried it on my Windows Phone and happened to exit the browser while the timer was running.

I came back to the test page and the timer picked up where it left off. In some situations, this would be fine. But in my use the timer is meant to be triggered (more or less) at the same time for a group of users (via SignalR). It would be bad if one user got a text message during a 5-minute session, suspended the browser temporarily to check it, and then got an additional 30 seconds or whatever to keep on entering items after the session ended.

Was this just a Windows Phone issue? Nope. I tried it on an iPhone 5S and had the same issue. It makes sense. Phones need to conserve power whenever possible so suspending running code in a browser tab when it’s invisible is logical. I fixed this issue by setting an initiated time, using Math.round(new Date().getTime() / 1000. Each time the timer interval is called (once per second) the current time is gotten (also in seconds) and then the difference is compared to the elapsed time. And, if necessary, the timer’s remaining time is adjusted (by subtracting the suspended time span from the overall duration).

I ran into another minor issue: Hitting the test button that triggered the timer again would result in multiple intervals running. I needed to clear the current interval first. In this case, I decided to store the current interval ID in the display element, using the jQuery data function. After all, it’s the element being affected by the code.

This is the sort of thing that might be papered over easily by manipulating the UI so the triggering mechanism, e.g. a button, can’t be used more than once. But baking this little fail-safe right into the code heads off any unanticipated uses down the road. For example, perhaps the timer might be reset every time a user guesses the correct answer in a game and moves on to another question.

Here’s the complete code for the timer:

See the Pen zxWwOM by Jon Nehring (@stonetip) on CodePen.

JQuery HTML5 custom attributes

I came across what looks to be a good solution to managing UI elements (visibility, opacity, etc.) without resorting to burying styles in an attached CSS file. With HTML5, you can use custom attributes prefaced with “data-”, e.g:

<h1 data-groups="foo, bar">I have a session code</h1>

<p data-groups="bar">Enter it here to join a session</p>

You can extract that data, for example:

<div id="divNewSession" data-groups="foo">
var groupData = $("#divNewSession").data("groups");

Which would generally only make sense with something specific, such as a the DIV in this example. But you could also act globally on various elements that all share a data attribute, such as making them all invisible. You can even differentiate with keyword searches or a wildcard (contains) search:

// Any element with a data-group attribute containing "foo" will be affected
$("*[data-groups*='foo']").css("background", "black");

// Any element with a data-group attribute only containing "bar" will be affected
$("*[data-groups='bar']").css("background", "red");

Note the * after groups in the first example. This will act on any element even if the data-groups attribute contains more than just “foo”. Also pay careful attention to the use of double vs. single quotes. IE and Chrome didn’t care, but Safari did.

I like this approach because:

  • It’s easy to see the relationship between an element and an attribute
  • The relationship isn’t buried in an external CSS file or deep within a pile of javascript code
  • It doesn’t clutter up a CSS file with miscellaneous styles used just to control temporary states, e.g:
    #divNewSession { visibility: collapse; }
  • It’s flexible. An element might be affected in one case, ignored in another.
  • Use of a custom attribute avoids confusion or collisions with any other code or namespaces