I am a huge fan of HTML5 and JavaScript because they run on just about anything. I remember when web applications were in their infancy and the golden promise was that you could make a web application feel just like a desktop application – in a browser! Now we have come full circle into this weird parallel universe where we are putting web applications INTO desktop applications. It is heady and high times my friend!
Backstory
Aside from my JavaScript interests, I spend a lot of time doing events for the community. My partner in crime Aaron Murray @WeAreFractal and I are putting on an event called The JavaScript Taste Test with Microsoft where we will be exploring what you can actually do with HTML5 and JavaScript.
I was personally intrigued if I could write a Windows 8 application in JUST HTML5 and JavaScript. Could I do it on a Mac? Would it be hard? Would THIS happen to me?
Well I am going to just spare you the agony of wondering if I am even alive right now. It was pretty painless and felt pretty much like writing a web application. I kept my eyes closed the entire time! +1 if you get the joke.
Part Zero: The Source Files
You can download my project here if you want to follow along.
Part One: Testing the Waters
Microsoft has done a good job lately of making helpful tools available for the development community free of charge.
If you do not have a copy of Windows, you can download a VM image from http://www.modern.ie/en-us to get started.
The most economical choice is to use the VirtualBox image since VirtualBox is free of charge. I have a lot of friends that swear by VirtualBox and I take their word for it. I use Parallels and so I downloaded the VMWare Fusion image and just converted it. Took me all of about 40 minutes to download and get up and running. Bam!
From the VM, I downloaded Visual Studio Express for Windows 8 from http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-for-windows-8.
So, at this point, I was still pretty skeptical, so I figured the obligatory “Hello World” was in order, which I found here.
This took all of about 20 minutes to do and, so now I have about a 2 hour investment into the process. Not too bad!
Part Two: So About That AngularJS?
So now my curiosity is totally piqued. Can it be done man!?
Step 1: Create a New Project
So first things first, we need to create a new project. Ctrl + shift + n and you are on your way!
I left all the defaults as is and called the project HelloAngular. You can see my settings in the image below.
Step 2: Import AngularJS
Windows 8 applications require that all your scripts run local for security reasons and so I downloaded the latest angular.min.js and dropped it into the js folder of the project.
Step 3: Include AngularJS and Roll Dice
So I wanted to see if I could just bootstrap an AngularJS application and so I referenced the script and added ng-app to the html tag of the default.html file.
<html ng-app> <head> <meta charset="utf-8" /> <title>Hello AngularJS!</title> <pre><code><!-- WinJS references --> <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" /> <script src="//Microsoft.WinJS.1.0/js/base.js"></script> <script src="//Microsoft.WinJS.1.0/js/ui.js"></script> <!-- HelloAngular references --> <link href="/css/default.css" rel="stylesheet" /> <script src="/js/angular.min.js"></script> <script src="/js/default.js"></script> </code></pre> </head>
Oh noes!
“JavaScript runtime error: Unable to add dynamic content.”
Step 4: A Little Help From My Friends
To the Googles! A little poking around and I found that I was not the first one to experience this. A gentleman by the name of Jonathan Channon shed all the light I needed on this conundrum. You can read his post here.
Enter JavaScript juggernaut Elijah Manor @elijahmanor and his breakdancing crew with a custom version of jQuery. WINDOWS 8 STYLE!
Oh appendTo… I love you!
The moral of the story is to use jquery-win8 from here
Add the file to the js folder.
Include the script and make one small tweak as you can see below. Friction removed!
<link href="/css/default.css" rel="stylesheet" /> <script src="js/jquery-1.8.2-win8-1.0.min.js"></script> <script type="text/javascript"> jQuery.isUnsafe = true; </script> <script src="/js/angular.min.js"></script> <script src="/js/default.js"></script>
Behold the choir of angels! It works!
Step 5: Build Something!
I am not going to delve too much into the AngularJS application I built since it is super 101 level stuff, but here is the basic rundown.
In the js folder, open default.js and jump right to the bottom of the file. Just above the app.start(); function call is where I decided to craft my AngularJS app.
First, I define my AngularJS module, and then I define a MainCtrl on that module to hold my data and methods for the application.
// AngularJS Stuff var myApp = angular.module('app', []); <pre><code>myApp.controller('MainCtrl', function ($scope) { $scope.greeting = 'Hello AngularJS!'; }); </code></pre>
Now that I have a defined module, I am going to bootstrap the AngularJS application to use that module. That is as simple as updating ng-app to ng-app=”app” in the html tag.
<html ng-app="app">
Now I want to give the reins to MainCtrl to do its thing. I do this by using the AngularJS ng-controller directive with a value of MainCtrl. This essentially sets up the relationship between $scope and the HTML. Notice that I created a greeting property on $scope when I defined the controller. I can bind to that in the HTML using the doubly curly brace syntax a la {{greeting}}.
Side note: Directives are an entirely different conversation for another day, but for now think of them as “html elements with super powers”.
<body ng-controller="MainCtrl"> <h1>{{greeting}}</h1> </body>
Moving along…I am going to add a messages array to hold well…messages. Self documenting code FTW! And I am going to create a method called addMessage that adds a message to the front of the array via unshift. By adding these methods and properties to the $scope object, I am making them available to the elements that exist within the HTML element that we defined the controller on. You will notice that I am also setting a message property to an empty string. More on that in just a moment.
var myApp = angular.module('app', []); <pre><code>myApp.controller('MainCtrl', function ($scope) { $scope.greeting = 'Hello AngularJS!'; $scope.messages = []; $scope.addMessage = function (m) { $scope.messages.unshift(m); $scope.message = ''; } }); </code></pre>
To the HTML! Let’s start with the messages. I want to display all the messages that exist and so I do that with ng-repeat. ng-repeat is an AngularJS directive that essentially loops over an array and stamps out whatever element it is defined on. So in this case we are saying “Create a new p tag with the value of m for every message that exists in messages“. From there we are back to the curly braces for the binding.
And to add a message, we first declare ng-model=”message” on the messageInput element. This essentially sets up two-way binding with $scope from the HTML side. We are going to call addMessage by adding ng-click=”addMessage(message)” to the messageButton. The ng-click directive takes all of that messy event listening handlers and takes care of the biz for you. We are passing it the message value which is essentially whatever is in the messageInput field thanks to ng-model.
<body ng-controller="MainCtrl"> <h1>{{greeting}}</h1> Leave a message. <input id="messageInput" ng-model="message" type="text" /> <button id="messageButton" ng-click="addMessage(message)">Say "Hello"</button> <div id="greetingOutput"> <p ng-repeat="m in messages">{{m}} </div> </body>
And that my friends is how I did it! Behold!
Conclusion
I could have definitely dug into the AngularJS side a bit more, but I wanted to highlight how easy it was to get up and running, even for a guy on a Mac running Windows in a VM. It was really just HTML5 and JavaScript! Hooray!
AngularJS
http://angularjs.org/
Modern.ie
http://www.modern.ie/en-us/
VirtualBox
https://www.virtualbox.org/
jQuery for Windows 8 Store Applications
https://github.com/appendto/jquery-win8
Create your first Windows Store app using JavaScript
http://msdn.microsoft.com/en-us/library/windows/apps/br211385.aspx
That’s pretty sweet. I did it earlier and within about 45 minutes I had a working app (including download/install time).
Oh and an interesting note, you can get Angular and jQuery from NuGet:
http://nuget.org/packages/angularjs/1.0.5
http://nuget.org/packages/jQuery/
I did not use these in my tests but checked for them while re-familiarizing myself w/ VS.
hej,
ok but this is super simple scenario. what about nested views with win-controls? have you tried to port it to angular?
I fear that WinJs and PageControl make some magic behind scene and it wont be that easy to just call angular.module().configure
Worth noting that the Win8 specific version of jQuery is not needed. Win 8 is fully compatible with jQuery 2.0.
Yep! That happened post blog post 😀 Sneaky guys! I should update the post though…
Check out: https://github.com/codemonkeychris/angular-winjs, it’s a library to enable using WinJS UI controls like ListView natively within Angular.
Thanks Josh!
The jquery-win repo no longer contains the js file, but you can get it here:
https://github.com/th2tran/public/tree/master/Win8.AngularJS.App1/AngularJS.App1/_assets/js
Trying to run Angular 1.2.15 with jQuery 2.1.0 was puzzling….
Angular has an unsafe line where it adds an element to the DOM that apparently jQuery executes in a way that is not safe (I am not sure what I would expect from jQuery, as the Angular-element has a lot of properties that Windows could mark as “unsafe”; it should probably throw an error).
Anyway, putting this last line in an MSApp.execUnsafeLocalFunction works; the result:
MSApp.execUnsafeLocalFunction(function () {
!angular.$$csp() && angular.element(document).find(‘head’).prepend(‘@charset “UTF-8”;[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}’);
});
Hi, I am trying to build a Windows 8 app with angular, I followed your tutorial step by step, and it worked almost perfectly.
The problem is on the focus of inputs of type text, when I click on any of these inputs, the focus goes to some other part of the window, and I can’t type anything, btab to go tout if I use the fields, it seems to work fine, I can type something, click the button and add the messages.
Do you have any idea of what can be the problem?
Can you repost you sample ? (the link in the beginning is broken)
Ps.: I’ve tested also routing, and it worked fine too.
If you want, you can find my test on:
http://1drv.ms/1BKmb2H
Hi Matheus — thanks for pointing that out! Let me give this post some love and I will shoot you an email when it is back up. Thanks!
Hi, for those of you using angularjs and having input problems, you must add the attribute “ng-csp” to your html tag, this solves the issue:
The problem i’m having now is that when i click on an anchor tag “<a href='#/ '" windows does not know how to route this and offers me apps to open the link. Had you ever had this problem?
Thanks for this
Great Article !! Wish I’d found this a couple of days ago..
Special shout out to Maximiliano… the ns-csp fix for the Windows Universal App textbox/input edit is a life saver.. I’ve been banging my head on this issue for the last 10 hours..
🙂