Hello every body I have a controller:
app.controller('CartController', ['$scope', 'cartDataService', function($scope, cartDataService){
$scope.goodsCount = cartDataService.goodsCount;
$scope.changeQuantity = function (quantity, id) {
if (quantity < 1) {
ngCart.removeItem(id);
} else {
ngCart.getItemById(id).setQuantity(quantity);
}
console.log(ngCart.getTotalItems());
$scope.goodsCount = cartDataService.goodsCount;
}
}]);
And service:
app.service( 'cartDataService', [ '$rootScope', 'ngCart', function( $rootScope, ngCart ) {
return {
goodsCount: ngCart.getTotalItems()
};
}]);
(ngCart is a module, it stores goods in web storage)
And my view on the top of the page:
<div ng-controller="CartController" class="numerik"><% goodsCount %></div>
And view in body of the page:
<div ng-controller="CartController"><% goodsCount %></div>
When I'm calling changeQuantity method, data into the both views doesn't changes. What am I doing wrong, or maybe here I should use other logic?
Angular services are singleton. So when you call your cartDataService it is instantiated and set the value goodsCount what ngCart.getTotalItems() returns, initially it maybe undefined or something.
Next time when you want the updated value from cartDataService.goodsCount it returns initial value Not the changed value
To get updated value you have to set the function and call the function later in your controller like
In service
return {
goodsCount: ngCart.getTotalItems; // pass the function Not executed result. ngCart.getTotalItems() it returns executed result
};
And in controller inside $scope.changeQuantity function
$scope.goodsCount = cartDataService.goodsCount(); //call the function here
Related
I have 2 js files namely collegeApp.js and branchApp.js. I have two controllers CollegeController.js which is inside collegeApp.js ng-app and BranchController.js which is inside branchApp.js ng-app.
From my html I am redirecting to another page.
Here is my html
<li data-ng-click="getBranchByBranchId(branch.branchId); setBranchId(branch.branchId)">
{{branch.branchName}}
</li>
This html page is in collegeApp.js.After clicking on branch name I am calling method And its controller looks like this.
CollegeController.js
var CollegeController = function($scope, $rootScope, $http, $location, $route,CollegeService,$routeParams) {
$rootScope.pageTitle = $route.current.title;
$scope.getBranchId = function() {
CollegeService.getBranchId().then(function(response) {
$scope.branchId = response.data;
});
}
$scope.setBranchId=function(branchId) {
CollegeService.setBranchId(branchId);
$rootScope.passBranchId = branchId;
window.location.href="./branch?
branchId='+$rootScope.passBranchId";//Here I am redirecting to branch page with id.//
}
}
The branch page is in branchApp.js and above code is in collegeApp.js.
Now in BranchController.js I am trying to catch branchId sent from previous page.
BranchController.js
var BranchController = function($scope, $rootScope, $http, $location, $route,BranchService,$routeParams)
{
$scope.branchId = $rootScope.passBranchId;//Here i am trying to get branchId//
console.log($scope.branchId);//I am getting undefined.
}
I tried $rootScope,$routeParams.But none of them worked.
Is there any possible way that i can pass branchId from collegeApp to branchApp? or am i missing something?
When redirecting your page use $location.path('/branch/' + branchId)
Plus you already have $location in your controller.
Then you'll want to use $routeParams to find the id in your url.
Update route config to find params, should look like this
$routeProvider
...
.when('branch/:branchId', {
templateUrl: 'views/branches.html',
controller: 'BranchController'
})
Then get the value like so
$scope.branchId = $routeParams.branchId;
I realized that you wanted to share information between multiple modules within the same application. Here is a completed code sample to test the scenario.
/**
* Service definition which holds the passed values
*/
angular.module('myapp')
.config('collegeService', collegeService);
collegeService.$inject = [];
function collegeService() {
var branchId = null;
return {
getBranchId: getBranchId,
setBranchId: setBranchId
};
function getBranchId() {
/**
* Implement a promise based approach if the branch ID reads from an external source
* else just return it as given below
*/
return branchId;
}
function setBranchId(brId) {
branchId = brId
}
}
/**
* First controller definition
*/
angular.module('myapp')
.controller('CollegeController', CollegeController);
CollegeController.$inject = ['$scope', 'collegeService'];
function CollegeController($scope, collegeService) {
$scope.getBranchId = function() {
/**
* Use promise based approach as below if the read method returns a promise
*/
collegeService.getBranchId().then(function(response) {
$scope.branchId = response.data;
});
/**
* Uses a simple approach as below if the read method returns the value
*/
// $scope.branchId = collegeService.getBranchId();
};
$scope.setBranchId = function(branchId) {
CollegeService.setBranchId(branchId);
}
}
/**
* Second controller definition
*/
angular.module('myapp')
.controller('BranchController', BranchController);
BranchController.$inject = ['$scope', 'collegeService'];
function BranchController($scope, collegeService) {
$scope.init = function() {
$scope.branchId = collegeService.getBranchId();
};
/**
* Invokes the init method during the Controller getting instantiated
*/
$scope.init();
}
I finally found the solution.I just added this line and it worked.
Inside SchoolController.js
$scope.setBranchId=function(branchId)
{
window.localStorage.setItem("branchId", branchId);
}
And in BranchController.js
$scope.branchId = window.localStorage.getItem("branchId");
Now i am able to use Id anywhere in controller and also i am able to pass Id from collegeApp.js to branchApp.js ng-apps.
My first controller:
angular.module('application')
.controller('FirstController',['$rootScope',function($rootScope) {
var data=[0,1,2];
$rootScope.items=data;
}]);
My second controller:
angular.module('application')
.controller('SecondController',['$rootScope',function($rootScope) {
$rootScope.items[0]=3;
console.log($rootScope.items); // [3,1,2]
}]);
When the second controller is running, its corresponding view is changed; however not the same happens when going back to the corresponding view of the first controller (both views are bound to $rootScope.items). Why that happens? I am using ui-router and FirstController has to do with the main page of the SPA and SecondController with another page. Moreover, by keeping track of $rootScope.items with:
<pre>
{{$root.items | json}}
</pre>
in both templates the second one is renewed to [3,1,2] and the first one remains [0,1,2].
Passing the same $scope between the two controllers isn't an ideal way of maintaining a single data model, and what you need to do is to establish a service module (or a factory) to manage the data for you, so that both controllers can talk to the factor for your data.
This is how you set up the factory
app.factory("Data",
function () {
var storage = [0,1,2]; // where your data is
return {
get: function () {
return storage;
},
set: function (toSet) {
storage = toSet;
return storage;
}
};
});
to let the controllers know where the data is, use
app.controller ("FirstController",
function ($scope, Data)
{
console.log(Data); // [0,1,2]
Data.set( [3,1,2]); // demoing change
}
same is for the second controller
app.controller ("FirstController",
function ($scope, Data)
{
console.log(Data); // [3,1,2]
}
I am trying to update the scope value on a view when the service data changes.
The problem is that, (a) if I update the data in a different controller, then (b) the value doesn't update on the view.
main.html
<!-- breadcrumb row -->
<div ng-controller="mainController">
<span ng-if="memberCompany !== null">{{ memberCompany }}</span>
</div>
<!-- / breadcrumb -->
main.js
// breadcrumb service
app.service('breadcrumb', function() {
// variables
var memberCompany = null;
return {
// get compnay
getCompany: function() {
return memberCompany;
},
// set company
setCompany: function(value) {
memberCompany = value;
}
}
});
// main controller
app.controller('MainController', ['$scope', 'breadcrumb', function($scope, breadcrumb) {
// get company to display in view
$scope.memberCompany = breadcrumb.getCompany();
}
]);
If I update the service value in a different controller, I would like to be able to display that updated value back on the index view so it's viable across the app
other controller
app.controller('otherController', ['$scope', 'breadcrumb', function($scope, breadcrumb) {
// update company
breadcrumb.setCompany('StackExchange');
// update the scope data in the view?
}]);
How can I display the updated value on the index view once it's changed?
You can use a $watch in your controller on that service:
$scope.$watch(function() {
return breadcrumb.getCompany()
}, function(newValue, oldValue) {
$scope.memberCompany = newValue;
});
If this is a site-wide necessity, I would definitely stay far, far away from adding a bunch of watches everywhere as they can be costly for development time as well as computer resources. I would first write the service accordingly:
angular.module('myModule').service('Breadcrumb', function() {
return {
company: null,
setCompany: function(company) {
this.company = company;
},
getCompany: function() {
return this.company;
}
};
});
Although in my opinion, the getters and setters are definitely very unnecessary ( you could just set by Breadcrumb.company = company and get by Breadcrumb.company). Moving on, you should assign the breadcrumb service to the root scope:
angular.module('myModule').run(function($rootScope, Breadcrumb) {
return $rootScope.breadcrumb = Breadcrumb;
});
Then at this point you can either inject this service into your controllers/directives and call upon it within any view in the application like so:
<span class="my-company-name" ng-bind="$root.breadcrumb.company.name" />
This saves you from having to call watchers on everything and allows for you to only inject the Breadcrumb service when you actually need it in the application logic. However, like I said at first, it really depends on how widely used this service is as you do not want to muddy up your $rootScope with arbitrary values. If you don't want to assign it to the $rootScope you could assign it in your controllers and directives:
angular.module('myModule').controller('ApplicationCtrl', function($scope, Breadcrumb) {
$scope.breadcrumb = Breadcrumb;
});
and access it from templates like this:
<span ng-bind="breadcrumb.company.whatever" />
Hope that helps!
There are a lot of references that discuss this, but I just need someone to confirm if this is right or not. If i have a service which I want to share information with a controller, and the controller should update on changes to the service I need to return an object from the service, like:
.factory('myService', ['$http', function($http) {
var data = {};
var service = {
constant: 1234,
getData: function() {
return data;
},
doCalculation: function() {
service.constant = data.const*25;
},
requestData: function() {
return $http.get('/blah')
.then(function( response ) {
data = response.data;
}
}
}
return service;
}])
Now to pass it to a controller for use and have it update if requestData is invoked again during maybe a route resolve() I would and can't do:
.controller('myCtrl', ['myService', function(myService) {
var self = this;
// PART 1
self.data = myService.constant; // this is not bound and will not update, yes?
self.data1 = myService.getData(); // this is not bound and will not update, yes?
// So, the above would be assigned or invoked only once on init of controller and
// would have to reset manually by assigning either a value or the result of the
// the function call again
self.myService = myService; // pass entire service
// Now, in controller functions or in the UI I can invoke the functions or access
// values, and those results will be bound and update on changes to the service
// since I've passed it in its entirety
self.getData = function() {
return self.myService.getData();
}
// PART 2
self.getData = myService.getData; // would you ever do this?
// You wouldn't have to pass the entire service if it had a bunch of different
// parts that maybe you didn't want to be available...
}]);
PART 1
<div ng-show="myCtrl.myService.doCalculation() === someNumber">You can't see me unless doCalculation resolves to someNumber</div>
PART 2
<div ng-show="myCtrl.getData() === anotherNumber">Would this work? and would you want to do this?</div>
I just can't seem to get the concept of how sharing data between a service(s) and a controller(s) works, and when it is working and when it won't. If all you can do is say correct, wrong, wrong, oh man so wrong, that's kewl, but if you can also say and this is why, I'd be ecstatic to put this away as finally resolved so I don't keep questioning it.
I wouldn't go too far here..
A controller is your view's helper. You need to generate vars and functions on your scope to help your view accomplish things.
Your business model however, is something that you would like to have one reference.
What I do is create my business model on a service, so multiple entities can share it(e.g. other services, directives, controllers etc.).
When my controller kicks in, I add a pointer to the model from the service and use the same reference between them. I bind the models properties to the view.
So:
A controller has it's own methods(dont share the service's methods). A controllers method should be short and use a service method as a helper.
A controller should have a reference to the business model which is created by a service. All your ajax calls should come from the service and populate\send the model that the service is holding.
A controller should have basic view functions(e.g. decide which css class to apply to an element). When you submit a form, the controller function should call the service's submit which will perform you ajax call.
Example:
Html:
<div ng-app="app">
<div ng-controller="myCtrl">
<input type="text" ng-model="Model.propA" />
<br/>
<input type="text" ng-model="Model.propB" />
<div ng-show="ShouldShowSecondDiv()">Second Div.</div>
<br/>
<button ng-click="SubmitForm()">Submit</button>
</div>
</div>
JS:
var app = angular.module('app', []);
app.controller('myCtrl', function ($scope, myService) {
// simple controller "view method".
$scope.ShouldShowSecondDiv = function () {
return $scope.Model.propB > 12;
};
// "complex" "non-view method" -> use service.
$scope.SubmitForm = function () {
myService.SubmitModelToServer();
};
// get the ref. from the service.
$scope.Model = myService.GetModel();
});
app.service('myService', function () {
this.Model = {};
// perform an ajax to get the model or whatever.
this.GetModel = function () {
this.Model = {
propA: 'Im prop A',
propB: 12
};
return this.Model;
};
// submit it to the server via $http. Check the log and you will see the binding(if you changed a value in the view).
this.SubmitModelToServer = function () {
console.log("ajax or whatever....submitted");
console.log(this.Model);
};
});
JSFIDDLE.
I want to pass a variable between controllers with a service. Here is the service to pass the variable (in this case a song id):
'use strict';
angular.module('PortalApp')
.service('ActionbarService', ['$window', function ActionbarService(window) {
var song;
return {
getSong: function () {
return song;
},
setSong: function(value) {
song = value;
}
};
}]);
Here is the relevant part of the controller I am setting the song from:
$scope.actionbarSetSong = function(song_id) {
ActionbarService.setSong(song_id);
}
and here is the controller I am getting the song id from:
'use strict';
angular.module('PortalApp')
.controller('ActionbarCtrl', function ($scope, MediaService, ActionbarService, $location, $routeParams, AudioPlayerAPI) {
$scope.song_id = ActionbarService.getSong();
$scope.openPlaylistModal = function (song_id) {
$("#addToPlaylist").modal('show');
}
});
It is being set in the service because when I do getSong in my view it worked (I forget where), but then when I try to set it in my 2nd controller it doesn't work. Here's the relevant part of my view for reference:
<div class="cell action-bar" ng-click="actionbarSetSong(song.id);" ng-repeat="song in media.data">
Some Stuff
</div>
Mmm.. service returns new ActionbarService. You probably want to use factory, or change your getters/setters to this.get & this.set.
Also, avoid polluting the $rootScope; whenever you want to share data between controllers, use a service.