Here is what I want to do
(function(){angular.module('app').factory("loadDataForStep",ls);
ls.$inject = ['$scope','stepIndex']
function ls ($scope, stepIndex) {
if ($routeParams.code != undefined) {
$scope.code = $routeParams.code;
$scope.retrieveData($routeParams.code);
}
$rootScope.stepIndex = stepIndex-1;
$rootScope.currentStep = stepIndex;
$rootScope.resultsLoaded = false;
if (!fieldDefinitionsLoaded) {
loadAllElementsDefinition();
loadStepsWithOverrides(stepIndex, loadStep);
} else {
loadStep(stepIndex);
}
}
})();
I know there are plenty of issues here, but the issue of the moment (the question) is How do I get $scope injected and pass step index as a parameter? As you can see, $scope needs to come from angular, but I need to provide stepIndex.
Any help is appreciated.
Service don't have scope So can't inject scope in factory.
Scope is an instance of controller.
If you wanna to deal scope object in factory then declare variable in factory then bind factory with scope variable.
Then try kinda like this
var app = angular.module("app",[]);
app.factory("mySvc",function(){
return {
dataList : []
}
});
app.controller("myCtrl",function($scope,mySvc){
$scope.model=mySvc;
console.log($scope.model);
});
Related
Pardon if this question is a total blow-off... Just getting warmed-up into the world angularJS.
I have these two controllers: seekerController and wizardController...
Inside the wizardController, I have a chat Scope object, and I have implemented a bunch of functions that are manipulating this chat Scope object.
Going back to the other controller now, ( seekerController ), I discover that I need to have basically a direct replica of this chat Scope object and all the other functions manipulating it as I have inside wizardController
The obvious way is just to copy all these into my other controller, and my work is done under a minute, but then I'll have a lot of repeated stuffs everywhere...
So: I'm looking for a way where I can have this(the code) in a single place, but still be able to have access to this chat Scope object from both controllers, as well as all the other functions working seamlessly.
Update - add code samples:
//seekerController
angular.module('cg.seeker', [])
.controller('SeekerController', ['$scope', 'seekerService', 'timeService', 'chatService', '$stateParams', 'toastr',
function ($scope, seekerService, timeService, chatService, $stateParams, toastr) {
...
// THE CHAT BUSINESS
$scope.chat = { close: true };
chatService.unreadCount(function(count){
$scope.chat.unreadCount = count;
$scope.$apply();
});
chatService.listDialogs( function (dialogList) {
$scope.chat.dialogList = dialogList.items;
$scope.$apply();
} );
$scope.endChat = function () {
$scope.chat.close = true;
}
$scope.chatBox = function (dialogId, occupants_ids) {
$scope.chat.opponentId = getOpponentId(occupants_ids);
chatService.getMessages( dialogId, function (messageList) {
$scope.chat.messages = messageList.items;
$scope.chat.close = false;
$scope.$apply();
});
}
var getOpponentId = function (opponentId) {
if(typeof(opponentId) != 'object') {
return opponentId;
} else {
return opponentId.filter(function(x) { return x != $scope.seeker.chat_user.chat_id_string; })[0];
}
}
$scope.sendMsg = function (opponentId) {
var msg = {
type: 'chat',
body: $scope.chat.msg,
extension: {
save_to_history: 1,
}
};
chatService.sendMsg(opponentId, msg);
$scope.chat.msg = '';
}
...
I now have an exact replica of the above code in a second controller WizardController. Exactly same, with no changes... and even a third controller have some of these, though not all.
The next level of abstraction to angularjs controllers are
Factory
Service
Provider
You could use a service called maybe chatService which could contain the common code. You can inject the service into any controller which needs the common functionality and invoke the methods on the Service.
Do note that you could use any of the above three options even though I have mentioned just Service in the above statement.
EDIT 1:
You could move the common parts of the code from Controller to Service.
For example:- You could move the construction of msg object from controller to chatService. You controller would be simply -
$scope.sendMsg = function (opponentId) {
chatService.sendMsg(opponentId);
$scope.chat.msg = '';
}
And your chatService would be doing the hard-work.
$chatService.sendMsg = function (opponentId) {
var msg = {
type: 'chat',
body: $scope.chat.msg,
extension: {
save_to_history: 1,
}
};
sendMsg(opponentId, msg);
}
After simplifying the Controllers you could revisit to see if you could use only one controller instead of 3 as they seem to be doing similar function.
I can find bits and pieces of how to solve this, but no concrete way to make it work.
I have an asynchronous call to a server to fetch data in AngularJS and wish to store it in a variable. This variable then needs to be accessible to all the directives in the app, but they obviously all need to wait for the variable to be assigned before they can use it. I'm also using TypeScript and its export functionality to spin directives from their own functions.
Controller
export class MainController{
fundData: Object;
constructor(scope, FundService) {
FundService.fetchData('some_param').then(d => {
let data = d[0],
fundProps = data.properties_pub;
this.fundData = {
'isin': data.clientCode,
'nav': fundProps.nav.value,
'nav_change': fundProps.nav_change.value.toFixed(2),
'nav_change_direction': change,
'total_aum': fundProps.net_asset.value.toFixed(2)
};
scope.ctrl = this;
});
}
}
Directive
class OverviewController {
scope: ng.IScope;
constructor(scope){
scope.$watch('data', newVal => {
console.log(newVal);
});
}
}
OverviewController.$inject = ['$scope'];
export function overview(): ng.IDirective {
return {
restrict : "C",
controller : OverviewController,
controllerAs : "overview",
template : require("../templates/overview"),
bindToController :{
data: '='
}
}
}
HTML
<div ng-controller="MainController">
<div class="overview" data="ctrl.fundData"></div>
</div>
Bootstrap Process
let module = angular.module(MODULE_NAME,[])
.controller('MainController', ['$scope','FundService', MainController])
.service('FundService', FundService)
.directive('overview', overview);
Things I've Tried:
$rootScope
I can set something static and share it, so this works:
$rootScope.data = 2;
This doesn't:
someFunction().then(data => { $rootScope.data = data });
Maybe there's something about promises in $rootScope I don't understand.
Setting in controller
I can set the result of the call to a variable in the controller, set that to an attribute in the directive, and then bind the attribute to its controller, but this doesn't work either, even if I use $watch on the variable.
What I would do is fetch the data, store it in a service (which I think you are already doing) and then broadcast an event when the data in the service is updated. Here's an example (in raw javascript)
module.service('DataService', function(rootScope) {
...
var data;
services.setData = function(newData) {
data = newData;
rootScope.$broadcast('DataUpdated');
};
...
});
And then in your directives all you would need to do is listen for the 'DataUpdated' event:
scope.$on('DataUpdated', ...);
Hope that helps!
I am storing my data inside Angular service (to share across controllers) and provide a function to update it:
.factory('DataManager', function($rootScope){
var _json = {init: 'from DataManager'};
return {
json: _json,
changeTo: function (newVal) {
_json = newVal;
console.log("Changing to ", _json);
}
};
})
Then I simply pull the data into controller:
.controller('MainCtrl', function(DataManager){
var MC = this;
MC.json = DataManager.json;
MC.changeTo = DataManager.changeTo;
})
The problem is - when MC.changeTo function is called, it does update _json variable inside the Service, but not in the controller!
Here is JSbin illustrating the problem.
Any idea what I am doing wrong here?
Try this. Your code doesn't work because _json variable is refering to diffrent object each time. angular.copy copies the new object to the same reference.
changeTo: function (newVal) {
angular.copy(newVal, _json);
console.log("Changing to ", _json);
}
I cannot get a binded service value to update when it is changed. I have tried numerous methods of doing so but none of them have worked, what am I doing wrong? From everything I have seen, this seems like it should work...
HTML:
<div class="drawer" ng-controller="DrawerController">
{{activeCountry}}
</div>
Controller:
angular.module('worldboxApp')
.controller('DrawerController', ['$scope', 'mapService', function($scope, mapService) {
$scope.$watch(function() { return mapService.activeCountry }, function(newValue, oldValue) {
$scope.activeCountry = mapService.activeCountry;
});
}]);
Service:
angular.module('worldboxApp').
service('mapService', function(dbService, mapboxService, userService) {
this.init = function() {
this.activeCountry = {};
}
this.countryClick = function(e) {
this.activeCountry = e.layer.feature;
};
this.init();
});
I put a break point to make sure the mapService.activeCountry variable is being changed, but all that ever shows in the html is {}.
If you work with objects and their properties on your scope, rather than directly with strings/numbers/booleans, you're more likely to maintain references to the correct scope.
I believe the guideline is that you generally want to have a '.' (dot) in your bindings (esp for ngModel) - that is, {{data.something}} is generally better than just {{something}}. If you update a property on an object, the reference to the parent object is maintained and the updated property can be seen by Angular.
This generally doesn't matter for props you're setting and modifying only in the controller, but for values returned from a service (and that may be shared by multiple consumers of the service), I find it helps to work with an object.
See (these focus on relevance to ngModel binding):
https://github.com/angular/angular.js/wiki/Understanding-Scopes
If you are not using a .(dot) in your AngularJS models you are doing it wrong?
angular.module('worldboxApp', []);
/* Controller */
angular.module('worldboxApp')
.controller('DrawerController', ['$scope', 'mapService',
function($scope, mapService) {
//map to an object (by ref) rather than just a string (by val), otherwise it's easy to lose reference
$scope.data = mapService.data;
$scope.setCountry = setCountry; //see below
function setCountry(country) {
// could have just set $scope.setCountry = mapService.setCountry;
// however we can wrap it here if we want to do something less generic
// like getting data out of an event object, before passing it on to
// the service.
mapService.setCountry(country);
}
}
]);
/* Service */
angular.module('worldboxApp')
.service('mapService', ['$log',
function($log) {
var self = this; //so that the functions can reference .data; 'this' within the functions would not reach the correct scope
self.data = {
activeCountry: null
}; //we use an object since it can be returned by reference, and changing activeCountry's value will not break the link between it here and the controller using it
_init();
function _init() {
self.data.activeCountry = '';
$log.log('Init was called!');
}
this.setCountry = function _setCountry(country) {
$log.log('setCountry was called: ' + country);
self.data.activeCountry = country;
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="worldboxApp">
<div ng-controller="DrawerController">
<button ng-click="setCountry('USA')">USA</button>
<br />
<button ng-click="setCountry('AUS')">AUS</button>
<br />Active Country: {{data.activeCountry}}
</div>
</div>
In some case $watch is not working with factory object. Than you may use events for updates.
app.factory('userService',['$rootScope',function($rootScope){
var user = {};
return {
getFirstname : function () {
return user.firstname;
},
setFirstname : function (firstname) {
user.firstname = firstname;
$rootScope.$broadcast("updates");
}
}
}]);
app.controller('MainCtrl',['userService','$scope','$rootScope', function(userService,$scope,$rootScope) {
userService.setFirstname("bharat");
$scope.name = userService.getFirstname();
$rootScope.$on("updates",function(){
$scope.name = userService.getFirstname();
});
}]);
app.controller('one',['userService','$scope', function(userService,$scope) {
$scope.updateName=function(){
userService.setFirstname($scope.firstname);
}
}]);
Here is the plunker
Note:- In Some case if broadcast event is not fired instantly you may use $timeout. I have added this in plunker and time depends on your needs. this will work for both factories and services.
I have the worlds simplest controller which i want access to $scope but it is "undefined" and I cannot, for the life of me work out why, however all the functions are called corectly, the DataService, etc is working perfectly, just i have no access to $scope?!
controller code is below
app = angular.module("windscreens", []);
app.controller('DamageCtrl', function($scope, DataService) {
$scope.setDamageLocation = function(location) {
DataService.getDamage().setLocation(location);
};
$scope.isLocation = function(requiredLocation) {
return DataService.getDamage().getLocation() === requiredLocation;
};
$scope.progress = function() {
};
});
To access a property on the scope from your HTML template you only need to use the property name, you don't need to write $scope with it.
Example:
<button ng-click="progress()"></button>
In your javascript you will only have access to the $scope inside the controller and its functions. If you call an external resource, for example: DataService module, it won't have access to the $scope unless you pass it as an argument explicitly.
I managed to get it working using the alternative syntax. As detailed below, still not sure why it wasn't working but hey hum
app.controller('DamageCtrl', ['$scope', 'DataService',
function($scope, DataService) {
$scope.setDamageLocation = function(location) {
DataService.getDamage().setLocation(location);
};
$scope.isLocation = function(requiredLocation) {
return DataService.getDamage().getLocation() === requiredLocation;
};
$scope.progress = function() {
console.log($scope);
};
}
]);