Share Data Between Angularjs Controllers

Share data between AngularJS controllers

A simple solution is to have your factory return an object and let your controllers work with a reference to the same object:

JS:

// declare the app with no dependencies
var myApp = angular.module('myApp', []);

// Create the factory that share the Fact
myApp.factory('Fact', function(){
return { Field: '' };
});

// Two controllers sharing an object that has a string in it
myApp.controller('FirstCtrl', function( $scope, Fact ){
$scope.Alpha = Fact;
});

myApp.controller('SecondCtrl', function( $scope, Fact ){
$scope.Beta = Fact;
});

HTML:

<div ng-controller="FirstCtrl">
<input type="text" ng-model="Alpha.Field">
First {{Alpha.Field}}
</div>

<div ng-controller="SecondCtrl">
<input type="text" ng-model="Beta.Field">
Second {{Beta.Field}}
</div>

Demo: http://jsfiddle.net/HEdJF/

When applications get larger, more complex and harder to test you might not want to expose the entire object from the factory this way, but instead give limited access for example via getters and setters:

myApp.factory('Data', function () {

var data = {
FirstName: ''
};

return {
getFirstName: function () {
return data.FirstName;
},
setFirstName: function (firstName) {
data.FirstName = firstName;
}
};
});

With this approach it is up to the consuming controllers to update the factory with new values, and to watch for changes to get them:

myApp.controller('FirstCtrl', function ($scope, Data) {

$scope.firstName = '';

$scope.$watch('firstName', function (newValue, oldValue) {
if (newValue !== oldValue) Data.setFirstName(newValue);
});
});

myApp.controller('SecondCtrl', function ($scope, Data) {

$scope.$watch(function () { return Data.getFirstName(); }, function (newValue, oldValue) {
if (newValue !== oldValue) $scope.firstName = newValue;
});
});

HTML:

<div ng-controller="FirstCtrl">
<input type="text" ng-model="firstName">
<br>Input is : <strong>{{firstName}}</strong>
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{firstName}}
</div>

Demo: http://jsfiddle.net/27mk1n1o/

AngularJS - Correct way to share data between two controllers

Sharing data between controllers has always been a prominent requirement. You have a couple of options out there :

  1. Factory
  2. Services

You can refer to this answer, for more details upon the differences.

Using services is definitely the better option, since you won't be polluting the root scope with extra variables [That are destined to grow in numbers as your have already mentioned].


A possible way to store your data in services, and access them in controllers and HTML effortlessly can be described as :

  1. Create a service, that will hold all the model variables.

    angular.service("dataService", function() {

    this.value1 = "";
    this.value2 = "";
    });
  2. reference that service in your controllers, saving their reference in the scope.

    angular.controller("myCntrl1", function($scope, dataService) {
    $scope.dataService = dataService;
    });

    angular.controller("myCntrl2", function($scope, dataService) {
    $scope.dataService = dataService;
    });
  3. Now in your html, you refer all your modal variables using the service reference :

        // Controller 1 view
    <div ng-controller="myCntrl1">
    <input type="text" ng-model="dataService.value1" />
    </div>

    // Controller 2 view
    <div ng-controller="myCntrl2">
    The value entered by user is {{dataService.value1}}
    </div>

Passing data between controllers in Angular JS?

From the description, seems as though you should be using a service. Check out http://egghead.io/lessons/angularjs-sharing-data-between-controllers and AngularJS Service Passing Data Between Controllers to see some examples.

You could define your product service (as a factory) as such:

app.factory('productService', function() {
var productList = [];

var addProduct = function(newObj) {
productList.push(newObj);
};

var getProducts = function(){
return productList;
};

return {
addProduct: addProduct,
getProducts: getProducts
};

});

Dependency inject the service into both controllers.

In your ProductController, define some action that adds the selected object to the array:

app.controller('ProductController', function($scope, productService) {
$scope.callToAddToProductList = function(currObj){
productService.addProduct(currObj);
};
});

In your CartController, get the products from the service:

app.controller('CartController', function($scope, productService) {
$scope.products = productService.getProducts();
});

AngularJS - sharing information between controllers, or altering architecture to not have to

Create a Service to Share Data

Take a look at services in angular to share data. Services are like "global namespaces" inside of angular. They can store/pull data, and they can be injected into multiple controllers to share data. Here's a quick example of a service in angular.

If it's small, you can use rootScope instead

And, it its a small thing (like userName), store it as a property on $rootScope. All of the scopes in your various controllers inherit from rootScope. If you inject it into your controller, then you can access it.

var myApp = angular.module('myApp');

myApp.controller('first', ['$scope', '$rootScope', function($scope, $rootScope) {
$rootScope.userName = 'name';
}]);

Modal Issues

Depending on what you are using to create modal divs, you'll likely create those modal dialogs from within your parent controller.

If you're using a framework like angular-ui, then you will likely

(a) pass the person object to the modal form's controller as a resolve parameter and

(b) pass it back to your base controller in the .then() function for reintegration back into your dataset.

The whole open/ close modal dialog is well articulated in this post.

Sharing data from API between controllers in AngularJS

Well, the best way is to use a service to have your API handling atomar placed inside your application. This fiddle shows you how you could achieve what you try to. By using AngularJS services you will be able to share the same data, objects and functions between controllers and let them interact with eachother. This is undepending on the amount of your controllers inside your application.

The following example is a full working API service with real HTTP-Requests and a real AngularJS service handling. It will help you by implement such logic inside your application. Please dont forget to check out the fiddle demo.

View

<div ng-controller="MyCtrl">
<h1>
MyCtrl
</h1>
<button ng-click="clearData()">
Clear data by using MyCtrl
</button>
<div ng-repeat="user in users">
<p>
Username: {{ user.name }}
</p>
</div>
</div>
<br /><br />
<div ng-controller="MyOtherCtrl">
<h1>
MyOtherController
</h1>
<button ng-click="clearData()">
Clear data by using MyOtherController
</button>
<div ng-repeat="user in users">
<p>
Username: {{ user.name }}
</p>
</div>
</div>

AngularJS Application

var myApp = angular.module('myApp',[]);;

myApp.controller('MyCtrl', function ($scope, apiService) {
$scope.users = apiService.getResponseData();
$scope.$watch(function () { return apiService.getResponseData()}, function (newValue, oldValue) {
$scope.users = newValue
});

$scope.clearData = function () {
apiService.reset();
}
});
myApp.controller('MyOtherCtrl', function ($scope, apiService) {

apiService.loadData();

$scope.$watch(function () { return apiService.getResponseData()}, function (newValue, oldValue) {
$scope.users = newValue
});

$scope.clearData = function () {
apiService.reset();
}
})

myApp.service('apiService', function ($http) {

var responseData = null;

return {
loadData: function () {
return $http({
url: 'https://jsonplaceholder.typicode.com/users',
method: 'GET'
}).then(function (response) {
responseData = response.data
});
},
getResponseData: function () {
return responseData
},
reset: function () {
responseData = null;
}
}
});

AngularJS help sharing data between controllers using $broadcast

I did find a solution to my initial question, which was to use localStorage.setItem("num", "num") to store the data in the browser. It seems this was developed specifically to share data between tabs/windows, and so is accessible via localStorage.getItem("num").

This answers my original question, however I would now like the total to be updated dynamically. At the moment it is only updated upon refresh. Any tips would be appreciated.


EDIT (ANSWER TO ABOVE)

By using this event listener in my second popup -

window.addEventListener('storage', function (event) {
$scope.total = parseInt(event.newValue);
$scope.$apply();
});

I was able to access the storage and bind it to an expression in my HTML. Bear in mind $scope.apply() needs to be called here because total is outside of the scope.

More detail here - https://developer.apple.com/library/safari/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Name-ValueStorage/Name-ValueStorage.html

AngularJS factory for sharing data between controllers

Ok I solved the problem. Basically before I was using this code for the redirect to the new page:

$window.location.assign('/cards/service');

And now I switched to this code:

$location.path('/cards/service');

And it's working.

The only thing is that when it wasn't working when I redirect the page the console in the chrome inspector refresh for every reloading, now the console do not refresh. Can someone tell me the difference between those two functions?



Related Topics



Leave a reply



Submit