BigHeadCreations
BigHeadCreations

Reputation: 1703

Angular function constructor in Controller

In normal JS I can do this:

function Droppable() {
    this.relevant = true;
    this.uuid = generateUUID();
};

var generateUUID = function() {
   return '12345';
}


console.log(new Droppable); // returns Droppable {relevant: true, uuid: "12345"}

But in Angular I have this:

angular.module('myApp').controller('MyCtrl', ['$scope', function($scope) {

    function Droppable() {
        this.relevant = true;
        this.uuid = generateUUID();
    }

    var generateUUID = function() {
        return '12345';
    }

    // initalize droppable areas
    $scope.region1 = [new Droppable];
    $scope.region2 = [new Droppable];
    $scope.region3 = [new Droppable];

}]);

I am trying to make 3 droppable areas all with a UUID.

But when I do this I get 'undefined is not a function' referring to the line this.uuid = generateUUID(); in function Droppable() {...}

Why is that?

Upvotes: 2

Views: 888

Answers (3)

Hadi
Hadi

Reputation: 2905

Giving some quick examples

function Droppable() {
    this.relevant = true;
    this.uuid = generateUUID();
}

// this will throw an error because you are calling generateUUID before it initialize
console.log(new Droppable);

var generateUUID = function() {
   return '12345';
}

// this will give you actuall output what you wanted
console.log(new Droppable);

So when you will call function generateUUID before calling Droppable it will work. Like this -

// initializes
var generateUUID = function() {
    return '12345';
}

// initializes
function Droppable() {
    this.relevant = true;
    this.uuid = generateUUID();
}

// this will work as expected
console.log(new Droppable);

In JavaScript you can define function in two method

var varibaleName = function(){

}

and

function variableName(){

}

There is a significant differences. When you are declaring a function with a variable then before call that function that variable need to register.

if you call like this -

varibaleName();
var varibaleName = function(){

}

this will give you an error.

But if you call like this it will work -

varibaleName();
function varibaleName (){

}

So this should work too -

function Droppable() {
    this.relevant = true;
    this.uuid = generateUUID();
}

// this will work as expected
console.log(new Droppable);


function generateUUID() {
    return '12345';
}

Hope this make sense.

However in angular this will work -

var myApp = angular.module("myApp", []);

myApp.controller("MyCtrl", function($scope){

    function Droppable() {
        this.relevant = true;
        this.uuid = generateUUID();
    }

    var generateUUID = function() {
        return '12345';
    }

    // initalize droppable areas
    $scope.region1 = [new Droppable];
    $scope.region2 = [new Droppable];
    $scope.region3 = [new Droppable];

    console.log( $scope.region1 );
});

But best practice is -

myApp.controller("MyCtrl", function($scope){

    // you can call this before Droppable or after
    $scope.generateUUID = function() {
        return '12345';
    }

    $scope.Droppable = function () {
        this.relevant = true;
        this.uuid = $scope.generateUUID();
    }

    // initalize droppable areas
    $scope.region1 = [new $scope.Droppable];

    console.log( $scope.region1 );
});

Why i am calling those with $scope. prefix, because later you may need to talk between controller to controllers even in directives!

Happy coding and happy prototyping! How this helps you to understand how things are working.

Upvotes: 1

PSL
PSL

Reputation: 123739

Turning my comment to answer. Your issue is due to the variable holding the function expression is being used before it has been assigned, in which case the variable generateUUID is not defined yet.

var generateUUID = function() {
    return '12345';
}

One way to fix it, is to turn it to function declaration so that it is automatically hoisted to the top of the scope.

function generateUUID () {
        return '12345';
 }

or define the variable generateUUID to a function reference before its possible usage.

//Some variable declarations, start of the scope
var generateUUID = function() {
    return '12345';
}

function Droppable() {
    this.relevant = true;
    this.uuid = generateUUID();
}

When you do:-

.... Some Code ....


var generateUUID = function() {
        return '12345';
    }

.... Some Code ...

it is same as:-

var generateUUID;
.... Some Code ....
//Any usage of this till here will cause the error that you are facing, since there is no value assigned to generateUUID yet
generateUUID = function() {
            return '12345';
  }

.... Some Code ...

Some reference:- MDN, SO

and a Plnkr

Note:- This issue should not happen in your example because you are invoking the constructor after it (generateUUID) has been assigned with value, probably a different usecase (which is not present in the question) might be having this issue.

Upvotes: 1

PremiumSoySauce
PremiumSoySauce

Reputation: 46

function Droppable() {
  this.relevant = true;
  this.uuid = generateUUID();
}
var generateUUID = function() {
  return '12345';
}

Okay, this is not a problem about AngularJS but it is more about Javascript. Read up on Javascript variable hoisting. When you declare a function using the var keyword, there are two things happens: You create a variable, and then assign a variable to it. Because of javascript hoisting, variable declaration (var generateUUID) will be hoisted to the top, where the declaration happens later where you wrote it.

var generateUUID;   //undefined
function Droppable() {
  this.relevant = true;
  this.uuid = generateUUID(); //you are invoking undefined here.
}
generateUUID = function() {
  return '12345';
}

the right way to do it would be:

function Droppable() {
  this.relevant = true;
  this.uuid = generateUUID();
}
function GenerateUUID() {
  return '12345';
}

Here, because you use by "function GenerateUUID()", the whole thing get hoisted to the top instead of only just the variable

Upvotes: 1

Related Questions