I use cordova and ionic for my mobile application.
I trying to use $http.get() for loading a JSON web service, so I wrote this code :
.controller('loading', function ($scope, $state, $http) {
var loadedService = {
news: false,
users: false
};
$http.get('http://{url}/users')
.success(function (result) {
loadedService.users = result;
});
I want to change the loadedService.users to returned result from webservice.
But when I trying to console.log(loadedService.users) I will get false (the default value for this variable).
What should I do?
$http.get, or javascript in general is asynchronous. Put console.log inside the success callback of http.get, you will see that (hopefully), you are getting correct results there. But if you put console.log after the get call, you will see the false output since your get call is still busy but your js keeps running. Long story short, js is asynchronous.
Related
I'm working on a Meteor project and want to get the return value of Meteor.call in template helpers on client side. At very first, I just set a variable in the call back function and get the variable's value outside the Meteor.call. I found out the code after Meteor.call doesn't execute at all. Then I searched a bit and use Session, it works. But I don't really understand the reason. Here's my original code and modified code. Can anyone explain a bit for me? Thanks!!
Original wrong code: html
<div id="text-result-main">
<h2>{{title}}</h2>
</div>
js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
console.log(titles);
return titles;
}});
Collection text.js
Text = new Mongo.Collection("text");
Meteor.methods({
'getTitle': function(myindex){
return Text.findOne({index: myindex}).title;
}});
The working code: js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
Session.set("titles",result);
});
console.log(Session.get("titles"));
return Session.get("titles");
}});
Notice that I didn't publish Collection Text to the client at all because it's just so huge. Every time when I refresh the page when running the wrong code, I can't see the content of "title" or see it on the console. But when I set the session, it works. I don't really understand how it works here. Thanks
There is two issues Asynchronicity and Reactivity
This affectation
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
inside the meteor call is executed but in a asynch way. So the return of your helper is immediately called, and return a empty value.
Try it out in the console of your browser.
But then, why your template render correctly with {{title}} when you use a Session Variable ?
It's because the Session is a reactive data source, witch means that every change to it trigger a re-computation of all templates involving this piece of data.
Here is a timeline:
Methods is called
Return empty value
Method is executed, setting variable value
If the Variable is a reactive data source, template is re-computed. ( in your case, the session is a reactive data source. )
To go further
I would use a reactive var in that case, it's very close from a session variable, but the scope is limited to a template.
A good read on Reactive data source: http://richsilv.github.io/meteor/meteor-reactive-data-types/
The problem is the fact that Meteor.call() is asynchronous when paired with a callback.
So when title() starts executing, it does not wait for your Meteor.call() invocation to return a result (or possibly an error). It continues execution. This is called asynchronous execution.
In short, you are trying to log the value for the key titles which doesn't exist in Session (since the state of your asynchronous Meteor call is unknown, at this point of time).
Try moving the console log statement into the callback paired with your Meteor.call() and you can see the result once it has successfully been set in Session.
A workaround to your problem is to make your Meteor.call() synchronous like this:
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
var result = Meteor.call('getTitle', index); // <--- this is synchronous code now
Session.set("titles",result);
console.log(Session.get("titles"));
return Session.get("titles");
}});
Removing the callback makes Meteor.call() behave synchronously.
If you do not pass a callback on the server, the method invocation
will block until the method is complete. It will eventually return the
return value of the method, or it will throw an exception if the
method threw an exception.
(from http://docs.meteor.com/api/methods.html#Meteor-call)
Why not use something like this:
title: function(){
var index = Router.current().params.index;
var a = Text.findOne({index: myindex}).title;
console.log(a);
return a;
without methods
I have some controller and a function called to obtain some value from a REST WCF web service:
fooBar.controller('fooCtrl',
function fooCtrl($scope, $http, $resource) {
$scope.someOnClickEvent = function () {
GetSomething('a','b','c');
}
}
);
function GetSomething($scope, $resource, a, b, c) {
var ServiceHandle = $resource('some/addr');
var serviceHandle = new ServiceHandle();
serviceHandle.a = a;
serviceHandle.b = b;
serviceHandle.c = c;
serviceHandle.$save().then(function (result) {
console.log('So response should be ready');
$scope.result = result.ValueFromService;
});
}
As far as I know $save() returns promise and function inside .then should be called right after response is returned by the server. In my case it's called imediately.
If service returns true I'm going to show some popup, so I need this value to be returned before conditional instruction is executed.
Version of Angular is 1.4.9.
I've analysed code and its behavior and I'm wrong obviously. Maybe I should delete this question, but I believe it can help someone to understand similar problems.
Function inside .then is in fact called after a response comes from the server. It can be verified using for instance Chrome's developer tools (namely tab network).
However if just after calling GetSomething function we want to access a $scope.result we are making a great mistake. $scope.result will be undefined as long as function inside .then won't be executed. To use a value returned from a service we must do it inside .then function or in a function called by it.
I'm having a issue where calling the $http request is not updating the DOM for jQuery function call.
Please check the Plunker
In my code script.js, for testing purpose I have $scope.components both as global and in a function.
But when i hardcoded the json value to the global variable everything works fine. when i get the json as a $http response, the expand and collapse functionality of tree structure stops working.
Below is my code for $http request
$scope.init = function init() {
$http.get('treeData.json').success(function(data) {
$scope.components = data;
}).error(function(data) {
});
};
Please let me know what am i doing wrong here.
Its because your jQuery code is getting executed before getting the data from treedata.json. $http will create a promise so move you jQuery logic after promises is getting resolved.
I have updated the plunker.
[http://plnkr.co/edit/XuxO29FZUoXf84nVvjrg?p=preview][1]
You should define components first,like below:
$scope.components = [];
Look like the data coming back from the server is not in JSON format. By default $http.get accept JSON return type. Due to this your success function is not getting executed.
Update
You can check the angular documentation for using $http. The recommend way is to use get is as shown below.
$http.get('/someUrl', config).then(successCallback, errorCallback);
try $scope.$apply(
$scope.components = data
);
I'm currently working on an angular application i'll post some sample code here.
In My Service i have a method that access a rest api via $resource:
function getData() {
resource.get({}, function success(data) {
return data;
}, function error() {
console.log('error')
})
}
Now over in a controller that has been injected with the service i attempt to use the data with some conditions from the previous page that are passed through as a routeParameter as follows:
$scope.data = MyResource.getData()
$scope.editingObject = angular.copy($scope.data[$routeParams.objIndex])
On my view i would like to bind to $scope.editingObject but since that code executes immediately and the data may not have arrived back from the server i receive the following error:
TypeError: Cannot read property '0' of undefined
Now i understand that i cannot access the array before the data has arrived back from the server but my question is more about how do i construct this service in such a way that i can access that data?
To resolve this issue i have attempted to place a watch on $scope.data and monitor for the data to arrive but it never fires when the data does arrive. i have confirmed this using console.log in a set timeout to check after a few seconds if the data has arrived at which point it has... and the object is updated to reflect this.
Could anyone please point me in the right direction regarding services, resources and accessing the data?
I would like to see the $watch() code because it should fire when data is received. But anyways, you should use the promise returned from service:
MyResource.getData().then(function(data) {
$scope.data = data;
$scope.editingObject = angular.copy($scope.data[$routeParams.objIndex])
});
So here is what I need to do. I'm using the Angular Deferred Bootstrap library in my code because I need to receive some essential data from a RESTful server before bootstrapping and trying to load the content. Anyway, I must make a second call once the first call resolves. The second call is a login that depends on some URL that is contained in the first response.
Right now, I want to try to make the login call once I receive that data (I was trying in the .success() block) but once the first call resolves, the program begins bootstrapping before the login call is finished; things break because I'm not "logged in" on the server.
window.deferredBootstrapper.bootstrap({
element: window.document.body,
module: 'app',
resolve: {
STARTUP_CONFIG: ['$http', function($http) {
return $http.get(url1 + 'blah/blah/blah/' + layout);
}],
CONTEXT_CONFIG: ['$http', function($http) {
return $http.get(url1 + 'blah/blah/blah/blah').
success(function(data) {
$http.post('https://' + data.url2 + '/10001/guestidentity?client_id=' + data.id).
success(function(result){
token = result.token;
});
});
}],
}
});
Anyone have any idea what I can do?
hi since this is a promise you can chain the next call to the then function something like
$http(url).
then(function(response){
//note that this shouldn't be the body of the response
// but the entire response stream so you need to check for the status code and the body and apply and possibly apply any transformation that is needed as it will probably be just text
// then we can start the other call
return $http(url);
})
this way the second promise will be handled to the final destination.