regarding the question Passing data between controllers in Angular JS? I ran into the situation that my ProductService is executing some $http(RestFUL Service) and returns NULL because the callback function isn't completed.
Because the p.getProducts() function is evaluted and the callback function which fetches the data from the RestFUL service, is'nt complete the function returns always null.
app.service('productService', function() {
p = this
p.productList = [];
var addProduct = function(newObj) {
productList.push(newObj);
}
p.getProducts = function(){
return $http(RestFUL Service,function(data){p.productList.push(data)});
}
return {
addProduct: addProduct,
getProducts: return p.getProducts();
};
});
How can I solve this problem?
If you change your service to look more like this
return {
addProduct: addProduct,
getProducts: p.getProducts
}
then in controller you can make it work like that
app.controller('myCtrl', function ($scope, productService) {
var products = null
productService.getProducts().then(function(response){
//do something with data returned
})
})
your getProducts return $http which itself returns promise, that's why the I used then in controller
You must play with callback's. The http is an async operation, and for that reason you canĀ“t return a valid result right away. How invoke getProducts must set as parameter a function (callback) that will be invoked when http is completed - when data is available.
app.service('productService', function() {
p = this
p.productList = [];
var addProduct = function(newObj) {
productList.push(newObj);
}
p.getProducts = function(callback){
$http(RestFUL Service,function(data){
p.productList.push(data)
callback(data);//do something with data
});
}
return {
addProduct: addProduct,
getProducts: p.getProducts
};
}
//invoking
getProducts(function(products){
//do something with products
});
Related
I have the following code which fetches some data by implementing promises.
var TreeDataService = new DataService();
export default class TreeStore {
treeData = [];
getData() {
TreeDataService.get().then(data => {
this.treeData = data;
},
() => {
alert("Error fetching data");
});
return this.treeData; //this returns empty array instead of returning the data fetched from TreeDataService.get
}
}
How can I make return this.treeData execute only after the promise is fully resolved? I know I can put return this.treeData inside then's success method and return the entire getDatamethod as a promise, but that will require again resolving the promise at the call site of getData.
EDIT: I understand that as it's a async operation, I cannot synchronously execute the return statement and can instead return a promise. But then how do I resolve that promise at call site? I am facing the same issue at calling code:
export default class App extends React.Component {
treeData = TreeStoreObj.getData().then(data => {
return data;
}); // This will also execute asynchronously, so will be initially empty.
render() {
return (
<div className="app-container">
<TreeNode node={this.treeData} /> // So this will also be empty
</div>
);
}
}
Earlier code will now be:
export default class TreeStore {
treeData = [];
return getData() {
TreeDataService.get().then(data => {
return this.treeData = data;
},
() => {
alert("Error fetching data");
});
}
}
You are doing something strange. getData should not return any value at all if you are using mobx. It should set store observable only. React component will automatically rerender when this observable value change.
Are you using mobx-react? If so show your integration code. If not try to use it ;)
Async model does not allow you to execute return this.treeData after the promise is resolved. However, you might want to cache the promise not to invoke TreeDataService.get() several times.
For example (untested, just trying to show the main idea):
export default class TreeStore {
treeData = [];
treeDataPromise = null;
getData() {
if (this.treeDataPromise) return this.treeDataPromise;
this.treeDataPromise = TreeDataService.get().then(data => {
this.treeData = data;
return this.treeData;
},
() => {
alert("Error fetching data");
});
return this.treeDataPromise;
}
}
Another option is to check if this.treeData is loaded, and return Promise.resolve(this.treeData) if this is the case.
I am trying to delete a post from a list. The delete function is performing by passing serially to a delete function showed below.
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) { });
}
After performing the function, I need to reload the http.get request which used for listing the list.
$http.get("api/phone_accept.php")
.then(function (response) { });
Once the function performed. The entire list will reload with new updated list. Is there any way to do this thing.
Try this
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) {
//on success of first function it will call
$http.get("api/phone_accept.php")
.then(function (response) {
});
});
}
function list_data() {
$http.get("api/phone_accept.php")
.then(function (response) {
console.log('listing');
});
}
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) {
// call function to do listing
list_data();
});
}
Like what #sudheesh Singanamalla says by calling the same http.get request again inside function resolved my problem.
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref).success(function (data) {
//same function goes here will solve the problem.
});}
});
You can use $q - A service that helps you run functions asynchronously, and use their return values (or exceptions) when they are done processing.
https://docs.angularjs.org/api/ng/service/$q
Inside some service.
app.factory('SomeService', function ($http, $q) {
return {
getData : function() {
// the $http API is based on the deferred/promise APIs exposed by the $q service
// so it returns a promise for us by default
return $http.get("api/phone_recev.php?id="+ref)
.then(function(response) {
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
}, function(response) {
// something went wrong
return $q.reject(response.data);
});
}
};
});
function somewhere in controller
var makePromiseWithData = function() {
// This service's function returns a promise, but we'll deal with that shortly
SomeService.getData()
// then() called when gets back
.then(function(data) {
// promise fulfilled
// something
}, function(error) {
// promise rejected, could log the error with: console.log('error', error);
//some code
});
};
I have the following controller:
public class UserController : BaseApiController
{
// GET api/<controller>
public string Get()
{
var currentuser = CurrentUser.Name;
return currentuser;
}
}
The value of currentuser I pass it the datacontext in this way:
function getName() {
var deferred = $q.defer();
var promise = deferred.promise;
cachedPromises.currentuser = promise;
$http.get(baseUrl + 'api/user').success(getSucceeded).error(getFailed);
return cachedPromises.currentuser;
function getSucceeded(data) {
console.log('data:', data);
}
function getFailed(parameters) {
console.log("failed", parameters);
}
}
On the console log console.log('data:', data); I get the value and in order to apply binding I have to pass this value to the scope in the controller.js. In order to do that, I have done a controller in this way.
LogName.$inject = ['$scope', 'datacontext']
function LogName($scope, datacontext) {
$scope.name =[];
datacontext.getName().then(function (currentuser) {
$scope.name = currentuser;
});
}
And on the view I have the following code for data binding :
<h1 ng-controller="LogName" class="title">{{name}}</h1>
The binding is shown as an empty array, and I don't understand what goes wrong .
EDIT:
When I do a console log on the controller:
datacontext.getName().then(function (currentuser) {
$scope.name = currentuser;
console.log('current', currentuser);
});
Nothing appears on the view, the compiler does not reach the datacontext.getName
You MVC controller returning string public string Get() and you declare $scope.name =[]; as array change it to $scope.name =''; that should helps
and change your function getName to :
function getName() {
var deferred = $q.defer();
$http.get(baseUrl + 'api/user').success(getSucceeded).error(getFailed);
return deffered.promise;
function getSucceeded(data) {
console.log('data:', data);
//add this
deferred.resolve(data);
}
function getFailed(parameters) {
console.log("failed", parameters);
deferred.reject(parameters);;
}
return deffered.promise;
}
You are never resolving your promise to provide the name. Add a resolve to the getSucceeded function and a reject to the error function.
function getSucceeded(data) {
console.log('data:', data);
promise.resolve(data);
}
function getFailed(parameters) {
console.log("failed", parameters);
promise.reject(parameters);
}
This will provide the data to the functions that are waiting on the promise results.
There are two issues:
Firstly, you are not resolving the promise. You need to resolve your promise with your data that is returned from the server.
Second, the result is actually in the results property of the data that is returned from the server. Here as you are retrieving only name, you should use below code:
function getSucceeded(data) {
console.log('data:', data);
deferred.resolve(data.results[0]);
}
I have a function which is going to make a REST call, but it cannot do this until an auth token has been fetched.
So I wrapped the REST call in the 'then()' of the auth token call's promise, like so:
var RESTCall = function() {
return authTokenPromise.then(function() {
return $http.get('userService' {
userId: 1234,
someFlag: true
});
});
};
This has the result of waiting to fire off the call to the userService until the authToken promise (from the service that gets the auth token) has resolved.
The problem comes when I try to remove the hard-coded params that set userId and someFlag. What I want to do is this:
var RESTCall = function(params) {
return authTokenPromise.then(function() {
return $http.get('userService' {
userId: params.userId, // params is undefined
someFlag: params.flag // params is undefined
});
});
};
How do I pass params into the anonymous function scope created by then(function() {...})?
i have a factory am passing it to controller LoginCtrl
.factory('Fbdata', function(){
var service = {
data: {
apiData: []
},
login: function () {
facebookConnectPlugin.login(["email"],
function() {
facebookConnectPlugin.api("me/?fields=id,email,name,picture", ["public_info","user_birthday"],
function (results) {
service.data.apiData = results;
console.log(service.data.apiData);
return results;
},
function (error) {
console.error('FB:API', error);
});
},
function(err) {
console.error('FB:Login', err);
});
}
};
return service;
})
LoginCtrl:
.controller('LoginCtrl', function($scope, Fbdata){
$scope.login = function(){
if (!window.cordova) {
var appId = "appId";
facebookConnectPlugin.browserInit(appId);
}
$scope.loginData = Fbdata.login();
console.log(Fbdata.data.apiData);
// got empty array []
$scope.retVal= angular.copy(Fbdata.data.apiData);
};
})
the Fbdata.data.apiData return empty array and i only could see the returned data from the login success function in the console .
my template which is has LoginCtrl as controller:
<div class="event listening button" ng-click="login();">Login with Facebook</div>
<h2>{{loginData.name}}</h2>
<h2>{{retVal.name}}</h2>
There is a variety of ways to achieve this, example:
Now I have never used Cordova Facebook Plugin so I'm not sure if you need to run the api function after the log in, or how those procedures need to be ordered. But I wanted to show you an example of how to retrieve the data from the factory using your code sample. Hope that helps
Edit 2:
I have changed my code to using promises that way we make sure that we don't call one without the other being completed, I am not a fan of chaining the login and api functions within one function since it is possible(?) that you may need to call login() but don't want to call api(), please try my code and paste in your console logs in the bottom of your question.
Factory:
// Let's add promises to our factory using AngularJS $q
.factory('Fbdata', ['$q', function($q){
// You could also just replace `var service =` with `return` but I thought this
// would make it easier to understand whats going on here.
var service = {
// I generally nest result to keep it clean when I log
// So results from functions that retrieve results are stored here
data: {
login: [],
api: []
},
api: function() {
var q = $q.defer();
facebookConnectPlugin.api("me/?fields=id,email,name,picture", ["public_info","user_birthday"],
function (results) {
// assign to the object being returned
service.data.api = results;
// The data has returned successfully so we will resolve our promise
q.resolve(results);
},
function (error) {
// We reject here so we can inform the user within through the error/reject callback
q.reject(error);
console.error('FB:API', error);
});
// Now that we have either resolved or rejected based on what we received
// we will return the promise
return q.promise;
},
login: function () {
var q = $q.defer();
facebookConnectPlugin.login(["email"], function (results) {
// assign to the object being returned
service.data.login = results;
q.resolve(results);
}, function(err) {
q.reject(error);
console.error('FB:Login', err);
});
return q.promise;
}
};
return service;
}])
Controller:
.controller('LoginCtrl', function($scope, Fbdata){
$scope.login = function(){
if (!window.cordova) {
var appId = "appid";
facebookConnectPlugin.browserInit(appId);
}
// By using the promises in our factory be can ensure that API is called after
// login by doing the following
// then(success, reject) function allows us to say once we have a return, do this.
Fbdata.login().then(function () {
$scope.loginData = Fbdata.data.login;
// Check what was returned
console.log('loginData', $scope.loginData);
Fbdata.api().then(function () {
$scope.apiData = Fbdata.data.api;
console.log('apiData', $scope.apiData);
}, function () {
// Tell the user that the api failed, if necessary
});
}, function () {
// Tell the user that the log in failed
});
};
});