Reactive Extensions are everywhere – I wanted to try the JavaScript version of the library, so below is a sample React component demonstrating a “fake” service call that might occur within the fetch function. The setTimeout is used simply to simulate some latency in the call.
In this example we have the fetch function returns an instance of an Observable of type string. We then subscribe to this within the componentDidMount function, which is called when the component is inserted into the DOM and then we subscribe to the Observable, updates will be applied to the component’s state.
The componentWillUnmount is called when the component is removed from the DOM and hence we unsubscribe from the Observable.
Web components are analogous to self-contained controls or components as you’ll have seen in Windows Forms, WPF etc. They allow developers to package up style, scripts and HTML into a single file which also is used to create a custom element, i.e. not part of the standard HTML.
Sadly, still not yet available in all browsers (although I believe Polyfills exist for the main ones). Hence, for this post you’ll either need a polyfill or the latest version of Google Chrome (which I’m using to test this with).
What does it look like using web components?
To start with we create an HTML file for our web component, we then define the template for the component – this is basically the combination of style and the control’s HTML. Finally we write scripts to effect the shadow DOM by interacting with our web component.
In this post we’re going to create a simple little web component which will flash it’s text. Before we look at the component code let’s see the component in use within the following index.html file
The key points here are that we include the web component using the line
<link rel="import" href="flashtext.html">
and then we use the custom element flash-text with it’s custom attributes and we use the component like this
<flash-text data-text="Hello World"></flash-text>
It’s important to note the closing element, a self closing element is not correctly handled (at least at this time using Google Chrome) and whilst the first usage of a web component might be displayed, if we had several flashing text components in the index.html it’s possible only one would be displayed and no obvious error or reason for the other components not displaying.
Creating our web component
We already decided our component will be stored in flashtext.html (as that’s what we linked to in the previous section).
We’ve created a new template with the id flashTextComponent. This id will be used within our script, it’s not what the pages using the component uses. To create a new custom element by adding the following to the script
var flashText = document.registerElement('flash-text', {
});
But we’re getting a little ahead of ourselves. Let’s instead create some styling and the HTML for our component. Within the template element, place the following
The style section simply defines the CSS for both the flashText div and the text div within it. The div elements create our layout template. Obviously if you created something like a menu component, the HTML for this would go here with custom attributes which we’ll define next, mapping to the template HTML.
Next up we need to create the code and custom attributes to map the data to our template. Before we do this let’s make sure the browser supports web components by writing
var template = document.createElement('template');
if('content' in template) {
// supports web components
}
else {
// does not support web components
}
If no content exists on the template, Google Chrome will report the error in the dev tools stating content is null (or similar wording).
Within the // supports web components section place the following
var ownerDocument = document.currentScript.ownerDocument;
var component = ownerDocument.querySelector('#flashTextComponent');
var templatePrototype = Object.create(HTMLElement.prototype);
templatePrototype.createdCallback = function () {
var root = this.createShadowRoot();
root.appendChild(document.importNode(component.content, true));
var name = root.querySelector('.text');
name.textContent = this.getAttribute('data-text');
setInterval(function(){
name.style.visibility = (name.style.visibility == 'hidden' ? '' : 'hidden');
}, 1000);
};
var flashText = document.registerElement('flash-text', {
prototype: templatePrototype
});
Let’s look at what we’ve done here. First we get at the ownerDocument and then locate our template via it’s id flashTextComponent. Now were going to create an HTMLElement prototype which will (in essence) replace our usage of the web component. When the HTMLElement is created we interact with the shadow DOM placing our component HTML into it and then interacting with parts of the template HTML, i.e. in this case placing data from the data-text custom attribute, into the text content of the div text.
As we want this text to flash we implement the script for this and attached to the visibility style of the text.
Finally, as mentioned previously, we register our custom element and “map” it to the previously created prototype.
Using in ASP.NET
ASP.NET can handle static pages easily enough, we just need to add the following to the RouteConfig
routes.IgnoreRoute("{filename}.html");
Now, inside _Layout.cshtml put in the head section
and within the Index.cshtml (or wherever you want it) place your custom elements, i.e.
Promises, are analogous to futures or tasks (if you background is C#) and are used for asynchronous code.
I’m using TypeScript at the moment (as part of learning Angular 2) but I’ll try to list code etc. in both JavaScript and TypeScript, solely to demonstrate the syntax. The underlying functionality will be exactly the same as (of course) TypeScript transpiles to JavaScript anyway.
let promise = new Promise((resolve, reject) {
// carry out some async task
// then resolve or reject
// i.e. resolve(result);
// and/or reject("Failed");
});
As you can see in the above code, we can (in essence) return a success, with resolve or a failure, with reject.
In some situations we might simply wish to immediately resolve or reject without actually executing any asynchronous code.
In such situations we can use the methods Promises.resolve and/or Promise.reject method calls, i.e.
// in JavaScript
function getData() {
return Promise.resolve(data);
// or
return Promise.reject("Cannot connect");
}
// in TypeScript
getData(): Promise<MyDataType> {
return Promise.resolve(data);
// or
return Promise.reject("Connot connect);
}
As you can see the difference between TypeScript and JavaScript (as one might expect) is the strong type checking/expectations.
Using the results from a Promise
As a promise is potentially going to be taking some time to complete we need a way to handle continuations, i.e. what happens when it completes.
In C# with have ContinueWith, in JavaScript we have then, hence our code having received a Promise might look like this
let promise = getData();
promise.then(result => {
// do something with the result
}).catch(reason => {
// failure, so something with failure
});
There are other Promise methods, see promise in JavaScript but this should get us up and running with the basics.
In JavaScript everything is an object from the obvious, such as arrays, strings etc. through to functions.
So how do we handle encapsulation such that we will have private and public data and methods ?
Well, because functions are themselves objects we can declare private data internally (within the function) and then using the prototype property we can add methods to the function that are public.
Below is a very simple example of encapsulation. The variable balance is private as it’s declared within the scope of the BankAccount function.
The functions add, subtract and getBalance are public and thus we can interact with this object using the following
var bankAccount = new BankAccount();
bankAccount.add(100);
bankAccount.subtract(10);
var current = bankAccount.getBalance();
If we wanted to make the balance variable public, we could simply alter the var balance = 0 to this.balance = 0 but of course this allows us to change the balance variable without going through the add/subtract methods.
To implement a more property like variable (as per C# for example) whereby we have methods to get/set the property we might look to implement something like
function BankAccount() {
var balance = 0;
this.__defineSetter__("balance", function(x) {});
this.__defineGetter__("balance", function() { return balance; });
// rest of the methods as before
};
Here we define a getter such that we can access in this way bankAccount.balance but we’ve defined a setter that does nothing so whilst a setter exists it doesn’t alter the balance.
JavaScript is a dynamic language. We do not need to declare properties or methods on an object prior to using them, for example the following will automatically add a new property and method to an object
var o = new Object();
o.Message = "Clicked";
o.Clicked = function() {
alert(this.Message);
}
So in the above code we create an instance of an Object and then by calling o.Message we basically add a new property to the object o. Next we create a method on the object. Note: We need to use “this” to access the property from within the method otherwise the code tries to access an undefined variable.
We can actually add properties and methods as well as access them using indexer notation, for example
var o = new Object();
o["Message"] = "Hello";
and this allows us to even call methods dynamically such as
var clicked = "Clicked";
var o = new Object();
o["Message"] = "Clicked";
o["Clicked"] = function() {
alert(this["Message"]);
}
o[clicked]();
So in the above we can dynamically change the method called (assuming we had more than one method).
We can also iterate over the members of an object using the following
var o = new Object();
o["Message"] = "Clicked";
o["Clicked"] = function() {
var s = "";
// iterate over the object
for(var p in o)
{
s = s + p + ";"
}
alert(s);
}
Using the for..in loop we simply iterate over and object, the string “s” will be “Message;Clicked”.
Finally, we can add properties and methods, but we can also delete them using
delete o.Message;
This deletes the Message property from the object o.
Types
JavaScript is loosely types. We declare variables using the var keyword and a variable can change type at any time, for example
var tmp = 3.1415926;
tmp = "Hello";
The runtime will not complain about the type conversion from a floating point number to a string.
JavaScript has a small number of types which include, string, number, boolean, array and object.
A string may be declared using either double quotes or single quotes, obviously this helps when the string is declare inline.
A number can be declared with or without decimal places (in other words it can be floating point or an integer).
A boolean may be true or false (as one would expect)
An array can be declared in various ways (described later) and can store heterogeneous data types
An object can be declared and properties and methods assigned to it (see above)
If a var is not assigned a value it is “undefined” (which is itself a type), basically this is a variable that has no value, but we can also use null to denote an “empty” value.
Declaring Arrays
Arrays can be declared in various ways, for the first example we declare an array and then we dynamically add items by creating an index to them
var vowels = new Array();
vowels[0] = "a";
vowels[1] = "e";
vowels[2] = "i";
vowels[3] = "o";
vowels[4] = "u";
A couple of alternatives are
var vowels1 = new Array("a", "e", "i", "o", "u");
var vowels2 = ["a", "e", "i", "o", "u"];