Friday, April 14, 2017

Angular 2 - Our First Component

This is the second in a series of posts describing how to build an Angular 2 application from the ground up by using the Angular CLI.  The first installment in the series can be found here.  I'm going to build on what I did in that post so it would probably help to at least be a little bit familiar with what I did there.  If you want to skip that first installment you can get the code that we generated during that part of the guide by visiting Github (here) and switching to the first-installment branch.

At this point we have our basic application running and we essentially have "Hello, World" going in our browser.  That's a great start, but it doesn't really do anything for us.  Let's build out the application by displaying a list of students in the UI.  We're not going to worry about styling right now.  Instead we're just going to show each student in a separate div.  We can style it later (or not, whatever).

Let's take an object-oriented approach to this part (I know, "object-oriented approach to JavaScript?!?!", but yes.  We're using TypeScript and the newer versions of the ECMAScript specification support designing objects).  What is a student?  For our purposes we're going to say a student has the following characteristics:

  • id
  • name
  • teacherId
  • age
If we were writing in C# we'd create a POCO that represents a single student and specify somewhere that we have a List<Student>.  Since this is TypeScript we're going to do things slightly differently.  Create a new folder under src/app and name it "common" (obviously without the quotes).  In your command prompt, navigate to that new folder (so I navigated to D:\Dev\Learning\Angular2\cli\ProveIt\src\app\common) and run the command ng g interface student. This creates a new interface called student in the common folder.  Go ahead and open that file (src/app/common/student.ts) and you'll see that it's pretty simple at this point.  It's just a declaration and export of what amounts to a POCO - or in this case a POJSO (Plain Old JavaScript Object).

We can add our properties to the interface and specify their type.  Our new interface looks like this:
export interface Student {     idnumber;     namestring;     teacherIdnumber;     agenumber; }
All we've done here is specify what a Student looks like to us.  Now we're going to use our Student interface in our StudentsComponent.  Open src/app/students/students.component.ts and import the new Student interface at the top of the file.
import { Student } from'../common/student';
Now that we have our Student interface available to us, we'll create a property on our StudentComponent that is an array of Students.  Just inside the creation of the StudentComponent class (so this would be above the constructor) add this line: studentsStudent[] = [];. This tells Angular that our every single object in our students array is going to implement the Student interface. Doing this gives us type checking while we develop. In Angular! How cool is that!?

Go ahead and populate the students array with 5 students.  Just make up the information.  I usually use pop culture characters and consecutive numbers for ids.

If you're not already serving your application you should do that now and make sure everything still works properly.  In your command prompt navigate to the application directory (so mine is D:\Dev\Learning\Angular2\cli\ProveIt) and run the ng serve --open command.  You should still see "students works!" as the only thing on the page.  We're about to change that.

Open your students.component.html file and replace the contents of the file with this:
<div *ngFor="let student of students">   {{student.id}} {{student.name}} {{student.teacherId}} {{student.age}} </div>
If you look at your application now you'll see each student's information listed on a separate line. Sweet! That's what we were going for. Remember that at least for now we don't really care how it looks. In a future installment of this guide we're going to bring in Bootstrap and style this up a little bit better. For now we have a little bit more work to do.

Let's create another component; one that allows us to view the details of a student.  Right now we only have a little bit of information about them, but we want to be able to see more.  To create a new component we'll use Angular CLI from the command prompt.  Go to src/app and run the command ng g component student to create a new StudentComponent.  If you're worried that the name will be too easy to confuse with the current StudentsComponent you can name it something else (like student-detail) if you want.

Open the newly created student.component.ts and we're going to jump right in to making some changes.  Right away we want to import Input from @angular/core so you can just add it after the import of OnInit (in the same curly brace).  We also want to import the Student interface like we did in the StudentsComponent.  In fact, you can copy that line exactly from StudentsComponent into StudentComponent.  Next we'll add an input property called student.  Add this line just above the constructor: @Input() studentStudent;  Setting the @Input() decorator on this property tells Angular that we're going to get this value as an input wherever the StudentComponent is used.  Add city (as a string) to the Student interface, then update the list of students so that each student has a city.

In student.component.ts replace the templateUrl with an inline template by replacing the entire templateUrl line with this: template'<p>{{student.name}} lives in {{student.city}}</p> So now all we need to do is figure out which student's information to show and how to show it.  We're going to go back to students.component.html and make a few changes now.  Oh, you can delete student.component.html if you want to since we're not using it anymore.

Back in students.component.html we're going to add a click handler on the main div that's repeating for each student.  When the user clicks on a student in the list of students we're going to invoke a function called show and pass the current student to that function: (click)="show(student)" You'll want to add that to the <div> that has the *ngFor on it. Down below that <div> we're going to introduce the student component by adding this code:
<app-student *ngIf="selectedStudent" [student]="selectedStudent"></app-student>
Now we'll wire up that click event to set the selectedStudent to whatever student was passed to the function. First we need to add a property called selectedStudent that is of type Student. You should know how to do this by now so I'm not going to show you.
show(student) { this.selectedStudent = student; }
So now we have (sort of) a working app. We can see a list of students and we can click on a student to view his "details" (such as they are). We have two components working together and we have an interface keeping us honest with our Student objects. We've taken an object-oriented approach to creating an Angular 2 application and so far it's going pretty well. We'll look at routing in our application in the next installment, btu that's all for now.

Angular 2 - Getting Started with Angular CLI

Angular 2 (finally) went live in September 2016 and I (finally) have had a chance to work on it, both at work and on a couple of personal projects.  This post is a bit of a deviation from the overall intention of my blog in that there are already some pretty good guides available for getting started with Angular 2.  The only reason I'm writing this one is to make sure I understand the ins and outs of doing it myself.  So, I guess in that regard, this post isn't a deviation at all.  Huh.  Cool.

I'll start off by pointing out that, yes, Angular 4 is already released (don't worry they just skipped 3).  I plan to work with 4 soon enough, but so far what I've done has been in 2 so that's what I'm documenting.  Since 4 is already out it can be a bit tricky to find the documentation for 2, so here's a link to it: https://v2.angular.io/docs/ts/latest/.  Now that that's out of the way, let's dig right in.

OK, so you'll still need npm (and therefore node.js) installed so if you haven't done that yet, do it now.  With npm installed you can install the Angular CLI globally with the following command: npm install @angular/cli -g.  All of the CLI documentation can be found here.

I've checked in the code that corresponds to this series on Github.  You can find it here.  For this installment of this guide you'll want to checkout the first-installment branch.

Once the CLI is installed you just have to run the following command in the directory you want to create your project: ng new [project name] where [project name] is the name of your project. So I'm going to create a project at D:\Dev\Learning\Angular2\cli called ProveIt. I'll navigate to D:\Dev\Learning\Angular2\cli in my command prompt and run ng new ProveIt. Creating the project using the CLI is the easiest way I've found.  You should be aware that the CLI uses Webpack so if you come across some bit of help (that's probably outdated) that talks about SystemJS, that probably won't work for you if you're following this guide.  ng new initializes git and installs a ton of npm packages for you so it takes a few minutes to complete.  Once it does finish, though, you actually have a working, testable application.  To prove it you can navigate into the directory you created (for me, that's D:\Dev\Learning\Angular2\cli\ProveIt) and run the command ng serve --open.  That will build your Angular 2 project, host it on port 4200, and launch your default browser to the root level of the application.  You should see a message that says (as of this writing) "app works!".  Congratulations!  You've "written" an Angular 2 app!

So now we have the default app running, which is a great start, but it isn't really an application.  At least, it doesn't do anything.  Let's use the CLI to add a new component to the application, called students.  Open a new command prompt and navigate to your new project (D:\Dev\Learning\Angular2\cli\ProveIt).  From there you want to go forward to src/app and run the command ng g component students.  This command is much faster, and creates four new files and modifies one file.  It's time to open our application.  I prefer VS Code, but you can use whatever you want.  Open the ProveIt folder and we'll explore some of the files that have been created so far.

.angular-cli.json

This is the configuration file used by the CLI to bootstrap the application when you run ng serve.  The CLI includes a built-in SASS parser so one of the first things I always do is change my styles.css to styles.scss and update this file to reference the .scss file instead of the .css file (line 22 as of this writing, but it's in the "styles" array).  If you want to include any 3rd party scripts (like Bootstrap) you'd add their relative path (assuming you added them via npm they'd be in node_modules/...) to the "scripts" array.  Finally, if you have nested directories with assets you want to deploy (like images or customized fonts) you'd add those to the "assets" array.  Just adding the top-level folder should be enough to include the entire directory in the output.

index.html

This file is the only file initially loaded by the application. Since Angular is focused on creating Single Page Applications (SPAs) this is that single page. From here on out everything that gets loaded just enhances the DOM or functionality of this one page. If you look in the <body> tag you'll see that we start off with an unknown (at least to HTML) tag called <app-root>. As we'll see in a few paragraphs this is actually an Angular component. Just keep this in mind as we move forward.

src/main.ts

This is essentially the entry point for the compilation of your application. I'm not going to lie and tell you I know exactly how this works, because I'm still a little murky on it, but I can tell you that it's where your browser gets told which module to start with. It should be defaulted to AppModule.

src/app/app.module.ts

This is the declaration of the AppModule.  You can see at the end of this file that AppModule is exported, which allows it to be used by main.ts as the bootstrap module.  You can also see that this file imports the necessary modules from various @angular folders that you're going to need to run this application in the browser.  Finally, there are two components imported and listed in the declarations section.  Part of using the Angular CLI to generate a new component (like we did earlier) is that the CLI will edit this module to import and declare your new component automatically so you don't have to worry about that part.

src/app/app.component.ts

This is where the actual AppComponent is declared and exported so it can be used in the AppModule as the bootstrap component (which means it's where the whole application starts).  You can see that the Component recipe is imported from @angular/core and then the class (AppComponent) is decorated with the @Component decorator, which specifies the selector for the component, the location of the template for the component, and the location of the stylesheet for the component.  This component has a single property, called title.

src/app/app.component.html

This is the markup that will be injected wherever Angular 2 finds our app component being used.  In other words, when we use <app-root></app-root>, Angular 2 will inject whatever is in this template file inside those tags.  Right now it's just a placeholder that displays the title inside of an <h1>, which is why we see "app works!" when we run the application.  The value of title is being set in app.component.ts and then displayed here.

If we examine the students.component.ts and students.component.html files that were created by the Angular CLI we'll see that they are very similar to the app.component.* files we just looked at.  Components are the basic force within Angular 2.  Components allow us to manipulate the DOM to do and show what we want.  One thing we haven't done yet is use our StudentsComponent in our application.  Let's go back to index.html and take another look.  Knowing what we know now about our AppComponent and its selector we can see that Angular is being told to inject the contents of src/app/app.component.html between the opening and closing <app-root> tags.  We want to do basically the same thing with our StudentsComponent so let's make that happen.  Open src/app/app.component.html and replace {{title}} with <app-students></app-students>.  If you left Angular CLI serving the application then just look at that tab in your browser again and you should see that the message has changed to "students works!".  What's happening is that Angular finds the <app-root> tag and injects the contents of the AppComponent in there.  While Angular is injecting that content it comes across the <app-students> component and realizes it needs to inject the contents of students.component.html into the AppComponent markup.  Since the content of our StudentsComponent is a simple message that says "students works!" (as you can see by opening src/app/students/students.component.html) that's what we see in our browser.

I'm going to end this post here because I think there's been a lot to digest so far.  This will only be the first in a series that I'll hopefully get up pretty quickly.  I'm still learning Angular 2 so don't take what I say as absolute truth.  Remember that I'm just putting up my thoughts to help me out in the future.

Sunday, March 19, 2017

Gitting Started with Git

I've recently switched from using TFS to using Git as my Version Control System of choice.  Some folks have been having issues making the transition so I put together a guide to get them through the process and I wanted to share it here for others.

The first thing I want to do is put a disclaimer out that I stole the name of this post from a session at Desert Code Camp last year.  Sorry, dude who presented it.  It was catchy.

I may edit this post in the future with some shortcuts and stuff, but for now here's a link to the slideshow I put together to present at work: https://docs.google.com/presentation/d/1KOc1M4KlXgzvdoRhjkcaZ8FeSOoN0z1RVnI8odSZo_0/edit?usp=sharing

Saturday, February 11, 2017

Testing Resolves in Jasmine

I've come across this issue before and I came up with a different answer (I think), but I can't remember that answer and I can't find it here.  So today I'm posting my new answer so at least I have this one for next time.

I'm using Angular UI Bootstrap's modal control to... open a modal.  I suppose that's kind of obvious.  Anyway, when you open a modal you can pass functions in that get resolved in the controller.  I'm not going to explain that in great detail here.

My problem was testing those resolves in my modal instance controller.  The resolves look something like this:
resolve: {
    student: function() {
        return {};
    },
    title: function() {
        return 'Add a Student';
    }
}

Since they're functions, UI Bootstrap is going to handle resolving them (get it?) to their returned values.  So when the controller loads, student will be an empty object and title will be that text.  When I test the modal instance controller I'll just be sure to inject those resolved values instead of functions.  It looks like this:
beforeEach(inject(function(_$rootScope_, _$controller_) {
    scope = _$rootScope_.$new();

    _$controller_('studentController', { $scope: scope, title: 'Add a Student', meal: {} });
}));

Now in my tests I can use those values the same way they'll be used in the actual code.  I answered a question on Stack Overflow about this topic a while back, but I can't recall what code I was looking at that prompted me to go looking for an answer that lead me to that question that I was able to answer.  Anyway, here's my answer on SO: http://stackoverflow.com/questions/37023953/unit-testing-ui-router-with-resolve/37075491#37075491

Tuesday, December 20, 2016

Testing "this" with Jasmine

I had cause to test a function that references this in JavaScript and, although it ended up being easy, it took some figuring to get there.  Rather than have to figure it all out again (and maybe to save someone else some trouble, too) I'm putting my solutions here (yes, there are two solutions).

Here is the function I needed to test:
$scope.dataBound = function(e) {
    var data = this.dataSource.data();
    for (var i = data.length; --i >= 0;) {
        if (!data[i].IsBundle) {
            var row = $('#grid')
                .data('kendoGrid')
                .tbody.find('tr[data-uid="' + data[i].uid + '"]');
            $(row).find('td.k-hierarchy-cell .k-icon').removeClass();
        }
    }
};

The first - and easiest - solution is to set whatever you need on scope.  In Angular, when this is referenced, it's referring to scope so in my case I was using this.dataSource.data() so I was able to just set an object directly on scope called dataSource that had a data function.
it('should set this on scope', function() {
    // arrange
    scope.dataSource = {
        data: function() {
            return [];
        }
    };
    spyOn(scope.dataSource, 'data').and.callThrough();

    // act
    scope.dataBound();

    // assert
    expect(scope.dataSource.data).toHaveBeenCalledTimes(1);
});

The second - and in my opinion more correct - solution is to invoke the function using call and pass whatever you want this to be as your first parameter.
it('should set pass this using call', function() {
    // arrange
    var thisToSet = {
        dataSource: {
            data: function() {
                return [];
            }
        }
    };
    spyOn(thisToSet.dataSource, 'data').and.callThrough();

    // act
    scope.dataBound.call(thisToSet);

    // assert
    expect(thisToSet.dataSource.data).toHaveBeenCalledTimes(1);
});

They're pretty similar, but I prefer using call because it should work outside Angular as well.

Mozilla has a pretty sweet explanation of this and how to use it in case you want more detailed information.

Kendo UI Directives

Below is a list of directives found in the Kendo UI module.  I was trying to figure out how to set just the data of a data source on a grid and couldn't find a list.  I came across a question on SO asking for a list, but there was no answer.  I found another question on SO on how to list out the registered items in an Angular module, ran that against the kendo.directives module and voila!

This list is from the 2016.3.1118 release (please note that this is just a list of directives so if you're looking for something else you'll have to modify the code and get it yourself).

The code I used to generate the list:
   1:  angular.module('kendo.directives')['_invokeQueue'].forEach(function(value) {
   2:      if (value[1] === 'directive') {
   3:          console.log(value[2][0]);
   4:      }
   5:  });

The list:
2kendoAlert
2kendoAttribution
2kendoBarcode
2kendoBreadcrumbs
2kendoButton
2kendoCalendar
2kendoChart
2kendoConfirm
2kendoDiagram
2kendoDialog
2kendoDraggable
2kendoEditable
2kendoEditor
2kendoGantt
2kendoGrid
2kendoGroupable
2kendoMap
2kendoMenu
2kendoNavigator
2kendoNotification
2kendoPager
2kendoPopup
2kendoPrompt
2kendoReorderable
2kendoResizable
2kendoScheduler
2kendoSelectable
2kendoSlider
2kendoSortable
2kendoSparkline
2kendoSplitter
2kendoSpreadsheet
2kendoSurface
2kendoTooltip
2kendoTouch
2kendoUpload
2kendoValidator
2kendoWindow
kActionsheetContext
kAlign
kAllDayEventTemplate
kAltRowTemplate
kAltTemplate
kColumnHeaderTemplate
kDataCellTemplate
kDateHeaderTemplate
kDetailTemplate
kEditTemplate
kEmptyTemplate
kendoAutoComplete
kendoColorPalette
kendoColorPicker
kendoColumnMenu
kendoColumnSorter
kendoComboBox
kendoContextMenu
kendoDatePicker
kendoDateTimePicker
kendoDropDownList
kendoDropTarget
kendoDropTargetArea
kendoFileBrowser
kendoFilterCell
kendoFilterMenu
kendoFilterMultiCheck
kendoFlatColorPicker
kendoImageBrowser
kendoLinearGauge
kendoListView
kendoMaskedTextBox
kendoMediaPlayer
kendoMobileActionSheet
kendoMobileApplication
kendoMobileBackButton
kendoMobileButton
kendoMobileButtonGroup
kendoMobileCollapsible
kendoMobileDetailButton
kendoMobileDrawer
kendoMobileFooter
kendoMobileHeader
kendoMobileLayout
kendoMobileListView
kendoMobileLoader
kendoMobileModalView
kendoMobileNavBar
kendoMobilePane
kendoMobilePopOver
kendoMobilePopup
kendoMobileRecurrenceEditor
kendoMobileScroller
kendoMobileScrollView
kendoMobileScrollViewPage
kendoMobileShim
kendoMobileSplitView
kendoMobileSwitch
kendoMobileTabStrip
kendoMobileTimezoneEditor
kendoMobileView
kendoMultiSelect
kendoNumericTextBox
kendoPanelBar
kendoPivotConfigurator
kendoPivotFieldMenu
kendoPivotGrid
kendoProgressBar
kendoQRCode
kendoRadialGauge
kendoRangeSlider
kendoRecurrenceEditor
kendoResponsivePanel
kendoSearchBox
kendoSelectBox
kendoStaticList
kendoStockChart
kendoTabStrip
kendoTimePicker
kendoTimezoneEditor
kendoToolBar
kendoTreeList
kendoTreeMap
kendoTreeView
kendoViewTitle
kendoVirtualList
kendoVirtualScrollable
kendoZoomControl
kErrorTemplate
kEventTemplate
kHeaderTemplate
kIcon
kLinkTemplate
kMajorTimeHeaderTemplate
kMinorTimeHeaderTemplate
kRel
kRowHeaderTemplate
kRowTemplate
kSelectTemplate
kTemplate
kTransition

Thursday, December 1, 2016

Testing a Request in an ApiController

I recently came across a situation where I needed to test an action method on an ApiController to make sure the correct response was returned to the user based on the request.  In this particular case I was testing the ability to upload a file to an API and I needed to return a 400 (Bad Request) error if the content type of the request was not right.  I knew the code was working (I know, it wasn't TDD, but sometimes you have to roll with the punches), but I was having a hard time testing it.  To make things worse I couldn't use shims or fakes because the build server kept blowing up on them.  Fortunately, I came across a couple of really helpful blogs that pointed me in the right direction.

First, Shiju Varghese's blog on writing unit tests for an ApiController.  Next I used William Hallat's blog on testing a file upload to finish things off.

What I ended up with is pretty neat and easy to use, customized to meet my needs.  As usual, I'm posting it here so I don't have to redo the work next time.

The first key to making this work is declaring the controller.  Let's just say that our controller has a single object injected, an ILogger (a fairly common practice).  Instead of just doing this:
var controller = new ExampleController(_moqLogger.Object);

We want to do this:
   1:  var controller = new ExampleController(_moqLogger.Object)
   2:  {
   3:      Request = new HttpRequestMessage
   4:      {
   5:          Content = new ObjectContent(typeof(string), null, new JsonMediaTypeFormatter()),
   6:          Method = HttpMethod.Post
   7:      }
   8:  };

UPDATE: We actually also want to include an HttpConfiguration to prevent another error I was getting later:
   1:  var request = new HttpRequestMessage
   2:  {
   3:      Content = new ObjectContent(typeof(string), null, new JsonMediaTypeFormatter()),
   4:      Method = HttpMethod.Post
   5:  };
   6:  request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
   7:  var controller = new ExampleController(_moqLogger.Object)
   8:  {
   9:      Request = request
   8:  };

This declares that the request passed to the controller will actually be specified to contain content and a method (POST in this case).  Now that we have that, our tests won't fail with the awful (and unhelpful) "Object reference not set to an instance of an object" error you might be seeing.

In this case we've specified that the content will be a string, but we haven't specified any actual content.  But as I said before I needed to test whether the content was a file that had been uploaded, then also take certain actions based on that file.  To do that I actually needed to fake a file upload in the request itself.

A little bit of setup (this happens before each test run not each test):
   1:  [TestFixtureSetUp]
   2:  public void SetUpFixture()
   3:  {
   4:      using (var outFile = new StreamWriter(_testFile))
   5:      {
   6:          outFile.WriteLine("some test data");
   7:      }
   8:  }

The test:
   1:  [Test]
   2:  public void DoSomethingShouldReturnAnOkResult()
   3:  {
   4:      // arrange
   5:      var multipartContent = BuildFormDataContent();
   6:      multipartContent.Add(new StringContent("some value"), "someKey");
   7:   
   8:      var controller = new ExampleController(_moqLogger.Object)
   9:      {
  10:          Request = new HttpRequestMessage
  11:          {
  12:              Content = multipartContent,
  13:              Method = HttpMethod.Post
  14:          }
  15:      };
  16:   
  17:      // act
  18:      var response = controller.DoSomething();
  19:   
  20:      // assert
  21:      Assert.IsInstanceOf<OkResult>(response.Result);
  22:  }

The method called by the test:
   1:  private string _testFile = "test.file";
   2:   
   3:  private MultipartFormDataContent BuildFormDataContent()
   4:  {
   5:      var multipartContent = new MultipartFormDataContent("boundary=---011000010111000001101001");
   6:              
   7:      var fileStream = new FileStream(_testFile, FileMode.Open, FileAccess.Read);
   8:      var streamContent = new StreamContent(fileStream);
   9:      streamContent.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
  10:   
  11:      multipartContent.Add(streamContent, "TheFormDataKeyForTheFile", _testFile);
  12:   
  13:      return multipartContent;
  14:  }

And finally, the controller action method:
   1:  [HttpPost]
   2:  public async Task<IHttpActionResult> DoSomething()
   3:  {
   4:      if (!Request.Content.IsMimeMultipartContent("form-data"))
   5:      {
   6:          _logger.Information(() => "Unsupported media type");
   7:          return BadRequest("Unsupported media type");
   8:      }
   9:   
  10:      try
  11:      {
  12:          var root = @"C:\";
  13:          var provider = new MultipartFormDataStreamProvider(root);
  14:          await Request.Content.ReadAsMultipartAsync(provider);
  15:   
  16:          var someValue = provider.FormData.GetValues("someKey").FirstOrDefault();
  17:   
  18:          foreach (var file in provider.FileData)
  19:          {
  20:              var fileInfo = new FileInfo(file.LocalFileName);
  21:              // do something with the file here that returns a boolean
  22:              if(someOtherMethod()){
  23:                  return Ok();
  24:              }            
  25:   
  26:              return InternalServerError(new Exception("An error was encountered while processing the request"));
  27:          }
  28:   
  29:          return Ok();
  30:      }
  31:      catch (Exception ex)
  32:      {
  33:          return InternalServerError(ex);
  34:      }
  35:  }

This solved my problem and enabled me to test my action method on my controller.