1

I am learning the basics of AngularJS and I can´t figure out why this Factory returns an undefined value. It´ my first attempt to create and understand factories. I saw many examples on SO and on the internet but I couldn´ find the solution.

I am trying to create an array of strings (colors) on the factory and a button shown in each different view to add one string to the array. But the factory returns undefined so I can´t inject the value to the controllers.

Here is the code.

index.html

<head>
</head>

<body>
    <a href="#/">Home</a>
    <a href="#/seccion1">Seccion 1 </a>
    <div ng-view>

    </div>  
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-route.js"></script>

    <script src="mijs.js"></script>

</body>

JS file (mijs.js) with controllers, the factory and the $routeProvider service

var app=angular.module("myMod",['ngRoute']);

app.config(
    function($routeProvider)
    {
        $routeProvider.when('/',
            {
                controller:'ctrlHome',
                controllerAs:'home',
                templateUrl:'home.html'
            }
        );

        $routeProvider.when('/seccion1',
            {
                controller:'ctrlSeccion1',
                controllerAs:'seccion1',
                templateUrl:'seccion1.html'
            }
        );
    }//end function($routeProvider)
);//end config

app.factory("factColors",function(){
    var arrayColors=['red','green','blue'];
    return arrayColors;
}); //end factory

app.controller('ctrlHome',function(factColors) 
    {
        var home=this;
        home.arrayColors=factColors.arrayColors;
    }

);//end home controller

app.controller('ctrlSeccion1',function(factColors) 
    {
        var seccion1=this;
        seccion1.arrayColors=factColors.arrayColors;
    }
);//end seccion1 controller

Here is the view home.html

<p>home view </p>
<p ng-repeat="color in home.arrayColors">{{color}}</p>

<button ng-click="home.arrayColors.push('orange')">add color</button>

And the view seccion1.html

<p>seccion 1 view </p>
<p ng-repeat="color in seccion1.arrayColors">{{color}}</p>

<button ng-click="seccion1.arrayColors.push('purple')">add color</button>
Kalamarico
  • 5,466
  • 22
  • 53
  • 70

1 Answers1

1

Your factory is returning the array directly. That's fine in and of itself, but you're accessing it as though it's returning an object with an arrayColors property. So either change the factory to this:

app.factory("factColors",function(){
    return {
        arrayColors: ['red','green','blue']
    };
});

Or change the way you interact with it to this:

app.controller('ctrlSeccion1',function(factColors) {
    var seccion1=this;

    seccion1.arrayColors=factColors;
}
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • it works! but, although I tried to understand it, I don´t know why this happens. I mean, why then when I reference something declared in a controller, I must put "vm.Variable" (or whatever the alias from the scope is), and that doesn´t work the same way in a factory? –  Sep 27 '17 at 20:41
  • A factory can produce any type of thing that you want it to. If you want to produce an object with properties on it, then you can (as is done in my first code block). In fact that's probably the most common way to use a factory, because it lets you have multiple things in the factory, each with their own name. So if it's an object, you'll interact with it as an object, just like you do with `vm.Variable`. – Nicholas Tower Sep 28 '17 at 00:24
  • Your code on the other hand had the factory producing array, not an object. Since it was an array, it had no .arrayColors property; it just had the 0, 1, 2, etc indices. This is a legal thing to do in a factory, but it's somewhat uncommon. And if you want to do it, you'll then need to interact with it as an array. – Nicholas Tower Sep 28 '17 at 00:27
  • I mean, if I declare inside a controller for example an arrayColors, then I had to access it through "vm.arrayColors" (or whatever the scope is called) inside the HTML tags with an ng-controller directive injected. Why is different with a factory? the arrayColors inside the controller is neither an object, other? –  Sep 28 '17 at 02:45
  • A controller is written in javascript, and a template is written in html (mostly). There isn't a natural way for these two files to share data, so angular had to invent one. They invented a special `$scope` variable that you can save things to, and then angular does work behind the scenes to make those values available to both the controller and the template. Or if you're using controller-as syntax, you save things to the controller's `this` (which often gets renamed to `vm`). [...] – Nicholas Tower Sep 28 '17 at 03:21
  • [...] But this kind of workaround is only needed to bridge the gap between controller and template. For everything else, you can use more normal javascript. A controller is written in javascript, and so is a factory. So they can hand objects between themselves with no need for invented conventions. Or they can hand arrays between themselves. Whatever you need. – Nicholas Tower Sep 28 '17 at 03:22
  • I have read in documentation, scope is actually an object. Maybe that´s why we must use the "dot" access operator to use something declared inside a controller? –  Sep 28 '17 at 14:23