Catch response from callback-function or pass variable into callback function? - javascript

Using the facebook api, you can add a listener that triggers a function whenever someone clicks a like button:
FB.Event.subscribe('edge.create', page_like_callback);
This is what my function looks like, where I listen:
function($scope, $window) {
$scope.liking = $window.liking;
FB.Event.subscribe('edge.create', page_like_callback);
}
I want to set $scope.liking = true; for whenever someone clicks like:
var page_like_callback = function(url, html_element) {
$scope.liking = true;
};
But the $scope variable isn't accessible inside the callback. I either want to pass $scope to the callback or get a return from the callback and use that to set the like. What's the best approach for this and how should I do it?

You could have a function return your callback taking $scope as an argument so that $scope is now captured by the callback function
var page_like_callback = function($scope) {
return function(url, html_element) {
$scope.liking = true;
};
}
FB.Event.subscribe('edge.create', page_like_callback($scope));

That's because the $scope variable is only defined within your function($scope, $window), so you need to make sure that page_like_callback has access to it. One way to do this is:
function($scope, $window) {
var page_like_callback = function(url, html_element) {
$scope.liking = true;
};
$scope.liking = $window.liking;
FB.Event.subscribe('edge.create', page_like_callback);
}
That way, page_like_scope has access to $scope.
This is a bit spaghetti-ish, so you might need to provide more of your code if you want a better solution.

Related

How do I add result to my scope ng-click?

This is a relatively simple piece of code that calls a service and returns some data. I need to set the $scope with the result of the data. Is there an easy way to set this data to the scope without resorting to to binding the scope to the function in the then clause?
Angular Code
(function () {
var app = angular.module('reports', []);
var reportService = function($http, $q) {
var service = {};
service.getMenuData = function() {
var deffered = $q.defer();
$http.get('/Report/MenuData').success(function(data) {
deffered.resolve(data);
}).error(function(data) {
deferred.reject("Error getting data");
});
return deffered.promise;
}
return service;
};
reportService.$inject = ['$http', '$q'];
app.factory('reportService', reportService);
var reportMenuController =
function ($scope, $http, reportService) {
$scope.getMenuData = function(e) {
reportService.getMenuData().then(function(data) {
// Need to set the $scope in here
// However, the '$scope' is out of scope
});
}
};
reportMenuController.$inject = ['$scope', '$http', 'reportService'];
app.controller('ReportMenuController', reportMenuController);
})();
Markup
<div>
<div ng-controller="ReportMenuController">
<button ng-click="getMenuData()">Load Data</button>
</div>
</div>
There is absolutely no problem to set the $scope from within the function passed to then(). The variable is available from the enclosing scope and you can set your menu data to one of its fields.
By the way: You should consider to use then() instead of success() for your http request. The code looks much nicer because then() returns a promise:
service.getMenuData = function() {
return $http.get('/Report/MenuData').then(function(response) {
return response.data;
}, function(response) {
deferred.reject("Error getting data");
});
}
success() is deprecated by now.
I didn't notice the small detail missing in the plunker where my code was different.
(function () {
...
var reportMenuController =
function ($scope, $http, reportService) {
$scope.getMenuData = getMenuData;
function getMenuData(e) {
reportService.getMenuData().then(function(data) {
// Now I have access to $scope
});
}
};
...
})();
Notice the changes to the two lines as below:
$scope.getMenuData = getMenuData;
function getMenuData(e) {
This also begs a small question which is, "Why is it okay to set getMenuData to the $scope before it is declared?

value returned from ajax call not getting set to variable in controller in angular js

HTML
<div id="SalaryDiv">
<div ng-controller="SalaryController as sal">
<div ng-repeat="salaryDetail in sal.data">
<p>{{salaryDetail.Name}}</p>
<p>{{salaryDetail.Salary}}</p>
</div>
</div>
</div>
JS
(function () {
var salary = angular.module("SalaryDetails", []);
salary.controller("SalaryController", function () {
var newData = getAssociateData();
alert(newData); //here it is alerting as undefined
this.data = salaryDetails;
});
function getAssociateData() {
var returnData;
$.ajax({
url: "https://gist.githubusercontent.com/vigneshvdm/862ec5a97bbbe2021b79/raw/d7155b9c7fd533597c912fc386682e5baee1487a/associate.json",
type: "GET",
success: getDetails
});
function getDetails(data) {
salaryDetails = data;
return data;
};
};
}());
Here the success function is getting called,
but value is not getting set
1) The return value from getAssociateData is whatever the return value is of $.ajax - which is NOT the data that you return. $.ajax is an async call.
2) You should use Angular's $http rather than jQuery's $.ajax - this would apply the changes to the View automatically (i.e. it will call $scope.$apply() on your behalf).
You also seem to be expecting this.data to be an array (I gather from the use of ng-repeat="salaryDetail in sal.data", so push instead of assigning.
salary.controller("SalaryController", function ($http) {
var url = "https://gist.gith....json";
var vm = this; // your "Controller As" ViewModel
vm.data = [];
$http.get(url).then(function(salaryDetail){
vm.data.push(salaryDetail);
}
}
This is by way of illustration. I agree with other suggestions here that HTTP calls should be abstracted away in a Service, rather than keeping them in the controller. But, one step at a time...
You should use the $http service.
salary.controller("SalaryController", function ($scope, $http) {
$scope.salaryDetails = null;
var url = 'https://gist.githubusercontent.com/vigneshvdm/862ec5a97bbbe2021b79/raw/d7155b9c7fd533597c912fc386682e5baee1487a/associate.json';
$http.get(url).
success(function (data) {
$scope.salaryDetails = data;
});
});
Note: I put it in the controller here, but as a best practice, you should only inject an $http dependency into your custom service.
Whenever you trying to call an ajax call inside the controller, it will not fire the angular digest and hence the controller variables wont get updated.
The ideal way to go about it to have this in a factory and then call the factory method from the controller.
Code example:
appModule.factory('Search', function($rootScope, $http, $q) {
return {
var deferred = $q.defer();
$http.get('https://gist.githubusercontent.com/vigneshvdm/862ec5a97bbbe2021b79/raw/d7155b9c7fd533597c912fc386682e5baee1487a/associate.json').success(function(response) {
deferred.resolve({
data: response)};
});
return deferred.promise;
}
});
This code is using $q service inorder to make it more cleaner.Now just inject this factory (Search) into your controller and use it as is.

Why isn't my AngularJS $scope.$watch being triggered on service changes?

In my controller, I have:
var timespanServiceFn;
timespanServiceFn = function() {
return timespanService.getTimespan();
};
$scope.$watch(timespanServiceFn, $scope.updateVolume());
My $scope.updateVolume() function just has a console.log so that I know I got there.
My timespanService is also super simple:
myApp.service('timespanService', [
'$http', '$q', function($http, $q) {
var currentTimespan;
currentTimespan = '3M';
this.getTimespan = function() {
return currentTimespan;
};
this.setTimespan = function(timespan) {
console.log('setting timespan to', timespan);
return currentTimespan = timespan;
};
}
]);
So why is it that when I changed the timespan, the $watch doesn't get triggered?
The watch takes two functions as arguments. You must pass the second parameter as argument but you just called it there:
$scope.$watch(timespanServiceFn, $scope.updateVolume());
so the return statement of $scope.updateVolume() will be passed to $watch function instead of the function definition itself.
Just change it to:
$scope.$watch(timespanServiceFn, $scope.updateVolume);
See demo

angularJS data not available due to async call

This is my controller:
function TestCtrl ($scope, sharedProperties, $resource){
var userDataProfile = sharedProperties.getUserDataProfile();
var userCreatedBoard = $resource('/boards?owner=:owner');
userCreatedBoard.query({'owner':userDataProfile.id}, function (result) {
console.log(result);
});
}
Now problem is sharedProperties.setUserDataProfile() is called after calling a 3rd party service and its async. Hence, when the TestCtrl is bound, userDataProfile is effectively null. How do I handle this situation so that after the sharedProperties.setUserDataProfile() is called and variable has been assigned a value from 3rd party service, then only my controller should get bound?
I think you want to look at resolve:
http://www.youtube.com/watch?v=Kr1qZ8Ik9G8
This allows you to load all your data before instantiating your controller and firing a routeChangeSuccess event.
In the angular docs.
It does not make sense to pass variables into an Angular.js controller like that, that is what the Scope variable is meant for.
Try this
window.activeTestCtrls = [];
window.sharedProperties = [];
function TestCtrl ($scope, $resource){
if (window.sharedProperties) this.createUserData(window.sharedProperties)
window.activeTestCtrls.push[this];
function createUserData(sharedProperties) {
var userDataProfile = sharedProperties.getUserDataProfile();
var userCreatedBoard = $resource('/boards?owner=:owner');
userCreatedBoard.query({'owner':userDataProfile.id}, function (result) {
console.log(result);
}
});
// and when you get your sharedproperties
function gotSharedProperties(sharedProperties) {
$.each(activeTestControllers, function(index,value) {
activeTestControllers[index].createUserData(sharedProperties)})
}
}

Unset object property

I have a provider:
AdviceList.provider('$adviceList',function(){
this.$get = function ($rootScope,$document,$compile,$http,$purr){
function AdviceList(){
$http.post('../sys/core/fetchTreatments.php').success(function(data,status){
this.treatments = data;
console.log(this.treatments); // the correct object
});
this.adviceCategories = [
// available in the controller
];
}
return{
AdviceList: function(){
return new AdviceList();
}
}
}
});
Further, i have this controller:
AdviceList.controller('AdviceListCtrl',function($scope,$adviceList){
var adv = $adviceList.AdviceList();
$scope.treatments = adv.treatments; // undefined
});
Why is it, that the controller's $scope.treatments stays undefined, this.treatments inside the provider however, is filled correctly? Also, adviceCategories is available in my controller.
The call you get teatment is async in nature so the results may not have been populated when you try to assign them.
So here
var adv = $adviceList.AdviceList();
$scope.treatments = adv.treatments; //The treatments would only get filled after the server call is over.
You need to rewrite the code in a way that you assign it to your scope property on the success callback.
I will recommend you to simplify your code
1) Use simple factory method of angular instead of provider
2) return a promise to avoid using callbacks
AdviceList.service('adviceList', function ($http) {
return {
adviceList: function () {
return $http.post('../sys/core/fetchTreatments.php');
}
}
});
AdviceList.controller('AdviceListCtrl', function ($scope, $adviceList) {
adviceList.AdviceList().then(function (data) {
$scope.treatments = data //set value to data when data is recieved from server
});
});

Categories

Resources