17

How to define my controller using TypeScript. As right now it's in angular js but i want to change this for type script.So that the data can be retrieved quickly.

function CustomerCtrl($scope, $http, $templateCache){

    $scope.search = function(search)
    {
        debugger;
        var Search = {
            AccountId: search.AccountId,
            checkActiveOnly: search.checkActiveOnly,
            checkParentsOnly: search.checkParentsOnly,
            listCustomerType: search.listCustomerType
        };
        $scope.customer = [];
        $scope.ticket = [];
        $scope.services = [];
        $http.put('<%=ResolveUrl("API/Search/PutDoSearch")%>', Search).
            success(function(data, status, headers, config) {
                debugger;
                $scope.cust_File = data[0].customers;
                $scope.ticket_file = data[0].tickets;
                $scope.service_file = data[0].services;
            }).
            error(function(data, status)
            {
                console.log("Request Failed");
            });
    }
}
Shian JA
  • 848
  • 4
  • 15
  • 52
  • 2
    Are you open to using ControllerAs syntax? which is now the suggested implementation – Brocco May 27 '15 at 12:18
  • Actually,I am have created an angular app which is having a aspx page from which i m taking a text box data and than fetching that id into my angulart js code and than sending that parameters to my web api and than again when the data is returned through API it will be get through my Angular Script and than it will be shown it to my grid. – Shian JA May 27 '15 at 12:21
  • All our base are belong to us! – Bart Dec 24 '15 at 12:32
  • @Bart - All your base are belong to us! Can I come in to the outside now? – 9ers Rule Mar 29 '16 at 20:11

4 Answers4

20

There are 2 different ways to tackle this:

  • still using $scope
  • using controllerAs (recommended)

using $scope

class CustomCtrl{
    static $inject = ['$scope', '$http', '$templateCache'];
    constructor (
            private $scope,
            private $http,
            private $templateCache
    ){
        $scope.search = this.search;
    }

    private search (search) {
        debugger;
        var Search = {
            AccountId: search.AccountId,
            checkActiveOnly: search.checkActiveOnly,
            checkParentsOnly: search.checkParentsOnly,
            listCustomerType: search.listCustomerType
        };
        this.$scope.customer = [];
        this.$scope.ticket = [];
        this.$scope.services = [];
        this.$http.put('<%=ResolveUrl("API/Search/PutDoSearch")%>', Search).
                success((data, status, headers, config) => {
                    debugger;
                    this.$scope.cust_File = data[0].customers;
                    this.$scope.ticket_file = data[0].tickets;
                    this.$scope.service_file = data[0].services;
                }).
                error((data, status) => {
                    console.log("Request Failed");
                });

    }
}

Using controllerAs

class CustomCtrl{
    public customer;
    public ticket;
    public services;
    public cust_File;
    public ticket_file;
    public service_file;

    static $inject = ['$scope', '$http', '$templateCache'];
    constructor (
            private $http,
            private $templateCache
    ){}

    private search (search) {
        debugger;
        var Search = {
            AccountId: search.AccountId,
            checkActiveOnly: search.checkActiveOnly,
            checkParentsOnly: search.checkParentsOnly,
            listCustomerType: search.listCustomerType
        };
        this.customer = [];
        this.ticket = [];
        this.services = [];
        this.$http.put('<%=ResolveUrl("API/Search/PutDoSearch")%>', Search).
                success((data, status, headers, config) => {
                    debugger;
                    this.cust_File = data[0].customers;
                    this.ticket_file = data[0].tickets;
                    this.service_file = data[0].services;
                }).
                error((data, status) => {
                    console.log("Request Failed");
                });

    }
}

If you switch from $scope to controllerAs your view would change from:

<div ng-controller="CustomCtrl">
  <span>{{customer}}</span>
</div>

to:

<div ng-controller="CustomCtrl as custom">
  <span>{{custom.customer}}</span>
</div>

where custom is a representation of the controller so you are explicitly telling what you are binding to in your markup.

Note $inject is a way to provide angular with information about what dependencies to inject into your controller at run time even when the code has been minified (strings don't get minified)

Brocco
  • 62,737
  • 12
  • 70
  • 76
  • 1
    Will u please tell me what is the difference if i don't use $scope as it is the object of Angular Js? Means is dre ny impact on perfromnce.Or do i need to make changes in my aspx as well – Shian JA May 27 '15 at 12:24
  • 1
    I updated my answer to have both examples and also an example of how your view/markup would need to change to reflect your change in the controller – Brocco May 27 '15 at 12:29
  • thanks a very good answer...for for your faster response too!! ;) – Shian JA May 27 '15 at 12:33
  • 2
    @RadimKöhler I took your piece of `$inject` and added that in to my answer as well – Brocco May 27 '15 at 12:33
  • @Brocco having one more question is there any need to change my route as well ? – Shian JA May 27 '15 at 12:52
  • 1
    @Mico if you are defining the controller in your route and not inline (via `ng-controller`) then yes. In your route definition where you specify `controller: 'CustomCtrl'` you can add: `controllerAs: 'custom'` – Brocco May 27 '15 at 12:55
  • @Brocco i m trying to use inline. – Shian JA May 27 '15 at 12:56
  • 1
    @Mico in that case no, just the `ng-controller` attribute to have `as custom` – Brocco May 27 '15 at 12:59
  • @Mico You asked if you need to change the route (when defining it) and I said only if that's where you're specifying the controller. If so u change it there but if if you're defining inline (like you said you were) then you need to specify `as custom` inside the ng-controller attribute. – Brocco May 27 '15 at 13:20
  • @Brocco what to do with ng-repeter as i m using it for my grid? – Shian JA May 27 '15 at 17:46
  • 1
    @Mico `ng-repeat="customer in custom.customers"` – Brocco May 27 '15 at 17:48
  • @Brocco still the problem remain grid is not filled As i m trying to fill my grid previously like ticket in ticket_file After your conversion i made changes to ticket in in custom.customers As ticket_file, Service_file ,cust_file are my array where i m getting data and accessing their data by creating their object in my grid – Shian JA May 28 '15 at 08:07
  • I'm using the `$scope` method, but in `Search` function, `this` refers to the `$scope`, which means `this.$scope` is undefined. Am I missing anything ? – Redplane Aug 24 '18 at 04:13
15

I decided to add another answer, with working example. It is very simplified version, but should show all the basic how to us TypeScript and angularJS.

There is a working plunker

This would be our data.json playing role of a server.

{
  "a": "Customer AAA",
  "b": "Customer BBB",
  "c": "Customer DDD",
  "d": "Customer DDD",
  "Default": "Not found"
}

This would be our starting module MainApp.js:

var app = angular.module('MainApp', [
  'CustomerSearch'
  ]);

angular.module('CustomerSearch',[])

So later we can use module CustomerSearch. This would be our index.html

<!DOCTYPE html>
<html ng-app="MainApp" ng-strict-di>

  <head>
    <title>my app</title>
    <script data-require="angular.js@*"
            src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.0-rc.1/angular.js"
            ></script>

    <script src="MainApp.js"></script>
    <script src="CustomerSearch.dirc.js"></script>
  </head> 

  <body>    
    <customer-search></customer-search> // our directive
  </body> 

</html>

Now, we would see the declaration of 1) directive, 2) scope, 3) controller. This all could be in one file (check it here). Let's observe all three parts of that file CustomerSearch.dirc.js (it is CustomerSearch.dirc.ts .. but for plunker I complied that)

1) get reference to module 'CustomerSearch' declared above and declare directive

/// <reference path="../scripts/angularjs/angular.d.ts" />
module CustomerSearch
{
    var app = angular.module('CustomerSearch');

    export class CustomerSearchDirective implements ng.IDirective
    {
        public restrict: string = "E";
        public replace: boolean = true;
        public template: string = "<div>" +
            "<input ng-model=\"SearchedValue\" />" +
            "<button ng-click=\"Ctrl.Search()\" >Search</button>" +
            "<p> for searched value <b>{{SearchedValue}}</b> " +
            " we found: <i>{{FoundResult}}</i></p>" +
            "</div>";
        public controller: string = 'CustomerSearchCtrl';
        public controllerAs: string = 'Ctrl';
        public scope = {};
    }

    app.directive("customerSearch", [() => new CustomerSearch.CustomerSearchDirective()]);

The directive was declared in TypeScript and immediately injected into the our module

Now, we declare a scope to be used as a strongly typed object in Controller:

    export interface ICustomerSearchScope  extends ng.IScope
    {
        SearchedValue: string;
        FoundResult: string;
        Ctrl: CustomerSearchCtrl;
    }

And now we can declare simple controller

    export class CustomerSearchCtrl
    {
        static $inject = ["$scope", "$http"];
        constructor(protected $scope: CustomerSearch.ICustomerSearchScope,
            protected $http: ng.IHttpService)
        {
            // todo
        }
        public Search(): void
        {
            this.$http
                .get("data.json")
                .then((response: ng.IHttpPromiseCallbackArg<any>) =>
                {
                    var data = response.data;
                    this.$scope.FoundResult = data[this.$scope.SearchedValue]
                        || data["Default"];
                });
        }
    }
    app.controller('CustomerSearchCtrl',  CustomerSearch.CustomerSearchCtrl);
}

Observe that all in action here

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • I followed your second question and tried to provide more details about what is happening in this code http://stackoverflow.com/a/30507056/1679310, hope it helps a bit – Radim Köhler May 28 '15 at 12:49
  • Why are you layering your own modules on top of Angular? I'm not convinced this extra layer of complexity and additional global state is necessary. What benefit do you actually get from this? – yangmillstheory Jan 27 '16 at 05:27
  • @yangmillstheory Seems like misreading the module keyword. Take it as a namespace and it should give you the answer. There is NO special module at all. Hope that helps a bit.. – Radim Köhler Jan 27 '16 at 05:57
  • @RadimKöhler ng-modules already provide namespacing: https://www.safaribooksonline.com/blog/2014/03/27/13-step-guide-angularjs-modularization/ – yangmillstheory Jan 27 '16 at 16:02
  • @yangmillstheory that is a module of angular. What I used is module/namespace for the class. That is different topic. With angular 2 that is not needed, because we explicitly loads module. But with angular JS we can load all the code into the page, and then namespace could help... just could and do not introduce anything else then namespace.. – Radim Köhler Jan 27 '16 at 16:03
  • @RadimKöhler Again, you don't need the extra namespace because you can do it all in angular. Why does your application need to namespace (and actually, expose) Angular entities outside of Angular? :) – yangmillstheory Jan 27 '16 at 16:10
6

There would be more to improve (e.g. do not $scope.search, but Ctrl.search), but one of ways could be:

Firstly we create our module MyModule and define a new $scope - the ICustomer Scope

module MyModule
{
    export interface ICustomerScope extends ng.IScope
    {
        search: (search: any) => void;
        customer: any[];
        ticket: any[];
        services: any[];

        cust_File: any[];
        ticket_file: any[];
        service_file: any[];
    }

Next is the controller, which would be injected into angular module later. it does use the ICustomerScope defined above

    export class CustomerCtrl
    {
        static $inject = ['$scope', '$http', '$templateCache'];

        constructor(protected $scope: ICustomerScope,
            protected $http: ng.IHttpService,
            protected $templateCache: ng.ITemplateCacheService)
        {
            $scope.search = this.search;
        }
        public search = (search: any) => 
        {
            debugger;
            var Search = {
                AccountId: search.AccountId,
                checkActiveOnly: search.checkActiveOnly,
                checkParentsOnly: search.checkParentsOnly,
                listCustomerType: search.listCustomerType
            };

            this.$scope.customer = [];
            this.$scope.ticket = [];
            this.$scope.services = [];

            var url = "someUrl"; // '<%=ResolveUrl("API/Search/PutDoSearch")%>'
            this.$http.put(url, Search).
                success((data, status, headers, config) =>
                {
                    debugger;
                    this.$scope.cust_File = data[0].customers;
                    this.$scope.ticket_file = data[0].tickets;
                    this.$scope.service_file = data[0].services;
                }).
                error((data, status) =>
                {
                    console.log("Request Failed");
                });
        }
    }

Now we continue - we get reference to module, and register controller: CustomerCtrl.

    var app = angular.module("MyControllerModule");    

    app.controller("CustomerCtrl", MyModule.CustomerCtrl);
}

Now our controller can be used, will do the same as original. But could be used and declare public actions instead of $scope.methods()

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Kudos for adding `$inject` to the class to allow for minification – Brocco May 27 '15 at 12:30
  • @Radim Kohler getting error of uncaught error: amgular is not defined – Shian JA Jun 02 '15 at 08:14
  • Why are you layering your own modules on top of Angular? I'm not convinced this extra layer of complexity and additional global state is necessary. What benefit do you actually get from this? – yangmillstheory Jan 27 '16 at 05:26
  • @yangmillstheory Seems like misreading the module keyword. Take it as a namespace and it should give you the answer. There is NO special module at all. Hope that helps a bit... – Radim Köhler Jan 27 '16 at 05:43
0

Now we will see a basic sample in which we have to create a module and a controller with one method. To start with Typescript we need the following files need to be added in our project. Don't consider the reference path , just find the file name from the list.

<script type="text/javascript" src="scripts/angular.js"></script>
<script type="text/javascript" src="scripts/angular-route.js"></script>
<script type="text/javascript" src="scripts/jquery-1.9.1.js"></script>
<script type="text/javascript" src="scripts/bootstrap.js"></script>

Install the Typescript from the following link if not present in visual studio https://www.microsoft.com/en-us/download/details.aspx?id=48593

Once finish the download the above typing file , add that in your project.

/// <reference path="../scripts/typings/angularjs/angular.d.ts" />
/// <reference path="../scripts/typings/angularjs/angular-route.d.ts" />

Now create a typescript file app.ts and add the above reference in the first two line to get the intellisense while coding.

Refer below link for more detail information

https://angular2js.blogspot.in/2016/06/create-sample-application-in-angular-js.html

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Rajesh G
  • 141
  • 1
  • 3