JavaScript Scope within factories in AngularJS - javascript

I'm having some headaches with scope, not Angular scope but JavaScript itself.
I have a factory called chartParsingHelpers it's something like this:
angular.module('myApp')
.factory('chartParsingHelpers',['dateUtils', function(dateUtils){
return {
getInitArray : function(){
return [ 'Stuff', 'Stuff 2' ];
},
doFancyStuff : function (data){
var initArray = this.getInitArray();
}
};
}]);
That works great if I inject chartParsingHelpers anywhere and call doFancyStuff it will work. However, I wanted to have some config for my fancy charts since they share code structure and I think is great to share that config around directives and all friends so, I created something like this:
angular.module('visits')
.factory('ChartTypes',['dateUtils', 'chartParsingHelpers', function(dateUtils, chartParsingHelpers){
return {
config : [
{
name : 'Chart 1',
xAxisFormatter : dateUtils.getFullHour,
parseMethod : chartParsingHelpers.doFancyStuff
}
]
};
}]);
My plan is to inject ChartTypes into a Controller and into a directive (for now) but then I receive this error:
TypeError: Object #<Object> has no method 'getInitArray'
If I look into the value of this then... well, it's the value of the object itself with name, xAxisFormatter and so on...
How could I approach this? Is this the right way?

The context of this in chartParsingHelpers.doFancyStuff is probably the issue. I would create the factory like this:
angular.module('myApp')
.factory('chartParsingHelpers',['dateUtils', function(dateUtils){
var self = {};
self.getInitArray = function() {
return ['Stuff', 'Stuff 2'];
};
self.doFancyStuff = function(data) {
var initArray = self.getInitArray();
};
return self;
}]);
That way you make sure that you're always referencing that object.

Related

Passing data between controller via service won't work

I'm trying all the approaches passing data between controllers using service, factory or broadcast. None of them works for me. I follow the exact solution online, but still unfortunate. I placed service inside my app.js.
App.JS
myApp.service('customService', [function () {
this.list = [];
this.setObject = function (o) {
this.list.push(o);
},
this.getObject = function () {
return this.list;
}
}]);
Controller #1
myApp.controller('Controller1', function ($scope, customService) {
customService.setObject({..});
$window.open("/controller2", '_blank');
}
Controller #2
myApp.controller('Controller2', function ($scope, customService) {
console.log(customService.getObject()); // Returns []
}
Problem
It returns [] on controller 2 from controller 1, instead of object data.
You should modify your service for storing a object under some specific key, and then retrieve it later given that key. You can define these keys whatever you like. I defined them in the same service so I can reuse them through all controllers. Something like this
Service
myApp.service('customService', [function () {
this.keys = {"foo": "foo", "bar": "bar"};
this.list = {};
this.setObject = function (obj, key) {
this.list[ley] = obj;
},
this.getObject = function (key) {
return this.list[key];
}
}]);
Controller #1
myApp.controller('Controller1', function ($scope, customService) {
customService.setObject({"propX": "propX"}, customService.foo);
//$window.open("/controller2", '_blank');
/* I encourage you to use something like ngRoute here for navigating
* so, you should do something like $location.path('/controller2');
*/
}
Controller #2
myApp.controller('Controller2', function ($scope, customService) {
console.log(customService.getObject(customService.foo));
}
Are your controllers in the same page ?
Angular.js only works and keeps data on a single page. If your page reloads
(as you seem to indicate when you say "express.js loads the next
page", then it reinitialized everything.
You should either:
look at how to use Angular.js routing
(http://docs.angularjs.org/tutorial/step_07) so that you stay on the
same page. use something to persist your data, such as localstorage.
Find out more: http://diveintohtml5.info/storage.html
ref : Using angular service to share data between controllers
have you used routing? if u use then your code should be work.

Why are my controllers methods not available?

after a long time I have to concentrate an angular again.
But I fail...
... ng-repeat="n in DataController.getObjects"
myApp.controller('DataController', [function () {
console.log('test 1');
var getObjects = function () {
console.log('test 2');
return [1,2,3,4,5,6,7];
};
}]);
It is writing test 1 to console but not test 2. And the frontend does not get the array.
Any hint for me?
Regards
n00n
You have to expose method/variable which you want to access on page on this(context) of your controller. So that you can access that method/variable via controller alias as you you seems to be using controllerAs pattern.
Code
myApp.controller('DataController', [function () {
var self = this;
console.log('test 1');
var getObjects = function () {
console.log('test 2');
return [1,2,3,4,5,6,7];
};
self.getObjects = getObjects;
}]);
I hope you have already defined controller alias while using ng-controller directive, If you haven't used it, follow below.
ng-controller="DataController as dataCtrl"
ng-repeat="n in dataCtrl.getObjects()"
And as you can see you should call method in ng-repeat like getObjects() to get a array from method.

How to DRY up $scope-manipulating code across controllers in angularJS

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.

Sharing data from asynchronous calls amongst directives in AngularJS with TypeScript

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!

AngularJS automatically updating controller data by service

I'm having some basic problems with angular at the moment. I just wrote a service that reads the temperature of an external device in an interval of five seconds. The service saves the new temperature into a variable and exposes it via a return statement. This looks kind of this (simplified code):
angular.service("tempService", ["$interval", function ($interval) {
//revealing module pattern
var m_temp = 0,
requestTemp = function() {//some logic here},
onResponseTemp = function (temp) {
m_temp = temp;
},
//some other private functions and vars ...
foo = bar;
//request new temperture every 5s, calls onResponseTemp after new data got received
$interval(requestTemp, 5000);
return {
getTemp = function(){return m_temp;}
}
}]);
I use a controller to fetch the data from the service like this:
angular.controller("tempCtrl", ["$scope", "tempService", function ($scope, tempService) {
$scope.temp = tempService.getTemp();
}]);
In my view I access it like this:
<div ng-controller="tempCtrl">
<p>{{temp}}</p>
</div>
But I only get 0 and the value never changes. I have tried to implement a custom Pub/Sub pattern so that on a new temperature my service fires an event that my controller is waiting for to update the temperature on the scope. This approach works just fine but I'm not sure if this is the way to go as angular brings data-binding and I thought something this easy had to work by itself ;)
Help is really appreciated.
Please see here http://jsbin.com/wesucefofuyo/1/edit
var app = angular.module('app',[]);
app.service("tempService", ["$interval", function ($interval) {
//revealing module pattern
var m_temp = {
temp:0,
time:null
};
var requestTemp = function() {
m_temp.temp++;
m_temp.time = new Date();
};
var startTemp = function() {
$interval(requestTemp, 3000);
};
return {
startTemp :startTemp,
m_temp:m_temp
};
}]);
app.controller('fCtrl', function($scope,tempService){
$scope.temp = tempService;
$scope.temp.startTemp();
});
You are returning a primitive from your service, if you want to update an primative you need to reftech it. You should return an object, as on object is passed by reference, you get the actual values in your controller.
do this in your service:
return m_temp;
And this in your controller:
$scope.temp = tempService;
and your view will update as soon as the service gets updated.
Does this help you?
i think you should use $interval in controller ot in service
$interval(tempService.getTemp(), 5000);

Categories