Stop Bootstrap alerts being removed from the DOM with AngularJS

So I was just working on a few updates to getTest (well actually a total re-write to be honest, introducing loads of great new features and functionality! Sign up to my mailing list if you’re interested in hearing when it’s available!) and I came across a rather silly thing with Bootstrap (version 3.2).

If you create a dismissible message box and dismiss it, Bootstrap removes it completely from the DOM! So if you want to be able to re-display that alert box with the same or different message (say you want to show a confirmation message every time someone updates their profile, but don’t want to have to reload the entire page between each edit, because that’s how we roll nowadays right?) you either have to dynamically create that alert message box each time you want to use it (urgh!), or you have to find another way to close (i.e. hide) it when it is dismissed by the user (much nicer!).

If you’ve reached this point and you’re wondering what I’m talking about, an alert message box looks like this:

dismissible-alert

and the HTML looks like this:

<div class="alert alert-warning alert-dismissible" role="alert">
  <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
  <strong>Warning!</strong> Better check yourself, you’re not looking too good.
</div>

So as I’m using Angular on getTestr I thought I would use Angular to hide the alert when the ‘close’ link is clicked.

My HTML now looks like this:

<div class="alert alert-warning alert-dismissible" role="alert" ng-show="message">
  <button type="button" class="close" aria-label="Close" ng-click="dismissAlert()"><span aria-hidden="true">×</span></button>
  <strong>Warning!</strong> Better check yourself, you’re not looking too good.
</div>

I’ve done a few things here – I’ve added an ng-show="message" attribute to the alert box so it’s only showing when $scope.message is truthy (i.e. it contains a message). I’ve removed the ‘data-dismiss="alert" attribute from the ‘close’ link so the alert box won’t be removed from the DOM and I’ve added an ng-click attribute instead: ng-click="dismissAlert()". In reality I’m also doing a few other things like binding the text within the alert box to a scope property, but I don’t want to over-complicate the example.

So now I just create the dismissAlert function in my Angular Controller (actually I’m doing this all within an Angular Directive, but for the sake of simplicity let’s pretend it’s in my Controller). This is really simple because I’m showing the alert when $scope.message is truthy, so to hide it, I just need to set $scope.message to false:

$scope.dismissAlert = function() {
  scope.responseData = false;
};

And that’s it – you can now re-use that alert box on the same page without a page reload!

Tagged with: , ,

Building Custom AngularJS Filters

In recent months I’ve really started to get excited about Angular filters! I know – living the dream right?

Straight out of the box, Angular provides some pretty cool filters such as orderBy which lets you order an array or list, date which lets you format a date, and json which displays any JSON data in a nice format (great for debugging your Angular application). Plus (as with virtually everything else to do with Angular) if you need something that doesn’t come straight out of the box, you can just build your own custom filter and do it yourself!

Here’s a little story about a time (this afternoon actually) when an off-the-shelf filter just didn’t quite do what I wanted it to, so I knocked up a quick custom filter which did exactly what I wanted it to do. I was very happy about that, and wanted to share the love!

In the project I’m working on at the minute, I wanted to format a date so it displayed the ordinal (the “th” or “rd” or “nd” that comes after the numerical day part of a date) on a report, and the AngularJS date filter just didn’t do it for me.

To recap, the Angular date filter works like this.

If you have one of those horrible JSON-formatted dates like 2016-02-25T22:04Z and you want to transform it into something that humans can make sense of without their eyes starting to bleed, you can either write a custom JavaScript function to strip it apart and rearrange it into the correct format, or you can use the Angular date filter.

To use the Angular date filter to display today’s date in a nice format (e.g. 25th Feb 2016 22:04) you just drop this snippet in your template, using whichever date format you want:

{{myNastyJsonDate | date: "dd MM yyyy hh:mm"}}

However, the Angular date filter doesn’t add the “th” bit for you, so in order to do this you have to create a custom filter!

To use custom filters you have to remember 3 things –

  1. How to code a custom filter
  2. Inject the custom filter in your Angular application
  3. Use the custom filter in your markup

Ok so number 3 shouldn’t really be that hard, and number 2 can be done like this:

var myAngularApp = angular.module("angularApp", ["myCustomDatefilter"])

So that leaves us with number 1, which isn’t that tricky really – here’s the basics of creating a custom filter:

angular.module("myCustomDateFilter", [])
  .filter("formatAsLongDateTime", [
    "$filter", function($filter) {
      return function(input) {
        //your code goes here
        return ouput;
      }
    }
  ]);

So you can see from the code above – we’re creating an Angular module, which is why we have to inject our custom filter directly into our Angular application – it’s an external module that the application needs to be aware of in order to use it. This is different to most other parts of an Angular application (controllers, services, resources etc) are created within the context of the application, so you don’t need to worry about injecting them into the application.

So, we create an Angular module, and then (on line 2) we’re creating a Filter for that module. This is done in pretty much the same way you create controllers or services – give it a name, and then pass in an array of dependencies (stuff that Angular needs to inject into your filter for you in order for you to be able to use them) followed by the filter function itself.

The $filter service we’re injecting into our custom filter is the off-the-shelf Angular service that does all the basic funky stuff for us. We’re going to use that in the filter, but you don’t necessarily need to use it. Our filter function essentially needs to apply the off-the-shelf date filter, but add the “th” after the day digits.

The filter function has an input (the data you want to apply the filter to), and then you return an output (the filtered data).

The code in our filter function will look like this:

var dayPart = $filter("date")(input, "dd");
var monthYearPart = $filter("date")(input, "MMM yyyy");
var output = parseInt(dayPart, 10) + getOrdinal(dayPart) + " " + monthYearPart;
return output;

You can see we’re using the $filter service in a similar way to how we used it in the basic template earlier – we’re using the “date” method of the $filter service, passing in our input date and applying a format to it (first we’re formatting it to get the day digits, then we’re formatting it to get the month and year digits).

The final part of this is to call the “getOrdinal()” function to work out what letters to put after the day digits.

(Psst I have to admit, I did grab the code to work out the ordinal stuff from this Stack Overflow post, because why make your brain hurt when someone else has already gone through the pain!)

The code for this getOrdinal() function looks like this:

var getOrdinal = function (dayPart) {
  var suffixes = ["th", "st", "nd", "rd"];
  var day = parseInt(dayPart, 10);
  var relevantDigits = (day < 30) ? day % 20 : day % 30;
  var ordinal = (relevantDigits <= 3) ? suffixes[relevantDigits] : suffixes[0];
  return ordinal;
};

So putting it all together, it looks something like this:

angular.module("myCustomDateFilter", [])
  .filter("formatAsLongDateTime", [
    "$filter", function($filter) {
      var getOrdinal = function (dayPart) {
        var suffixes = ["th", "st", "nd", "rd"];
        var day = parseInt(dayPart, 10);
        var relevantDigits = (day < 30) ? day % 20 : day % 30;
        var ordinal = (relevantDigits <= 3) ? suffixes[relevantDigits] : suffixes[0];
        return ordinal;

       return function(input) {
         var dayPart = $filter("date")(input, "dd");
         var monthYearPart = $filter("date")(input, "MMM yyyy");
         var output = parseInt(dayPart, 10) + getOrdinal(dayPart) + " " + monthYearPart;
         return output;
       }
     }
   ]);

Finally you need to drop the custom filter into your template. It looks pretty much identical to the very first example in this article, but instead of using the standard "date" filter we use the custom filter, and we don't have to specify the date format because that's taken care of inside the custom filter code:

{{myUglyJsonDate | formatAsLongDateTime}}

You can put all your filters into one filter module if you like, by chaining another ".filter(..." to the end of the first filter constructor. I prefer to keep them in separate modules though if they're not related (i.e. I have one module for my date/time formatting filters, one for my list filtering filters etc)

You can make them as simple (like this example) or as complex as you want (or need to) - which can be fun or not so much fun, depending on how you view the world...

Tagged with: , , ,

Adding custom domain names to Azure CDN

The Azure CDN (Content Delivery Network) service is a pretty awesome feature which enables you to serve your website content to an end-user from the closest geographical server to them, decreasing load times and cutting down on general internet traffic (which can only be a good thing)!

You can create a new CDN service in just a few clicks through the Azure Management Portal, and you can choose your content source to be Azure Blob Storage, a Cloud Service, a Web App or a custom source.

One great feature I’ve discovered with the Azure CDN service recently is the ability to use a custom domain name! So if I wanted to serve all my blog images through Azure’s CDN service using a custom domain such as content.maffrigby.com I can do that!

First you have to set up your domain name in your DNS server. So set up a sub-domain such as content.maffrigby.com and create a CNAME record, pointing to the Azure CDN end point you just set up. This will be something like az783031.vo.msecnd.net and should look a bit like this when set up:

cname_record

Once you have set up your domain name record, go back to your CDN service in the Azure Portal and click on the “Manage Domains” icon at the bottom of the screen. You will see a screen that looks like this:

customdomainname

Simply add in your custom domain name and Azure will attempt to verify it by ensuring the CNAME record is indeed pointing to the CDN endpoint Url. If everything is good, you should see a green tick next to your domain name. If you don’t see the green tick, then you’ve done something wrong with your domain name setup. Go sort that out and try again.

customdomainname_withdomainname

Once you click the ‘OK’ tick on this screen, Azure will do what it needs to do in order to set up that custom domain name on your CDN service.

The only other thing you need to do is have a bit of patience – it can take a while for these changes to kick in, and you might get 404 errors when you’re trying to access your CDN-ed content through your custom domain name. Go have a cup of tea, or two cups of tea and then try again.

Tagged with: ,

Manually trigger a database update after upgrading Umbraco

So here’s the scenario. You’ve just upgraded Umbraco in your development project to the latest version using NuGet (because why would you do it any other way?). You’ve built the solution, you visit the website and see this screen:

upgradingumbraco

You click ‘Continue’ (and then immediately wish you had taken a backup of your database before you clicked that button, because that’s what good developers should do!) and Umbraco goes off and does some database bits and bobs behind the scenes before redirecting you back into Umbraco. Yeay it worked!

You click around a bit, publish a few items here and there, and you’re now ready to deploy your updated Umbraco installation to your staging and production environments. But how can you trigger that database update process again because it’s already happened? There has to be a secret command or spell you can use to initiate it, but you can’t remember for the life of you what it is (and it’s actually quite difficult to find the answer from Google too!).

So here’s how to do it in 2 easy steps:

Step 1 – ensure you have the umbraco/install folder present in the environment you’re updating. Of course we all know that it’s bad security practise to have this folder in any public-facing Umbraco installation, so please remember to remove it once your update has finished. (Oh you didn’t know that? Well, now you know – you can impress your friends with this new found knowledge!)

Step 2 – open up the web.config file of your Umbraco website and look for the key called “umbracoConfigurationStatus”. It should look something like this:

<add key="umbracoConfigurationStatus" value="7.2.6" />

The value in this case is the version that you just upgraded to.

Decrease this value by 1 so it looks something like this:

<add key="umbracoConfigurationStatus" value="7.2.5" />

and that’s all you need to do.

Deploy your Umbraco codebase to your staging or production environment, and you will see that same upgrade splash screen. Click the ‘Continue’ button, promise yourself that next time you really will take a database backup before clicking that button, and let Umbraco do it’s magic.

Once the update is complete and you’re back in the Umbraco portal, look at the web.config file again and you will see the version number has been incremented back up to the current installed version.

P.S. after tweeting this article and before I even managed to get a cup of tea, Sebastiaan Janssen (Project Manager at Umbraco HQ) replied with some further info on this. I’m not going to re-write this article though as my cuppa is going cold, so here’s Sebastiaan’s tweets with that info:

 

So effectively you only have to worry about triggering this database update when you do minor version upgrades, and you don’t have to worry about it at all after version 7.3!

Tagged with:

New things I learned today part 2 – Azure WebJobs ignore app.config transforms

I recently posted a two-part article about getting started with Azure WebJobs and was raving about how awesome they are.

In a WebJob I built for my current project (which is about to finish so contact me if you want me to work on your awesome project) I set up some app.config transforms which contain a couple of entries – one for the database which my WebJob is saving data to, and another for the Message Queue that triggers my WebJob. These are different for dev, staging and live as you would expect.

So the “new thing I learned today” is that they’re not as totally awesome as I first thought – when you publish your WebJob to Azure, it process totally ignores app.config transforms! It’s not just me “doing it wrong” – there’s others out there that have reported the same thing like this dude and these dudes.

So until this functionality is added to the Azure SDK you will need to either manually edit your app.config file before publishing it to different environments, or come up with some hacky code to work around this issue.

Tagged with: , ,
Top