67

I am an AngularJS starter. I am trying to send data from :

  • Page A : Van Listing page

    to

  • Page B: Van Update page.

When user click the update link for a van, I am invoking a controller and retrieving the van details in the controller. But, I cannot assign the van details to the Page B ( Van Update Page) using the same controller... Error "Cannot set property 'vanNumber' of undefined"

*** Page A: Van List ****

<form name="listVanForm" >
   <table>
   <tr> <td ng-controller="VanUpdateCtrl"><a href="#/van-update" ng-click="prePopulateForm(row.members.vanNumber.value )" class="btn btn-small btn-primary">update</a></td> </tr>
   </table>
</form>

*** Page B: Van Update ****

  <div class="container">
        <h2>Edit Van </h2>
    
        <form name="updateVanForm" novalidate="novalidate" class="form-horizontal" ng-submit="updateCard(formData)">
            <div class="control-group">
                <label class="control-label" >Van Number:</label>
    
                <div class="controls">
                    <input type="text" id="vanNumber" ng-model="formData.vanNumber" placeholder=""/>
                </div>
            </div>
        </form>
     </div>

*** VanUpdateCtrl **

   app.controller('VanUpdateCtrl', ['$scope', 'VanUpdateFactory', '$location',
                                      function ($scope, VanUpdateFactory, $location) {
    
        //callback for ng-init 'populateDD':    
        $scope.prePopulateForm = function (cardNoParam m) {
            
            alert('cardNo = '+cardNoParam);
            
            $scope.formData.cardNumber=cardNoParam;}
    }
    
So, $scope.formData.cardNumber OR $scope.formData in the destination page is not recognised.
Community
  • 1
  • 1
Mega
  • 1,304
  • 5
  • 22
  • 37
  • How many controllers you got on the page? Maybe I'm understanding wrong your scenario, could you post all the involved controllers. – Wawy Mar 14 '14 at 16:22
  • So I'm guessing the route #/van-update has VanUpdateCtrl associated to it in the $routeProvider, right? – Wawy Mar 14 '14 at 16:41
  • 3
    Just so you know every time a controller gets referenced, either via ng-controller or by associating it to a route, it's a new instance of that controller. You can't share the controller in terms of using the same $scope between pages. – Wawy Mar 14 '14 at 16:44
  • Yes and that works fine. Problem is when the Van Update screen is displayed first time, I want to prepopulate it with details from the van listing using the same controller. I can handle the form submission successful after the users has done the changes. Its just prepopulating the form that is an issue. – Mega Mar 14 '14 at 16:44
  • Does, that mean I have to use 2 controllers and one service.Set the van details in a service using one controller and retrieve in the second controller. May using the ng-init function on the update details page. – Mega Mar 14 '14 at 16:53
  • Most likely, also you shouldn't use ng-init lightly it's only advisable to use it in very niche cases (more info in http://docs.angularjs.org/api/ng/directive/ngInit). – Wawy Mar 14 '14 at 17:02
  • After I browse on here, I found this link for my question : http://stackoverflow.com/questions/25901096/passing-data-between-pages-in-angularjs-page-refresh – Phyoe2004 Apr 09 '15 at 03:34

4 Answers4

126

You need to create a service to be able to share data between controllers.

app.factory('myService', function() {
 var savedData = {}
 function set(data) {
   savedData = data;
 }
 function get() {
  return savedData;
 }

 return {
  set: set,
  get: get
 }

});

In your controller A:

myService.set(yourSharedData);

In your controller B:

$scope.desiredLocation = myService.get();

Remember to inject myService in the controllers by passing it as a parameter.

Wawy
  • 6,259
  • 2
  • 23
  • 23
  • Thanks for the responses, but when the user clicks on a van link in the van listing page, I am successfully retrieving the details in the VanUpdateCtrl control. I just need the same VanUpdateCtrl to pre-populate Van Update screen with the details passed to the controller. FYI, after updating the details, its the same VanUpdateCtrl which processing the submission to the server for database persistance. Do I really need 2 services???? – Mega Mar 14 '14 at 16:08
  • There are 2 pages. There is one controller. Each item in the van listing page has a updatevan contoller, which it passed the van details to. I want to populate the van details maintenance screen using the parameter from the van listing screen, using the same controller. – Mega Mar 14 '14 at 16:24
  • in myService.get() I'm getting [Object object] but in my CoontrollerA after myService.set I put an alert to myService.get() and returns what I expect. Only in ControllerB myService.get() return [Object object] – Lucas_Santos Jul 03 '14 at 14:31
  • 13
    Didn't work for me. On the next page, the service seems to be re-created and get() returns empty. – hadaytullah Nov 18 '14 at 16:26
  • 2
    @AlexisGamarra if you read the comments, you will understand that you can't have the same controller in two different pages, each controller is a new instance. – Wawy Jan 29 '15 at 10:46
  • 3
    It works great. But if I refresh the second page by pressing ctrl + f5, the services resets and the page becomes empty due to this. How do you cache the last `set` data so the last data is not lost when the second page with Controller B is refreshed? – Neel Jun 16 '15 at 18:23
  • 3
    @blackops_programmer you could use $cookies or localStorage. – Wawy Jun 16 '15 at 18:24
  • @Wawy, service will retain the data on CTRL + F5? – cracker Jun 07 '16 at 13:21
  • @cracker No, it's stored on memory only. – Wawy Jun 07 '16 at 13:29
  • @Wawy, any idea to maintain that within controller with CTRL + F5? – cracker Jun 07 '16 at 13:50
  • 7
    Yes, use sessionStorage.setItem('key', 'value'); in your service to store it and sessionStorage.getItem('key') to retrieve it. – Wawy Jun 07 '16 at 18:23
  • Nice way to share data between 2 controllers. Thanks – Misha Beskin Jan 18 '17 at 08:01
  • This is "ok" the issue is obviously going to be with page refresh. Especially when developing Ionic or Nodemon or live refresh ... It essentially is a development cycle nightmare. localStorage is therefore my preference – Tom Stickel Jun 04 '17 at 07:45
  • 1
    Using localStorage (or ipCookie, or whatever) inside of a service has been excellent for us. The service provides a simple and convenient API for setting/getting data, and it stores the data in cookies automatically to be robust against page refreshes. I highly recommend this approach. – iamtheddrman Jun 09 '17 at 13:23
  • I'm going to try that approach now as using the approach directly of setting object back and forth didn't work when I open the second page in a new browser window – Naomi Sep 25 '18 at 19:14
  • Wawy, can you please elaborate on your approach? – Naomi Sep 25 '18 at 19:16
8

What you should do is create a service to share data between controllers.

Nice tutorial https://www.youtube.com/watch?v=HXpHV5gWgyk

dopplesoldner
  • 8,891
  • 12
  • 44
  • 55
  • I'd like to clarify - would this work if I open the second page in a new tab? I'm going to re-try, may be in my original tests I didn't implement it correctly as it didn't work for me – Naomi Sep 25 '18 at 17:29
8

If you only need to share data between views/scopes/controllers, the easiest way is to store it in $rootScope. However, if you need a shared function, it is better to define a service to do that.

Yang Zhang
  • 4,540
  • 4
  • 37
  • 34
  • 3
    @YangZang. Thanks for sharing this option. To emphasize. You *can* store data to the $rootScope, then retrieve it from another view. However, as with any quick solution that uses the root/global scope, there's almost always a better solution. The **Angular** solution to this problem would be to pass your data in via a shared service. – Alex Johnson Jan 07 '16 at 18:10
  • depending on the data. This could be terrible if you setting var, it would cause digest to go over rootScope – Tatarin Sep 18 '16 at 19:46
  • Using $rootScope to share data between pages is a terrible idea. Yes, it's the easiest way to do it, but it's also the way that will ruin you the most in the future. It's global data, which can come back to bite you when that data starts getting accidentally mutated by a third page that doesn't know that variable is already defined. It pollutes $rootScope, making digest cycles slower. There are so many reasons to never use $rootScope for sharing data, just like there are so many reasons to never use global variables in traditional programming languages. – iamtheddrman Jun 09 '17 at 13:21
  • @iamtheddrman great point about polluting the rootScope. I 100% agree with you, but do you have any references for how this would cause digest cycles to become slower? – losmescaleros Sep 28 '17 at 17:50
  • Sure: https://www.airpair.com/angularjs/posts/angularjs-performance-large-applications#5-1-scopes-and-the-digest-cycle https://medium.com/developers-writing/tips-and-practices-to-optimize-your-angularjs-app-8118550ff808 Some of the performance loss also comes from the likelihood of watchers triggering other watchers in a digest cycle, making it take longer to settle back down when an outside force acts on it. Smaller $rootScope and proper use of services and controllers alleviates this issue, yielding a MUCH faster application. – iamtheddrman Oct 05 '17 at 18:47
-1
app.factory('persistObject', function () {

        var persistObject = [];

        function set(objectName, data) {
            persistObject[objectName] = data;
        }
        function get(objectName) {
            return persistObject[objectName];
        }

        return {
            set: set,
            get: get
        }
    });

Fill it with data like this

persistObject.set('objectName', data); 

Get the object data like this

persistObject.get('objectName');