In part 1 I was able to take an Angular controller written in JavaScript and convert it to a TypeScript file while doing very little to change the code. In this post I am going to explore transitioning that same controller to actually use the features provided in TypeScript. This is how I left off my controller:
The formChanged functionality will be the same across multiple controllers. It will call to the controller's service, but the service will be different for each controller. so I wrote a base class that implements my IControl interface:
Because each controller that uses this base class will need a service related to it, I create a constructor that will force the calling class to setup the service. I don't have a class or interface for those service yet, so I define it as "any" for now.
declare var angular: any;
(function () {
'use strict';
var controller: any = function($scope){
...
}
angular
.module('app')
.controller('controller', controller);
controller.$inject = ["$scope"];
})();
While performing the translation from JavaScript to TypeScript, I would make sure at every step that the functionality I expected still worked, so if anything I did broke the system I would change it back and try again with another approach. Also if something seemed like it worked too easily, I would break it on purpose to make sure I wasn't getting a false result through browser caching a previously working file, just like creating a failing test first in TDD.
The first step I took was to convert the controller into a class in TypeScript. This worked out really easily and helped clean up some issues from earlier. I moved everything from the controller into the constructor of the class, so I was still not gaining much value, but I also didn't have to change much to keep things working. I was also able to pull the $inject block inside the class, which I think makes more sense than in plain JavaScript where the $inject happens outside of the function that is being injected.
The first step I took was to convert the controller into a class in TypeScript. This worked out really easily and helped clean up some issues from earlier. I moved everything from the controller into the constructor of the class, so I was still not gaining much value, but I also didn't have to change much to keep things working. I was also able to pull the $inject block inside the class, which I think makes more sense than in plain JavaScript where the $inject happens outside of the function that is being injected.
declare var angular: any;
class controller{
static $inject = ["$scope"];
constructor($scope){
...
}
}
(function () {
'use strict';
angular
.module('app')
.controller('controller', controller);
})();
The next thing I looked for was how could I pull out pieces of this controller that are used by other controllers in the system and define either a base class or an interface, or possibly both. I decided to start out with a simple id property and a function that would watch the state of the form for this controller. I created the basic interface:
interface IControl{
id: string;
service: any;
formChanged: (isDirty: Boolean) => void;
}
The formChanged functionality will be the same across multiple controllers. It will call to the controller's service, but the service will be different for each controller. so I wrote a base class that implements my IControl interface:
class BaseControlController implements IControl {
id: string;
service: any;
constructor(service: any) {
this.service = service;
}
formChanged(isDirty: Boolean): void {
this.service.setDirtyFlag(isDirty);
}
}
Because each controller that uses this base class will need a service related to it, I create a constructor that will force the calling class to setup the service. I don't have a class or interface for those service yet, so I define it as "any" for now.
Next I have my actual controller extend the base class:
class controller extends BaseControlController{
constructor($scope, service) {
super(service);
}
}
To this point everything is still working just as it was before, and I have actually added a bit more code than the straight JavaScript implementation, but I do have a base class defined that will allow me to reuse code in a way that I was not previously doing. Except that I am not actually calling that function yet.
I ran into some issues trying to call the formChanged function. I want it to happen inside of an angular watch, which gets defined in the constructor like this:
I ran into some issues trying to call the formChanged function. I want it to happen inside of an angular watch, which gets defined in the constructor like this:
$scope.$watch('form.$dirty', function(newValue){
formChanged(newValue);
});
TypeScript didn't like this because formChanged was not defined in the class, it was being defined in the base class. So I tried calling it using 'this.formChanged', same problem. So just as I had to call super in the constructor, I figured I would call 'super.formChanged' and that would work. Unfortunately, now TypeScript complained that super could not be called outside of constructors or members. I was confused by this error as the watch definition was inside the constructor, so it should have been able to access it.
What I was failing to see was that even though the watch was being defined inside of the constructor, the actual call to the base class was happening inside of the anonymous function called when the watcher notices activity. What I had to do was transform that anonymous JavaScript function into an anonymous TypeScript function:
What I was failing to see was that even though the watch was being defined inside of the constructor, the actual call to the base class was happening inside of the anonymous function called when the watcher notices activity. What I had to do was transform that anonymous JavaScript function into an anonymous TypeScript function:
$scope.$watch('form.$dirty', (newValue: Boolean) => {
super.formChanged(newValue);
});
Now it was aware of super, and testing it out confirmed that it was being called at the correct time.
I have actual working TypeScript inside of my Controller and some basic inheritance in place that will allow for reuse across the project. I also have a large portion of my controller untouched and still as pure JavaScript. I would say that I am starting to see the value of converting to TypeScript. Having strongly typed object helps ensure that those objects are doing what they are supposed to do. Inheritance works in a manner I am more accustomed to coming from C# rather than trying to learn JavaScript Inheritance. Which brings up an interesting question, "would it be more productive to learn how to use JavaScript inheritance and make the JavaScript in my project more reusable than converting the project to TypeScript so that I can get that inheritance?"
I don't have an answer for that yet, I will continue to further explore converting my project over to TypeScript and see if I run into any more hurdles or find more reasons to convert to TypeScript.
I have actual working TypeScript inside of my Controller and some basic inheritance in place that will allow for reuse across the project. I also have a large portion of my controller untouched and still as pure JavaScript. I would say that I am starting to see the value of converting to TypeScript. Having strongly typed object helps ensure that those objects are doing what they are supposed to do. Inheritance works in a manner I am more accustomed to coming from C# rather than trying to learn JavaScript Inheritance. Which brings up an interesting question, "would it be more productive to learn how to use JavaScript inheritance and make the JavaScript in my project more reusable than converting the project to TypeScript so that I can get that inheritance?"
I don't have an answer for that yet, I will continue to further explore converting my project over to TypeScript and see if I run into any more hurdles or find more reasons to convert to TypeScript.
Hello , I have been training students on AngularJS for past 6 months, and at times, I have used your blog as reference for the class training and also for my personal project development. It has been so much useful. Thank you, keep writing more:)
ReplyDeleteShashaa
AngularJS training in Chennai
Thank you. I am glad that I have helped.
DeleteAwesome post which i have seen.I read your blog everything is helpful and effective.
ReplyDeleteAngularJS Training in Chennai
AngularJS Course in Chennai
AngularJS Training in Anna Nagar
AngularJS Training in T Nagar
AngularJS Training in OMR
Web Designing Course in chennai
Web Designing training in chennai
Web Designing Training in Velachery
Thanks for sharing this information. This is really useful. Keep doing more.
ReplyDeleteonline internship
online internships
watch internship online
online internship for students
the internship online
online internship with certificate
online internship certificate
python online internship
data science online internship