2

Query : Want to access the Main Controller scope object into ui-view states.

Problem Statement :

Here, I am creating one scope object($scope.myVar) based on the response getting from the API that will be applicable across the application. hence, I wrote an API in Main Controller to create this scope object as it is a parent controller and all other states(ui-view) are child.

[1]: https://i.stack.imgur.com/Fr4zK.png Here, I want to access that $scope.myVar in all the states in ui-view.

Tried so far : HTML

<body ng-controller="MainController">
  <div class="className">
    <ui-view></ui-view>
  </div>
</body>

Main Controller

app.controller('MainController', function($scope, $http) {

$http({
  method: 'GET',
  url: '/someUrl'
  }).then(function successCallback(response) {
    $scope.myVar = 'xyz'; // This variable i want to access into the state controller.
  }, function errorCallback(response) {        
  });
});

State controller :

app.controller('StateController', function($scope, $timeout) {

  console.log($scope.myVar); // undefined (Not working)

  $timeout(function() {
    console.log($scope.myVar); // xyz (working)
  }, 500);
});

I want to access $scope.myVar without using $timeout service. What is the correct way to do this ?

Pengyy
  • 37,383
  • 15
  • 83
  • 73
Debug Diva
  • 26,058
  • 13
  • 70
  • 123
  • You can use services if you want to share data between controllers. – Nitesh Rana May 12 '17 at 07:06
  • Or you can use $broadcast – Nitesh Rana May 12 '17 at 07:23
  • @NiteshRana As i already have the data in mainController and other controllers are child so need to use services in that case and `$broadcast` is used if we want to capture an event from parent to child but in my case i just want to pass the scope variable. – Debug Diva May 12 '17 at 07:29
  • Okay, you should use dot(.) notation for your variable and should not put it on $scope. See this https://egghead.io/lessons/angularjs-the-dot – Nitesh Rana May 12 '17 at 11:28

2 Answers2

1

you can use $parent.myVar to access data of parentScope

For your situation(async call), you can add $scope.$watch to watch the parent scope variable.

$scope.$watch("$parent.myVar", function(newValue, oldValue) {
  $scope.data = newValue;
)

Here you want to get data immediately when child state initializing, you can try with resolve.

$stateProvider.state({
  name: 'hello',
  url: '/hello',
  templateUrl: '...',
  resolve: {
    testData: function($http) {
      // invoke your async call here again
    }
  }
})

here are some issues about resolve which may help.

Community
  • 1
  • 1
Pengyy
  • 37,383
  • 15
  • 83
  • 73
  • Not working..getting `Unknown provider: $parentProvider <- $parent <- homeController` error. I already injected `$parent` in the controller. – Debug Diva May 12 '17 at 07:33
  • @RohitJindal you don't have to inject `$parent`. use it directly. – Pengyy May 12 '17 at 07:34
  • I also checked with `$scope.$watch` it return me `undefined` if i am accessing the $scope.data outside of $scope.$watch. – Debug Diva May 12 '17 at 07:38
  • @RohitJindal that is because you are fetching data with asynchorouse call, the data won't comeback immediately. – Pengyy May 12 '17 at 07:39
  • I agree with you but I want the solution for this issue. – Debug Diva May 12 '17 at 07:42
  • @RohitJindal I give you another advice about ui-router's resolve. If this still is what you wish, I would say that's impossible...sorry – Pengyy May 12 '17 at 07:53
  • I have lot of states in my application and i want that variable in every state. then i have to add `resolve` property in each state.. ? – Debug Diva May 12 '17 at 08:07
  • @RohitJindal Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/144035/discussion-between-pengyy-and-rohit-jindal). – Pengyy May 12 '17 at 08:11
  • Correct way to share data would create a service.. also you could use `resolve` function. – Pankaj Parkar May 12 '17 at 10:09
  • @PankajParkar you can see above comments, OP seems don't want to use resolve. Also without resolve here, service won't help because OP want that data immedatiely when substate init. – Pengyy May 12 '17 at 10:11
  • @Pengyy we can directly inject service inside `ui-view`(inner named view) controller, resolve isn't compulsory.. I think OP should use service which will be responsible for data sharing.. – Pankaj Parkar May 12 '17 at 10:17
  • @PankajParkar I know what you means and thanks, mention that OP just want to access asynchronous result without call it again which sounds like making `asynchronous` to `synchronous`. – Pengyy May 12 '17 at 10:30
  • @PankajParkar Thanks for the comment. But still i have one confusion. As data is available in the mainController and it will not refresh if view changes their states. so we can directly use $scope in child from parent then what is the purpose of storing the data in service here ? – Debug Diva May 12 '17 at 10:45
  • I know even data is present there in parent controller. asking it directly using `$parent` convention would make sense for me.. that way will introduce tight coupling inside your application(I never prefer it). Rather put inside a service(single resource responsible for data sharing). Have getter & setter inside a service to avail data in different places – Pankaj Parkar May 12 '17 at 10:49
1

You can use angular $q service

Using promises and $q to handle asynchronous calls

var app = angular.module("MY_APP", []);
//Parent Controller
app.controller("MyCtrl1", [
    '$scope','$q','$timeout', function($scope,$q,$timeout) {

 $scope.async = function(name) {
  var deferred = $q.defer();
  //Async call: Use your ajax call here instead of $timeout
  /*
  $http.get('/someUrl')
       .success(function(data) { 
          $scope.myVar = 'xyz';
          deferred.resolve(data);
       }).error(function(msg, code) {
          deferred.reject(msg);
          $log.error(msg, code);
       });
  */
  $timeout(function() {
    deferred.notify('About to greet ' + name + '.');
     if (name) {
      deferred.resolve('Hello, ' + name + '!');
     } else {
      deferred.reject('Greeting ' + name + ' is not allowed.');
     }
   }, 1000);
  return deferred.promise;
}
}]);
//Child Controller
app.controller("MyCtrl2", [
    '$scope','$q', function($scope,$q) {
 // call parent async method
var promise = $scope.$parent.async('Sai');
promise.then(function(greeting) {
//check your variable here
/*
console.log($scope.$parent.myVar); 
*/
  alert('Success: ' + greeting);
}, function(reason) {
  alert('Failed: ' + reason);
}, function(update) {
  alert('Got notification: ' + update);
});

}]);

Fiddle example

S B
  • 1,363
  • 12
  • 21