1

Scoping issues here, I have a page that includes an ng-switch:

<div ng-switch on="pagename()">
   <div ng-switch-when="plans">
      <div ng-include="'/assets/angular/plans/existingplans.html'"></div>
   </div>
   <div ng-switch-when="new">
      <div ng-include="'/assets/angular/plans/newplans.html'"></div>
   </div>
   <div ng-switch-when="credits">
      <div ng-include="'/assets/angular/plans/creditspanel.html'"></div>
   </div>
   <div ng-switch-when="wizard">
      <div ng-include="'/assets/angular/plans/wizard.html'"></div>
   </div>
</div>

As you can see I switch on a method in the controller, this method is bound to a scope variable that has a RESTful data source attached:

$scope.pagename = function() {
  var loc = $location.path().split("/").pop();

  if (loc == "plans" && $scope.plansinfo.data.length < 1) {
    return "wizard";
  } else if (loc == "plans" && $scope.plansinfo.data.length >= 1) {
    return "plans";
  } else if (loc == "new") {
    return "new";
  } else if (loc == "wizard") {
    return "wizard";
  } else {
    // alert(loc)
    console.log(loc);
    console.log(typeof $scope.plansinfo.data);

    return "credits";
  }
};

The basic idea being it drives the user to the correct page. The problem being whichever page you land on gets the $scope.plansinfo datasource object attached to it, but then when you traverse pages the other pages have that object undefined.

So in a nutshell, what am I doing wrong in my controller so that the object is being created in the nested scope, not the top level scope?

Thanks

Tom

==== EDIT ====

In an attempt to clean things up I followed the suggestion below to move the code to a service but now all I get is:

TypeError: string is not a function

Here's my attempt:

 .factory('PlansData', function() {
    var data = {};
    data.plansinfo = {};

   return {
        updateinfo: function(newdata) {
            data.plansinfo = newdata;
        },
        pagename: function (location) {
                return 'credits';
        },
        plansinfo: data
    }
})

controller:

$scope.pagename = PlansData.pagename($location);

So it should just return the string, but instead I get the above error. What am I missing?

Thanks

Tom

Dan
  • 59,490
  • 13
  • 101
  • 110
magicaltrout
  • 494
  • 3
  • 14
  • Try setting `$scope.plansinfo` on the `$rootScope`. This should allow you to access it no matter what child scope you are currently in. – Jonathan Palumbo May 22 '13 at 15:44
  • at which location you are setting $scope.plansinfo – Ajay Beniwal May 22 '13 at 16:09
  • Hi Ajay, Jonathan, The rootscope idea works great, although i'm wondering how "best practice" it is. I set the plansinfo variable in the PlansCtrl controller they all share, I did try using a nested Controller earlier, but didn't seem to get anywhere. – magicaltrout May 22 '13 at 16:10

2 Answers2

0

This would be a good time to use services to manage your model data rather than a controller. You may have already used a service to manage your RESTful API so you could possibly include the pagename function there. If not, here is an example of creating a new service to manage the data:

app.service('locService', function (){
    this.pagename = function () {
        // switch function here
    };
});

Then you can inject that service into the controller that needs the info:

app.controller('myController', function (locService){
    $scope.pagename = locService.pagename;
});
Dan
  • 59,490
  • 13
  • 101
  • 110
  • Hi sh0ber, your comment is correct but when i move the function into my factory all I get told is TypeError: string is not a function Edited the post to show what I've attempted – magicaltrout May 23 '13 at 22:23
  • Hi, I'm thinking that may be the result of some other error in your app. [Here is a fiddle](http://jsfiddle.net/sh0ber/BABsK/) showing the controller working with the service. – Dan May 23 '13 at 22:50
  • Actually, it looks like the problem is you are passing the `$location` service where a string is expected. – Dan May 23 '13 at 22:51
  • Its clearly my lack of understanding of javascript: $scope.pagename = PlansData.pagename works but $scope.pagename = PlansData.pagename($location) doesn't but i passed it into the service directly anyway so its a moot point, thanks a lot for the pointers – magicaltrout May 23 '13 at 22:52
  • Gladly. If it helps, `$scope.pagename = PlansData.pagename` just means something like: "create a property (technically a method, i.e. function) on `$scope` called `pagename` and make it point to the method `PlansData.pagename`" – Dan May 23 '13 at 22:55
0

What am I doing wrong in my controller so that the object is being created in the nested scope, not the top level scope?

If you are using a primitive in your PlansCtrl, or you are reassigning the object, it won't work:

var someObj = { hello: 'there' };

function MyCtrl($scope) {
    $scope.plansinfo = {}; // object, okay
    console.log($scope);
}
function MySubCtrl($scope) {
    $scope.plansinfo = someObj; // oops, reassigned the object
    console.log($scope);
}

What happens above is that controller MySubCtrl will get a local property named plansinfo that hides/shadows the MyCtrl property of the same name. This is the way JavaScript works.

Assigning to an object property in the child controllers should work:

var someObj = { hello: 'there' };

function MyCtrl($scope) {
    $scope.plansinfo = {};
    console.log($scope);
}
function MySubCtrl($scope) {
    $scope.plansinfo.obj = someObj;
    console.log($scope);
}

fiddle

What happens above is that controller MySubCtrl will look and not find object property plansinfo.obj defined on its $scope, so then it uses prototypal inheritance and finds the object on its parent, so it gets set there.

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • Hi Mark, Thanks for trying to explain this to me, I've been through a few documents about the inheritance and object vs primitive thing, and I've been trying to understand it, I thought in creating $scope.plansinfo and then assigning my data to $scope.plansinfo.data this was creating the object? – magicaltrout May 22 '13 at 18:15
  • @magicaltrout, if you have `$scope.plansinfo = {};` in your PlansCtrl, and `$scope.plansinfo.data = someObj;` in a scope that prototypically inherits (eventually) from PlansCtrl, it should work. If it doesn't, maybe you could try setting up a fiddle or plunker. – Mark Rajcok May 22 '13 at 18:34