Create a service to repeat functions in controller - javascript

I'm trying to write a service that simulates a polling functionality. My code is the following:
app.service('poller', ['$timeout',
function($timeout) {
return ({
poll
})
function poll(e) {
$timeout(function() {
poll(e);
}, 5000);
}
}
]);
When I inject it in my controller I try to use it like this:
poller.poll($scope.getNewMessages());
The weird thing is that it's only called once. Also when I try to use console log in the service like console.log(e) I get undefined. What am I doing wrong?

You need to pass function as value to the poller function and you need to call the function:
app.service('poller', ['$timeout', function($timeout) {
return ({
poll
});
function poll(e) {
e();
$timeout(function() {
poll(e);
}, 5000);
}
}
]);
poller.poll($scope.getNewMessages);

Related

Dealing with Different routeParams in the same controller

I have a single controller where for each different route diffrent parameters are passed.My routes.js file looks like this-
.when('/event/:eid/edit-question/:qid', {
templateUrl: 'views/edit-question.html',
controller: 'eventController',
controllerAs: 'eventCtrl',
resolve: {
"check": function (authService, $location) {
if (!authService.isLoggedIn()) {
$location.path('/login');
}
},
"params": function ($route) {
return $route.current.params;
}
}
})
.when('/event/edit-event/:eid', {
templateUrl: 'views/edit-event.html',
controller: 'eventController',
controllerAs: 'eventCtrl',
resolve: {
"check": function (authService, $location) {
if (!authService.isLoggedIn()) {
$location.path('/login');
}
},
"params": function ($route) {
return $route.current.params;
}
}
})
I'm resolving the route params before loading the controller.
My controller functions looks like this-
myApp.controller('eventController', ['$location','$rootScope', 'params', 'authService', 'apiService', function ($location,$rootScope, params,authService, apiService) {
let dash = this;
//all the route parameters will be resolved and stored here
dash.params = params;
//get the details of an event
dash.getTheEventDetail = () => {
apiService.getEventDetail(dash.params.eid).then(function successCallBack(response){
console.log(dash.params.eid);
dash.eventDetail = response.data.data;
});
}
dash.getTheEventDetail();
//get the detail of a question for the qid passed as parameter
dash.viewQuestion = () => {
console.log(dash.params.qid);
console.log(dash.eventDetail);
dash.questionDetail = dash.eventDetail.questions.filter(question => question._id === dash.params.qid);
console.log(dash.questionDetail);
}
The viewQuestion function gets executed before the getTheEventDetail when I try to access the route /event/:eid/edit-question/:qid due to which dash.eventDetail remains undefined
the viewQuestion is called on initialization of the controller in the edit-question view like this.
<div ng-init="eventCtrl.viewQuestion()"></div>
There can be certain workaround like calling viewQuestion function inside end of getTheEventDetail().But this cause the viewQuestion to be called everytime when the getTheEventDetail is called.Is there a good way to deal with routeParams in this case.
Why not use the $routeParams service in your controller instead? It seems that viewQuestion is dependent upon the getEventDetail method of the apiService running successfully and setting the eventDetail. If this is the case remove the ng-init command and add the view question to your call back to ensure that the promise has completed before calling a method on data that doesn't exist yet. Also, filter returns an array, and since you're searching by ID I assume you may want a single question instead of an array. If this is correct you may need to specify and index of [0] at the end or us Array.find instead.
I'm not sure exactly what outcome you're looking for, but I've pasted a possible solution below (untested of course). Hope that helps.
myApp.controller('eventController', ['$location','$rootScope', routeParams', 'authService', 'apiService',
function ($location,$rootScope, $routeParams,authService, apiService) {
let dash = this;
//get the details of an event
dash.getTheEventDetail = () => {
apiService.getEventDetail(dash.params.eid)
.then(response => {
dash.eventDetail = response.data.data;
if ($routeParams.qid) {
dash.viewQuestion()
}
});
}
dash.getTheEventDetail();
//get the detail of a question for the qid passed as parameter
dash.viewQuestion = () => {
dash.questionDetail =
dash.eventDetail.questions.filter(question => question._id === $routeParams.qid);
console.log(dash.questionDetail);
}
}

Angular Meteor $reactive vs getReactively

I'm learning Angular Meteor and I have a question:
What is the difference between using $reactive and getReactively?
If you take a look at the API reference you get this for $reactive (http://www.angular-meteor.com/api/1.3.2/reactive):
A service that takes care of the reactivity of your Meteor data, and updates your AngularJS code.
This service wraps context (can be used with this or $scope) - so you can use it with any context as you wish
And this for getReactively (http://www.angular-meteor.com/api/1.3.2/get-reactively):
Use this method to get a context variable and watch it reactively, so each change of this variable causes the dependents (autorun, helper functions and subscriptions) to run again.
The getReactively method is part of the ReactiveContext, and available on every context and $scope.
As far as I could understand $reactive will make everything reactive ('this', '$scope' and son on as long as you apply it to them) and getReactively will make only that particular variable, or object reactive.
So if I make this:
controller: function ($scope, $reactive) {
var vm = $reactive(this).attach($scope);
vm.sort = {
name: 1
};
this.helpers({
parties: () => {
return Parties.find({}, { sort : vm.sort });
}
});
this.subscribe('parties', () => {
return [{
sort: vm.sort
},
this.getReactively('searchText')
]
});
});
Why don't I get the same result as if I was doing this:
controller: function ($scope, $reactive) {
var vm = $reactive(this).attach($scope);
vm.sort = {
name: 1
};
this.helpers({
parties: () => {
return Parties.find({}, { sort : this.getReactively('sort') });
}
});
this.subscribe('parties', () => {
return [{
sort: this.getReactively('sort')
},
this.getReactively('searchText')
]
});
});
If $reactive takes care of reactivity I was expecting to see anything inside this and $scope to be reactive and, like in getReactively, whenever something is changed, to cause its dependents to run again.
So: what am I missing?

How to execute Run function before any controller

I'm using AngularJS to make my first application, I want to the run function to be executed before any controller.
My run function looks like :
.run(function ($rootScope,authentification)
{
teamsFactory.sendAuthent().then(function(response)
{
$rootScope.authentdata=response.data;
});
})
My service where I make the authentication :
teams.sendAuthent= function(DeviceID) {
return $http({method:"POST",url:http://myserver.com/authentification",headers: {'X-SocialAPI-Service-Name': 'auth'}})
.then(function(aResponse)
{
var deferred=$q.defer();
deferred.resolve({data:aResponse.data});
return deferred.promise;
});
}
And this is my controller where I use the rootScope data :
.controller('home', function($rootScope,$scope, $http,)
{
alert($rootScope.authentdata.token);
})
But this is not working it says that autehndata is undefined, so the controller is executed before the run function how to resolve that ?
you can try this,
$rootScope.$watch('authentdata', function(n, o) {
if(angular.isDefined(n) {
alert($rootScope.authentdata.token);
// or alert(n.token);
}
}

Angular.JS API using a factory

I've written a backend service which is used by a Angular.JS frontend using a factory, like so:
angular.module('app.social', ['ngResource'])
.factory('Social', function($http) {
return {
me: function() {
return $http.get('http://localhost:3000/me');
},
likeVideo: function(link) {
return $http.post('http://localhost:3000/like/video', { link : link });
},
post: function(link) {
return $http.post('http://localhost:3000/post', { link : link });
},
postVideo: function(link) {
return $http.post('http://localhost:3000/post/video', { link : link });
},
friends: function() {
return $http.get('http://localhost:3000/friends');
},
taggableFriends: function() {
return $http.get('http://localhost:3000/friends/taggable');
},
videos: function() {
return $http.get('http://localhost:3000/videos');
}
};
});
The Social.me endpoint receives profile information from the REST backend. This function is used in various Angular controllers, however (profile page, item detail page, header account button etc.). This means that for every view, profile information is requested from http://localhost:3000/me. Is this good practice, or is it a better idea to cache the information within the factory?
EDIT: Updated code (based on answer from #Rebornix):
angular.module('app.social', ['ngResource'])
.service('SocialService', function() {
var serviceData = {
me: null
};
return serviceData;
})
.factory('Social', function($http, SocialService) {
return {
me: function() {
if (SocialService.me === null) {
return $http.get('http://localhost:3000/me').then(function(response) {
SocialService.me = response.data;
return SocialService.me;
});
} else {
return SocialService.me;
}
}
}
};
});
In the controller, I use:
angular.module('app.profile', [])
.controller('ProfileCtrl', ['$window', '$scope', 'Social', function($window, $scope, Social) {
$scope.me = Social.me();
}])
And the view:
<div ng-controller="ProfileCtrl">
<h1 class="profile-name">{{ me.name }}</h1>
</div>
But the view is not updated as the Facebook.me value get initialized on the first request. I guess I have to manually trigger $scope.$apply() somehow?
You can create a service as storage across controllers like
angular.module('app.social', ['ngResource'])
.service("SocialService", function() {
var info = {
me: null,
friends: []
};
return info;
})
.factory('Social', function($http, SocialService) {
return {
me: function() {
$http.get('http://localhost:3000/me').then(function(response){
SocialService.me = response.data;
});
},
Then in all your controllers, reference infoService instead of calling API again. What you need to is fetching latest data and refresh infoService, all controllers scope will be notified with this change.
In your controller
angular.module('app.profile', [])
.controller('ProfileCtrl', ['$window', '$scope', 'SocialService', 'Social', function($window, $scope, SocialService, Social) {
$scope.SocialService = SocialService;
// Kick off social factory to update user info, you can move it into
// any other functions like `ng-click`.
Social.me();
}])
Then in your view
{{SocialService.me}}
(function (app) {
'use strict';
app.factory('myService', MyService);
MyService.$inject = ['$q', 'serviceResource'];
function MyService($q, serviceResource) {
var jobs = [];
var service = {
getJobs: getJobs
};
return service;
//////////////////////////////////////
function getJobs(refresh) {
if (refresh) {
return serviceResource.autosysJobs().$promise.then(function (data) {
jobs = data;
return jobs;
}, function (err) {
throw err;
});
}
else {
var deferrer = $q.defer();
deferrer.resolve(jobs);
return deferrer.promise;
}
}
}
}(angular.module('app')));
you can pass a bool argument to tell weather to get local copy or fresh copy
It all depends upon the frequency of data change in back end data change and degree of tolerance of data inconsistency in your application. if the source data is changing too frequently and you can't afford inconsistent data then you have no choice other than to get fresh copy every time, but if that's not the case then you can cash data locally

Angular Directives performance issue

I have a .NET webservice that returns an object like:
myObj = {
prop1: value,
prop2:value,
...
prop5:value
}
I created an angular service that returns this entire object(myObj).
I created 5 distinct directives to display these properties in different pages in the application(sometimes, some of them can be in the same page).
I'm calling the angular service in these directives, creating for any of them this "link" function:
link: function (scope, element, attrs) {
getService.getMethod().$promise.then(
function (myObj) {
element.text(myObj.prop1); // .prop2, ... , prop5
},
function (statusCode) {
console.log(statusCode);
}
);
}
I have the feeling that my approach is not the best, calling five times the angular service(through the $promise) obtaining actually the same object(myObj).
If you are interested also how the service is looking:
var localResource = $resource('https://.....',
{},
{'getAll': {method: 'JSONP', isArray: false, params: {callback: 'JSON_CALLBACK'}}}
);
return {
getMethod: function () {
return localResource.getAll();
}
}
Please help, if someone has an ideea haw can I improve it.
Thank you!
It sounds like you can make your getMethod issue only one server call.
.factory("getService", function () {
var getAll;
return {
getMethod: function () {
if (!getAll) {
getAll = localResource.getAll();
}
return getAll;
};
};
});

Categories