JavaScript: some lessons learned

Checking for valid dates

A naive solution:

Minimal web server

As discussed yesterday, and not related to JS as such, but useful:

Get a count of the instances of a given “class” in the DOM

You have to walk those instances 1 by 1, getting the innerHTML or innerTEXT. As far as I can see, you can’t just aggregate it all up:

ES6 syntax: for / let /of

Sorting an array of objects by a single attribute, in this case:

Templates…

Do stuff with an object, then add it to the array:

The 2 parts needed to make sense of a linked HTML:


'use strict';
// entry point...
(function () {
var link;
var content;
var composers = [];

importComposers();

var composerSetCount = content.getElementsByClassName("ComposerSet").length;

for (var index = 0; index < composerSetCount; index++) {
var composerSet = content.getElementsByClassName("ComposerSet")[index].innerHTML;
var composersAsElements = htmlToElements(composerSet);

//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
for (let composerAsElements of composersAsElements) {
convertComposerTextToObject(composerAsElements, composers);
};
}

composers.sort(function(a,b) {return (a.lastName > b.lastName) ? 1 :
((b.lastName > a.lastName) ? -1 : 0);});

for (let comp of composers) {
var dates = [];
dates = validateComposerDates(comp);

document.writeln("
<h1>" + comp.lastName + "</h1>
");
document.writeln("
<h4>" + comp.firstNames + " " + comp.lastName + " " +
dates["Birth"] + " " + dates["Death"] + "</h4>
");
}

// functions...
function htmlToElements(html) {
var template = document.createElement('template');
template.innerHTML = html;
return template.content.childNodes;
}

function convertComposerTextToObject(composer, composersx) {
var composerText = composer.innerText;
if (composerText === undefined) {
return;
}
// Treat the characters , and [ and - and ] as delimiters for splitting the string into tokens.
// An example of a string to be split:
// SMITH, John [4/21/1712-7/9/1768]
var separators = [',', '\\[', '\\-', '\\]']
console.log(composerText);
var composerParts = composerText.split(new RegExp('[' + separators.join('') + ']', 'g'));

var theComposer = {};
theComposer.lastName = composerParts[0];
theComposer.firstNames = composerParts[1];
var dob = new Date(composerParts[2]);
if (dob.isValid()) {
theComposer.dateOfBirth = dob;
}

var dod = new Date(composerParts[3]);
if (dod.isValid()) {
theComposer.dateOfDeath = dod;
}

composersx.push(theComposer);
console.log(theComposer);

} // convertComposerTextToObject

function importComposers() {
link = document.querySelector('link[rel="import"]');
content = link.import;
}

function validateComposerDates(currentComposer) {
var composerDates = [];
composerDates['Birth'] = currentComposer.dateOfBirth === undefined ? "[unknown]" : currentComposer.dateOfBirth.toLocaleDateString('en-GB');
composerDates['Death'] = currentComposer.dateOfDeath === undefined ? "[unknown]" : currentComposer.dateOfDeath.toLocaleDateString('en-GB');
//console.log(composerDates);
return composerDates;

}

})();

HTML, Angular, Json

This is a variation on an earlier page that actually has a purpose. I used to chuck my favourite links into a piece of html.. well I’m still doing that, but at least I’ve separated the data from the code. I wanted to have a separate file for the Json, but in static pages, you can’t easily do that for security reasons, and I don’t want to spin up IIS etc for something so simple.

This is the end result (so you just keeping adding to the Json):

<pre><!DOCTYPE html>
<html ng-app="linksApp">
<head>
<title>My name is John</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
</head>
<body ng-controller="linksCtrl as ctrl">
<div class="container" ng-cloak>
<h2>{{ctrl.Summary}} (Count:{{ctrl.Links.length}})</h2>
<table class="table table-condensed">
<tr>
<th>Link</th>
</tr>
<tr ng-repeat="links in ctrl.Links">
<td><a href="{{links.URL}}">{{links.Name}}</a></td>
</tr>
</table>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.js"></script>
 <script type="application/javascript">
 var linksApp = angular.module("linksApp",[]);
 linksApp.controller("linksCtrl", [function() {
 vm = this;
 vm.Summary = "A Set of Links";
 vm.Links = Links;
 }]);
 </script>

</body>
</html>
<!-- data... -->
<script>
 var Links = [
 {"Name" : "My blog", "URL" : "https://dennisaa.wordpress.com"},
 {"Name" : "Foreigner - Double Vision - YouTube", "URL" : "https://www.youtube.com/watch?v=36hdcn_3ekI"},
 {"Name" : "Acer 27\" monitor", "URL" : "http://www.acerdirect.co.uk/Acer_K272HLbid_69cm_27_Wide_6ms_100M_1_ACM_300nits_VA_LED_DVI_w-HDCP_HDMI_UM.HW3EE.005/version.asp"},
 {"Name" : "Chords for Hazard", "URL" : "https://tabs.ultimate-guitar.com/r/richard_marx/hazard_crd.htm"},
 ];
</script>

Visual Studio Code: Intellisense for Angular

Firstly, credit to this person for getting me to a certain point. However, after attempting this line from the steps:

typings install angular --ambient --save

, I was rewarded with this message:

The GitHub URL looked promising, so I took a look there. More drilling takes you here:

And if you read the contribution from said blakeembrey, you get the normal thing of some man or woman heroically fighting a tide of requests…  in their own time. Blake Embrey: I salute you! 🙂

So anyway, Blake quite reasonably suggests looking at the ReadMe (remember to scroll down when you get to the link). In there, we find this nugget:

Let’s take that principle, look for the Typings package for Angular, and install it:

typings search --name angular
typings install dt~angular --global --save

(So the only change really is the [dt~])

Now, we’ll close and re-open VSC, just in case, start our JavaScript file, and see what happens (spoiler: it works):

Typings09

I didn’t show you the before picture – you’ll just have to trust me, you won’t get IntelliSense for Angular out of the box in Visual Studio Code

 

JavaScript: Chrome Debugger

I used breakpoints in Chrome for the first time just now. Worth sharing…

I have a sandbox-type html and javascript page when I’m playing, so I always just need to refresh the page in Chrome which I generally keep open.

The plain text is below, but in VS Code, this is how it looks:

test.html

basicstuff.js

So let’s start with a fresh Chrome page…

Go to the location of my page – as you see, there is no html…

Now press F12, which is the short cut for Google Developer Tools. Exactly what you see at this point depends on its most recent state, but let’s say it’s something like this, with the focus on console:

 

 

Click the double chevron, and select sources:

ChromeJs04

 

That brings up your code, both the html and the js. In this I dragged the vertical line to the left to give more real estate:

ChromeJs05

In the next shot, I have already clicked in the margin at line 23, to set a breakpoint. And I am about to bring up the debug controls, in the orange border:

ChromeJs06

ChromeJs07.PNG

If you now press the refresh button to the left of the URL in Chrome, you get this:

ChromeJs08.PNG

There are resume, step into, step over controls just under where you see Security, Audits, above. And hovering over a variable gives you its values, even for an object. In summary, it is REALLY useful, I find.

And finally, pressing F12 again takes you out of debug mode.

<!DOCTYPE html>
 <html>
 <head>
 <title>From the snippets location in Visual Studio Code</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js
 <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"></link>
 http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js
 http://BasicStuff.js
 </head>
 <body>
</body>
 </html>
 <!-- https://validator.w3.org/nu/#textarea -->
 <!-- Location is [file:///e:/sandbox/javascript/test.html] -->

var clique01 = {
// https://en.wikipedia.org/wiki/Bloomsbury_Group
 type: "luvvies", residence: "London WC1",
 member1: {name: "Virginia Woolf", speciality: "bleakness", category: "novels"},
 member2: {name: "Duncan Grant", speciality: "post-impressionism", category: "art"},
 member3: {name: "John Maynard Keynes", speciality: "spending your way out", category: "economics"},
 member4: {name: "Edward Morgan Forster", speciality: "despair", category: "novels"},
 numMembers: 4
 };
function getNovelists (clique, requiredCategory) {
 var novelists = [];
 var notNovelists = [];
 for (var i = 1; i <= clique.numMembers; i++) {
 var currMemberIndex = "member" + i;
 var currMember = clique[currMemberIndex];
 if (requiredCategory === currMember.category) {
 novelists.push(currMember);
 } else {
 notNovelists.push(currMember);
 }
 delete clique[currMemberIndex];
 }
clique.numMembers -= novelists.length;
 for (var j = 1; j <= clique.numMembers; j++) {
 clique["member"+j] = notNovelists.shift();
 }
return novelists;
 }
var novelists = getNovelists(clique01, "novels");
 var x = novelists;

Using VSC code snippets again

 

BootStrap01BootStrap02BootStrap03

{
“Basic HTML boilerplate”: {
“prefix”: “BasicHtml”,
“body”: [
“<!DOCTYPE html>”,
“<html>”,
“\t<head>”,
“\t\t<title>From the snippets location in Visual Studio Code</title>”,
“\t\t<meta charset=\”utf-8\”>”,
“\t\t<meta name=\”viewport\” content=\”width=device-width, initial-scale=1\”>”,
“\t\thttps://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js“,
“\t\t<link rel=\”stylesheet\” href=\”http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css\”></link>”,
“\t\thttp://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js“,
“\t\thttp://BasicStuff.js“,
“\t</head>”,
“\t<body>”,
“\t\t<input type=\”button\” value=\”Press me\” id=\”BasicHtmlPressMeId\”>”,
“\t\t<input type=\”text\” value=\”Press mex\” id=\”BasicHtmlCapacityId\”>”,

“\t</body>”,
“</html>”,
“<!– https://validator.w3.org/nu/#textarea –>”,
“<!– Location is [file:///e:/sandbox/javascript/test.html] –>”
],
“description”: “A basic snippet of HTML”
},
“B01BootStrap”: {
“prefix”: “B01”,
“body”: [

“,
“\t

A bunch of big Bootstrap buttons

“,

“,
“<p>”,
“\t<button type=\”button\” class=\”btn btn-lg btn-default\”>Default</button>”,
“\t<button type=\”button\” class=\”btn btn-lg btn-primary\”>Primary</button>”,
“\t<button type=\”button\” class=\”btn btn-lg btn-success\”>Success</button>”,
“\t<button type=\”button\” class=\”btn btn-lg btn-info\”>Info</button>”,
“\t<button type=\”button\” class=\”btn btn-lg btn-warning\”>Warning</button>”,
“\t<button type=\”button\” class=\”btn btn-lg btn-danger\”>Danger</button>”,
“</p>”

],
“description”: “Initial bootstrap buttons”
}

}

Visual Studio Code: a little more on snippets

Firstly, the think I always forget after being away for a while: you invoke the snippets intellisense by doing CTRL-spacebar, on a PC, anyway.

While blindingly obvious, this is a real time saver…

{
 "Print to console": {
 "prefix": "BasicHtml",
 "body": [
 "<!DOCTYPE html>",
 "<html>",
 "\t<head>",
 "\t\t<title>From the snippets location in Visual Studio Code</title>",
 "\t\t<meta charset=\"utf-8\">",
 "\t\thttp://BasicStuff.js",
 "\t</head>",
 "\t<body>",
 "\t</body>",
 "</html>",
 "<!-- https://validator.w3.org/nu/#textarea -->"
 ],
 "description": "A basic snippet of HTML"
 }
}