Thursday, May 26, 2016

An Angular 2 Master/Detail using JavaScript

In this post, I'll talk about a complete Master/Detail sample I created for Angular 2 using JavaScript.

UPDATE 7/22/16: Fixed breaking changes in Angular with file refs.

[VIEW THE Plunker]


Why a JavaScript Sample?

It is apparent that TypeScript is the language of choice for Angular 2, and with good reason. But when teaching Angular 2 concepts to someone for the first time, it can be a benefit to stick with JavaScript, thereby removing the confusion of new TypeScript constructs. Not surprisingly, there is a dearth of full examples using JavaScript in Angular 2, so maybe this sample can help fill that void.

Using the Sample with MVC Web API

This sample was originally created with the Service hitting a Web API, but was adjusted to use an in-memory array for Plunker. The following tweaks are needed for hitting a Web API:

In beers.service.js, change the CRUD methods to use appropriate ng.http methods, and point to the MVC Web API url. Note how we add the ng.http.Headers collection as a parameter to the post call. This is important to avoid an error "415 / Unsupported Media Type: No MediaTypeFormatter is available to read an object of type 'xxx' from content with media type 'text/plain'."


        getBeers: function () {
             return this.http.get("api/beers").map(
                 function (res) {
                     res = res.json();
                     return res;
                 }
             );
         },

         saveBeer: function (beer) {
             var headers = new ng.http.Headers();
             headers.append('Content-Type', 'application/json');
             return this.http.post("api/beers", JSON.stringify(beer), { headers: headers });
         },

         deleteBeer: function (beer) {
             return this.http.delete("api/beers/" + beer.BeerId);


         }

In beer-master.component and beer-detail.component, the promise will now be an observable, so we instead use subscribe to await the return:

             this._beersService.getBeers().subscribe(
                 function (data) {
                     self.beers = data;
                 },
                 function (err) {
                     self.error = err;
                 }

             )

The Web API Controller itself should look something like the following.

    public class BeersController : ApiController
    {

        static Dictionary<int, Beer> beers = new Dictionary<int, Beer>()
          {
            { 1, new Beer { BeerId = 1, BeerName = "X Double Indian Pale Ale", BreweryId = 1, AlcoholPercent = 10.0M, ImageUrl = "http://middleagesbrewing.com/sites/default/files/styles/beer_label/public/labels/Double%20IPA%20Tap%20Marker.png?itok=agxkSzzn" }}

            // ... add more beers here :)

        };

        public IEnumerable<Beer> GetAllBeers()
        {
            return beers.Values.OrderBy(b => b.BeerId).ToList();
        }

        public IHttpActionResult GetBeer(int id)
        {
            var beer = beers.FirstOrDefault((p) => p.Key == id);
            if (beer.Value == null)
            {
                return NotFound();
            }
            return Ok(beer);
        }

        // POST api/values
        [HttpPost]
        public IHttpActionResult Post(Beer beer)
        {
            if (beer.BeerId == 0)
            {
                // new beer
                beer.BeerId = beers.Max(b => b.Value.BeerId) + 1;
                beers.Add(beer.BeerId, beer);
            }
            else
            {
                var beerEdit = beers.Where(b => b.Key == beer.BeerId).First().Value;
                beerEdit.BeerName = beer.BeerName;
                beerEdit.ImageUrl = beer.ImageUrl;
                beerEdit.AlcoholPercent = beer.AlcoholPercent;
            }
            return Ok(beer);
        }

        // DELETE api/values/5
        [HttpDelete]
        public IHttpActionResult Delete(int id)
        {
            beers.Remove(id);
            return Ok(id);
        }

    }

Sunday, January 3, 2016

Fluid Simulation using BabylonJS and LiquidFun

BabylonJS and LiquidFun allow for the creation of fluid simulations including soft body physics, using JavaScript and WebGL!

VIEW DEMO



Ingredients


Creating the Physics Sim

Like all physics engines, the first step for using LiquidFun is to create a World.

        // Liquid Fun Physics objects
        var gravity = new b2Vec2(0, -10);
        world = new b2World(gravity);

To create water and soft body physics using LiquidFun, we use Particle Groups. In the example below, we are creating a "rectangle" that will be filled with liquid particles. 

        // water
        var shape = new b2PolygonShape();
        var vertices = shape.vertices;
        vertices.push(new b2Vec2(-5, -1));
        vertices.push(new b2Vec2(5, -1));
        vertices.push(new b2Vec2(5, -2));
        vertices.push(new b2Vec2(-5, -2));
        var pd = new b2ParticleGroupDef();
        pd.shape = shape;
        pd.color.Set(0, 0, 192, 255);
        var group = particleSystem.CreateParticleGroup(pd);

Creating a soft body (like jelly) is just as easy - we just need to set a couple of extra flags in the particle group definition:

        // red jelly circle
        var circle = new b2CircleShape();
        circle.position.Set(-1, 8);
        circle.radius = 0.5;
        var pgd = new b2ParticleGroupDef();
        pgd.flags = b2_elasticParticle;
        pgd.groupFlags = b2_solidParticleGroup;
        pgd.shape = circle;
        pgd.color.Set(192, 0, 0, 255);
        particleSystem.CreateParticleGroup(pgd); 


Drawing using BabylonJS

There are two different types of items we need to draw in BabylonJS: particles and bodies. BabylonJS has a robust particle system which allows customization through a custom update function. Inside this custom update function, we can set the Babylon particle position and color based on the LiquidFun particle information:

  
        // draw particle systems
        for (var i = 0, max = world.particleSystems.length; i < max; i++) {
            var system = world.particleSystems[i];

            var particles = system.GetPositionBuffer();
            var color = system.GetColorBuffer();
            var maxParticles = particles.length;
            var transform = new b2Transform();
            transform.SetIdentity();

            for (var i = 0, c = 0;
            
     i < maxParticles && i < particlesBJS.length; 
                 i += 2, c += 4) {
                particlesBJS[i].position.x = particles[i];
                particlesBJS[i].position.y = particles[i + 1];
                particlesBJS[i].color.r = color[c];
                particlesBJS[i].color.g = color[c + 1];
                particlesBJS[i].color.b = color[c + 2];
            }
        }
    
Drawing the other bodies, such as ground or rigid physics objects is usually dependent on what you want to show in your simulation. In the demo,  we have ground objects and a little "smiley face" mesh that can be dragged around. In the case of the "smiley face," I used a cylinder with a material for the face:

var shape = BABYLON.Mesh.CreateCylinder("cylinder", 0.1, fixture.shape.radius * 2, fixture.shape.radius * 2, 24, 1, that._scene, false); 

... and then updating the position of the objects must be done on each iteration of the render loop. We need to set the position of the BabylonJS objects to be the same as the LiquidFun physics bodies:

var pos = fixture.body.GetPosition();
var angle = fixture.body.GetAngle();
fixture.babylonShape.position.x = pos.x;
fixture.babylonShape.position.y = pos.y;
  

Next Steps

This was just a quick overview of using BabylonJS and LiquidFun together. If you want to learn more, here are some links to get started:

Friday, October 23, 2015

AppXBundlePlatforms and Windows UWP app

Recently I've been working on porting one of my older Windows 8 apps to Windows 10 (Universal Windows Platform), and after associating the Windows 10 app with the Store, I started get the following compiler errors:


  • You cannot create an app bundle containing more than one package per architecture. Value of AppxBundlePlatforms property is 'neutral|neutral'.
  • You cannot create an app bundle which contains a neutral architecture package along with packages for other architectures. Value of AppxBundlePlatforms property is 'neutral|neutral'. 


If I did a Build/Clean Solution and then a Rebuild, the project was happy again, UNTIL I made another change.

Looking a bit closer, I noticed a Compiler Warning as well:


  • APPX4001: Build property AppxBundlePlatforms is not explicitly set and is calculated based on currently building architecture. Use 'Create App Package' wizard or edit project file to set it
Now this warning is actually _helpful_ ! Unfortunately, I tend to not look at Compiler Warnings as carefully as I should. But, in this case I packaged the app up, and noticed that the package process added the following to my .csproj:

  • <AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms>
... and all was happy again.

On a related note, the change from "neutral" to "x86|x64|arm" is because UWP apps are compiled to Native code when you choose a Release build. This promises 60% faster startup and 15-20% less memory use!

Friday, September 18, 2015

Windows 10 apps - Testing for Capabilities

Windows 10 (UWP) apps can be deployed to any device type as a single binary. But sometimes the capabilities of each device can differ. For example, a phone running Windows 10 has a Status Bar that shows network, battery and other info. But this Status Bar is missing on other devices such as the Desktop.

Let's say we add some code to hide the Status Bar in our UWP app:


                StatusBar statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView();
                statusBar.HideAsync();

... the first thing we'll notice is that our UWP app has no idea what a Status Bar is:


  • The type name 'StatusBar' could not be found in the namespace 'Windows.UI.ViewManagement'. 


To fix this first issue, we need to add a reference to "Windows Mobile Extensions for the UWP" - which contains phone-specific capabilities...



That will make the compile happy, but what if we run this code on a Desktop or other device that doesn't have a Status Bar?


  • An exception of type 'System.TypeLoadException' occurred in MyApp.exe but was not handled in user code

    Additional information: Requested Windows Runtime type 'Windows.UI.ViewManagement.StatusBar' is not registered.
So our binary is happy to compile and run, but as you can see it will crash at runtime. To get around this, we need to test to see if the StatusBar is present on the target machine...


            if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
            {
                StatusBar statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView();
                statusBar.HideAsync();
            }

So the key is the IsTypePresent method, which accepts the type name to test for. Given this, we can stick with our single binary, avoid more ugly compiler directives, and support each specific device's capabilities! 

Windows 10 App Design

I recently started moving one of my Windows 8 XAML apps to Universal Windows Platform (UWP) and was looking for some guidance on design and interaction. In previous versions, Visual Studio contained templates for Windows Apps including a Grid and Hub layout for Metro. But for the new Windows 10/UWP design, there are no templates included in Visual Studio 2015 at this time.

To see the drastic design differences between Win8 and Win10 apps, you don't have to look farther than first party apps, such as the News app...

Windows 8 News App



Windows 10 News App



As you can see, the metro-like concepts such as horizontal scrolling, slide-out menu options and mandatory full screen have been abandoned for vertical scrolling and *ahem* hamburger menu navigation.

So, as an App Developer, where do you go to get a "quick start" or guideline for UWP? Here are a few resources that I found useful.

  • UI basics for UWP apps breaks down the parts of an app from a high level, but stops short of code examples. Still a good idea to read through this though!
  • Navigation menu (XAML) sample is a concrete example of the Hamburger Menu integrating with navigation. I used this as a starting point for porting my app.
  • Template 10, while I chose not to use it, offers a more fleshed out starting point for a XAML-based UWP app. I started poking around with this, but it appears to be still a Work-in-progress at this point and had a bit more than I needed for my app conversion.



Wednesday, April 29, 2015

Using Ionic with Visual Studio Tools for Apache Cordova

Ionic has been gaining in popularity as a free and open source mobile development framework. It leverages AngularJS and SASS to provide a quick start to mobile development for iOS, Android and Windows.

The newly released RC of Visual Studio 2015 Tools for Apache Cordova (VS TACO) makes it easier to create Ionic apps using two different methods.

Method 1: Using the Ionic Templates for TACO

The easiest way (but not the best way) to create a new Ionic project using VS TACO is to use the new Ionic project templates, which are available on the Visual Studio Gallery.

However, there are currently some issues with using the template method:
  • at the time of this writing, the templates do not work with Windows Phone and Windows apps.
  • you are not guaranteed to get the latest Ionic CLI output when using the templates.
  • not all of the Ionic CLI templates are included in the VS Templates.
If any of these are issues for you, then continue to Method 2 below!



Method 2: Importing an Ionic Project

This second method involves creating an Ionic project at the command line, and then importing the source into a VS TACO solution. The advantage of using this method is that you will be sure to have the latest Ionic template source, and you have full control over what you bring into your project.

  1. Be sure you have ionic installed - you can install by typing the following at the command line.

    npm install -g cordova ionic
  2. Now, use Ionic to create a starter project. Ionic supports three different templates: blank, tabs, and sidemenu. To create the tabs template:

    ionic start myApp tabs

    NOTE: instead of tabs in the command above, you can also select blank or sidemenu.
  3. Next, create a Visual Studio 2015 TACO solution using the Blank App template:

  4. From the Visual Studio TACO solution you just created, select the following files and folders:


    ... and copy them to the "myApp" folder that you created using Ionic in Step 2.
  5. Open the myApp.jsproj file from the Ionic folder. Select "Save All" so that a new Solution (.sln) file is created for this project.
  6. Open index.html and add a reference to platformOverrides, which allows dynamic elements to work in Windows and Windows 8 apps:

    <script src="scripts/platformOverrides.js"></script>

    (if you are curious where this file is coming from, look in the merges/windows/scripts subfolder)
  7. At this point, you can run your Ionic app against Android, iOS, and Windows. Go ahead and try it! Note that Ionic does not _fully_ support Windows and Windows Phone platforms, but the Ionic team is working on getting full compatibility with Windows platforms.
  8. For Windows Phone 8.1 support (Windows Phone (Universal)), you will need to make one more tweak: add the following two nodes to config.xml:

    <preference name="windows-target-version" value="8.1" />
    <preference name="windows-phone-target-version" value="8.1" />

Using Crosswalk with Visual Studio Tools for Apache Cordova


4/29/2015 - Updated instructions for Visual Studio 2015 RC


If you've tried targeting Android devices using Hybrid app frameworks, you've probably run into issues with performance and outdated Chrome runtimes in the WebView. This is an issue with even newer devices with Android 4.4+ because the WebView does not use the same version of Chrome that the device has installed. For example, a Nexus 7 with Android 4.4.4 will use version 33 of Chrome - which is ancient in internet time! That means you are missing out on great features such as WebGL Support in Hybrid apps.

Enter the Crosswalk Project - which allows you to deploy the latest builds of Chromium with your Android app, and support all Android 4.x devices with the same featureset.


What is the downside you ask? The main downside is the size of your deployed app. You can expect the Crosswalk library to add about 15 MB to your APK if you target _either_ ARM or x86. If you choose to target _both_ with a single APK, you can expect about 30 MB added to the size. This is an unfortunate amount of bloat, but for some apps it might be just fine. But there are other downsides as well... Don't expect Debugging Support when using Visual Studio Tools for Apache Cordova (at least not in CTP3). You can however use Chrome DevTools to debug Crosswalk apps. Also in my experience, Emulator support is hosed as well - you will need a physical device to test and run your apps.

But if you determine the benefits of Crosswalk outweigh the limitations, read on!

Adding Crosswalk Support

  1. Before you start:

    Download and Expand the Crosswalk Cordova Android (ARM) and Cordova Android (x86) packages. IMPORTANT: Make sure you get the Cordova versions!!

    If you are doing this to an existing project, be sure you are checked into source control, or at least back up your project! Just in case something goes wrong.

    Note that these instructions are for Visual Studio 2015 RC. In later versions, these steps might change.

    You will need a physical Android device (I am using a Nexus 7)
  2. Create a new Visual Studio project using the Blank App template:

  3. Change your target to Android / Device:

  4. Run the Project so that it deploys to the device and runs.
  5. Open up Chrome and enter the url "chrome://inspect" - and note that the version of the Chrome WebView on the device is ancient history (in the case of the Nexus 7, it is 33.0.0.0).

  6. Back in Visual Studio, in the Solution Explorer select "Show All Files."
  7. Go to the \platforms\android\CordovaLib subfolder of the project, and delete the contents of \platforms\android\CordovaLib.
  8. Copy AndroidManifest.xml from \platforms\android\ to \res\native\android\
  9. Edit AndroidManifest.xml in \res\native\android\ so that it includes the following permissions just _before_ the <application> node.

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  10. Add a directory named CordovaLib in your \res\native\android\ folder.
  11. The Crosswalk packages you downloaded in Step 1 are needed now.

    copy the entire contents of the ARM directory

            \crosswalk-cordova-11.xx.xxx.xx-arm\framework

    to your project's

            \res\native\android\CordovaLib\
  12. Copy the VERSION file from

            \crosswalk-cordova-11.xx.xxx.xx-arm\VERSION

    to your project's

            \res\native\android\VERSION
  13. If you want x86 support as well, copy the x86 folder from

            \crosswalk-cordova-11.xx.xxx.xx-x86\framework\xwalk_core_library\libs\

    to your project's

            \res\native\android\CordovaLib\xwalk_core_library\libs
    ... so that it you have both the x86 and armeabi-v7a folders in the libs directory.
  14. Execute a Build in VS (Ctrl+Shift+B), so that the files in \res\native\android\ are copied to \platforms\android\.  NOTE: At this point, the build will succeed but Crosswalk is NOT yet enabled!
  15. Now we have to build the libs for Crosswalk.

    You only need to do this once.

    Open a command prompt at \platforms\android\CordovaLib and execute:

    android update project --subprojects --path . --target "android-21"

    Next, type in:
    ant debug

    ... you should see a BUILD SUCCESSFUL at the finish.
  16. In the command prompt, go up one directory to \platforms\android\ and once again update the version and run ant:

    android update project --subprojects --path . --target "android-21"
    ant debug

    ... you should see a BUILD SUCCESSFUL at the finish.
  17. Close any of the open cmd prompts and File Explorer Windows, as the VS build process attempts to delete some of these folders.
  18. Back in Visual Studio, select Build/Rebuild Solution. This time your build will take a bit longer because it's packaging up the Chromium runtime with the APK.
  19. Run the project on the device using F5. Note that Visual Studio currently does not support debugging with Crosswalk, because it cannot attach it's debugger. You can use ChromeDev tools to debug, however.
  20. To verify we are using Crosswalk, go back to Chrome and enter the URL chrome://inspect. You will see a much newer version of Chrome (in my case 40.0.2214.91, but it depends on the release of the Crosswalk libraries you downloaded in Step 1):




    That's it! We now have all of the goodness of a new Chromium runtime in our Android app, including toys like WebGL Support and improved performance!