javascriptangularjsfunctionangularjs-provider

JavaScript- calling a function defined inside a provider


I have recently taken on the development of web app that has been written in AngularJS. In one of the files, myApp.js, there is a provider that is defined as follows:

.provider('myAppConf', function($routeProvider){
    var constants = {
        'HOMEPAGE': '/alarms',
        ...
    };

    // Setter function for constants
    this.setConstant = function(constant, value){
        constants[constant.toUpperCase()] = value;
    };
    ...
    // Other setter functions
    ...
    // Non- setter/ getter functions:
    this.addElementOverview = function(){
        ...
        var location = 'pages/elementbrowser';
        ...
        return '/' + location;
    }
    function addCreatePageRoute(){
        $routeProvider.when('/pages/create', {
            page: {
                editable: true,
                title: {
                    ...
                },
                layout: {
                    ...
                },
                widgets: [
                    ...
                ]
            }
        });
    }
    // More non- setter/ getter functions
    this.$get = ['$q', '$timeout', 'myAppUI' function($q, $timeout, myAppUI){
        ...
    }];
}).run(function(...){
    ...
});

On most of the pages on the site, there is a 'settings' button, which opens a dialog box that the user can use to change the settings for a given page. I have added a checkbox to that dialog box, which, when checked, I want to use to set the page on which it is checked as the 'home' page, overwriting whichever page was previously the 'home' page. If/ when the checkbox is deselected again, the home page should be set back to its original value (i.e. the /alarms page determined in the constants).

As things currently stand, I have managed to change the home page, so that it is updated to the page selected by the user- when the click 'Home' they are taken to the page on which the checkbox was selected. But as soon as they log out, their chosen home page is forgotten, and when they log in again, the default home page is their home page until they select another one.

I now want to set the user's default home page to whatever they choose as their custom home page, and am trying to use the 'setter function for constants' that is defined in the provider function above.

I have done this by calling:

myAppConf.setConstant(myAppConf.HOMEPAGE, $location.path());

when the 'Confirm' button is pressed on the dialog box (with the 'set as homepage' checkbox checked).

However, when I press the 'Confirm' button, I get a TypeError in my console which says:

TypeError: myAppConf.setConstant is not a function

I don't understand why I'm getting this error... setConstant() is defined as a function with:

this.setConstant = function(constant, value){...};

so why is the console stating that it's not a function? How can I fix this?

Edit

The function where I'm calling myAppConf.setConstant() is defined in Pages/ctrls.js as follows:

angular.module('myApp.pagse')
...
.controller('LayoutCtrl', function($scope, $route, $location, $timeout, Page, myAppConf, NotifyMgr, DialogMgr,myAppUI){
    ...
    $scope.confirm = function(e){
        ...
        if($scope.checkboxModel){
            ...
            myAppConf.setConstant(myAppConf.HOMEPAGE, $location.path());
        }else{
            console.log("homepage not changed");
        }
    };

Solution

  • setConstant is myAppConfProvider method, not myAppConf. If it should be available both in config and run phases, it should be defined on both a provider and an instance:

    .provider('myAppConf', function(){
      ...
      var commonMethods = {
        setConstant: function (constant, value) {
          constants[constant.toUpperCase()] = value;
        },
        ...
      }
    
      Object.assign(this, commonMethods, {
        $get: function () {
          return commonMethods;
        }
      })
    })
    

    A cleaner way to do this is to use constant:

    .constant('myAppConf', {
      _constants: { ... },
      setConstant: function (constant, value) {
        this[constant.toUpperCase()] = value;
      },
      ...
    })
    

    Since getters and setters can be considered antipattern unless they are justified, a KISS alternative is just:

    .constant('myAppConf', {
      'HOMEPAGE': '/alarms',
      ...
    })