Update multiple views - javascript

I am trying to update views on multiple components. For that reason I am using broadcast. If I use my code without the $apply() the views are not updating. If I use apply on multiple views I am getting '[$rootScope:inprog] $apply already in progress' error.
Changed code
service.prototype.setNewTopic = function (topic) {
var self = this;
var promise = $http(
{
method: 'POST',
url: self.baseUrl + 'Admin/setNewTopic',
contentType: 'application/json',
data: {
topicName: topic
}
});
return promise;
}

I changed to how your $on method behaves, it should recive the data from the $broadcast and I guess set it appropriately in the component.
// controller - I assume the $scope property in the controller is called $scope.newTopic
service.setNewTopic($scope.newTopic).then( function(data) {
$rootScope.$emit('testMonitor',$scope.newTopic)
})
// one of these per listening component
$rootScope.$on('testMonitor', function(data) {
$scope.newTopic = data;
});
I changed the service to only do http work
// service
service.prototype.setNewTopic = function (topic) {
return $http(
{
method: 'POST',
url: self.baseUrl + 'Admin/setNewTopic',
contentType: 'application/json',
data: {
topicName: topic
}
});
}

Related

Accessing outer response data in nested $http call

Pardon as I am new to AngularJS.
I have the following nested $http call,
$http({
method: 'GET',
url: host1,
params: {
'format': 'json',
}
}).then(function successCallback(response) {
for (var i = 0; i < response.data.length; i++) {
$http({
method: 'GET',
url: response.data[i]['url'] + "packet-trace/base",
params: {
'format': 'json',
}
}).then(function successCallback(response2) {
//Retrieve some information from first $http call
var doSomething = response.data[i]['information'];
var doSomething2 = doSomething + response2.data['information'];
}, function errorCallback(response2) {
//Error
});
}
}, function errorCallback(response) {
//Error
});
I need to retrieve data from the first $http call, and then retrieve data from the $http, and use both of these data as part of my logic. However, I am unable to access the data from the first $http call. The loop counter 'i' always equal the length of response.data.
How can I access the first the data of $http call?
Additionally, are there any specific coding conventions or specific API I can use to call $http sequentially? Nesting $http calls gets messy and difficult to maintain.
Thanks.
The reason why this happens is because the loop probably has finished iterating before the AJAX call succeeds. At this stage i will obviously equal response.data.length.
You could capture the value outside the AJAX call and then use it in the success callback so that you don't depend on the i variable inside the callback:
for (var i = 0; i < response.data.length; i++) {
// Capture the value you need here
var someValue = response.data[i]['information'];
$http({
method: 'GET',
url: response.data[i]['url'] + "packet-trace/base",
params: {
'format': 'json',
}
}).then(function successCallback(response2) {
// Use the captured value from the first call here
var doSomething = someValue;
var doSomething2 = doSomething + response2.data['information'];
}, function errorCallback(response2) {
//Error
});
}
Well that is because of asynchronous nature of javascript. I suggest using async for your use case. May look a bit complex, but once you understand async concepts, it is breeze to use. This what you can do:
async.waterfall(
[
function(callback){
$http({
method: 'GET',
url: host1,
params: {
'format': 'json',
}
}).then(function successCallback(response) {
callback(null, response);
});
},
function(callback, response){
async.times(response.data.length, function(i,next){
$http({
method: 'GET',
url: response.data[i]['url'] + "packet-trace/base",
params: {
'format': 'json',
}
}).then(function successCallback(response2) {
//Retrieve some information from first $http call
var doSomething = response.data[i]['information'];
var doSomething2 = doSomething + response2.data['information'];
next(null,doSomething, doSomething2);
}, function errorCallback(err) {
next(err, null);
});
});
}
],
function(err,doSomethingArr, doSomething2Arr){
// get your arrays here
});

Angular $scope is setting value first than service, after second function call everything fine

I'm trying to set data to controller using my service viewShare, when i look to my console i can see the console.log of controller coming first and undefined but the services started first the strange is after this console.log, i can see the console.log from viewShare populated. If i try the function in controller again then my controller is populated correctly.
my controller:
$scope.getLine = function(search){
arcTouchAPI.getLine(search);
console.log(viewShare.getDetails);
$scope.details = viewShare.getDetails.details; //angular ignores my viewShare call and go to console.log($scope.details) than it start the viewShare service
$scope.$apply;
console.log($scope.details);
};
my service API:
var _getLine = function(search){
var encoded = $base64.encode("xxxx:xxxx");
$http({
url: "https://api.appglu.com/v1/queries/findRoutesByStopName/run",
headers : {
"X-AppGlu-Environment":"xxxx",
"Authorization": "Basic "+encoded,
"Content-Type" : "application/json; charset=utf-8"
},
method: 'POST',
data: {
"params":{
"stopName": "%"+search+"%"
}
}
}).then(function(response){
viewShare.add(response.data.rows);
// console.log($rootScope.details + "details");
console.log(response.data.rows);
});
}
return {
getLine : _getLine
}
});
my service to share data between views:
angular.module('myApp').factory('viewShare', function viewShare() {
var messages={};
var _add = function(message){
messages.details = "";
messages.details=message;
console.log(messages.details);
return messages.details;
};
var _getDetails = function(){
return messages;
};
return{
getDetails: messages,
add: _add
}
});
$http call is non-blocking, which means that your console.log is executed straight after your request is sent to getLine (as coded), however this does not wait for the $http call to finish, and therefore has no data right away. You should return the $http promise from _getLine, and wait for the promise to resolve, before trying to getDetails. Furthermore, an explicit call to $scope.$apply is not necessary.
var _getLine = function(search){
var encoded = $base64.encode("xxxx:xxxx");
return $http({ // add return statement here to return a promise
url: "https://api.appglu.com/v1/queries/findRoutesByStopName/run",
headers : {
"X-AppGlu-Environment":"xxxx",
"Authorization": "Basic "+encoded,
"Content-Type" : "application/json; charset=utf-8"
},
method: 'POST',
data: {
"params":{
"stopName": "%"+search+"%"
}
}
}).then(function(response){
viewShare.add(response.data.rows);
// console.log($rootScope.details + "details");
console.log(response.data.rows);
});
}
Change controller to:
$scope.getLine = function(search){
arcTouchAPI.getLine(search).then(function(){
console.log(viewShare.getDetails);
$scope.details = viewShare.getDetails.details;
});
};

AngularJS Toaster does not show on callback

I'm using AngularJS Toaster to show toast messages. But i can't seem to get it working with a result from a callback, and i REALLY don't know why.
I've created a service for Toaster:
service.factory('$toasterservice', ['toaster',
function (toaster) {
return {
'show': function (type, title, text) {
return toaster.pop({
type: type,
title: title,
body: text,
showCloseButton: false
});
}
};
}]);
This piece of code is in my controller:
$scope.submit = function (db) {
var params = {
username: db.credentials.username,
password: db.credentials.password,
database: db.name,
hostname: db.host,
port: db.port
};
$dbservice.testConnection(params, function (response) {
if (response.error)
{
console.log(response.error)
}
else
{
console.log('correct!');
}
});
};
whenever i put this line of code:
$toasterservice.show('error', 'TITLE', 'BODY');
within controller level scope, it works perfectly fine.
When ever i try to use it in:
$dbservice.testConnection(params, function (response) {
//HERE $toasterservice.show('error', 'TITLE', 'BODY');
});
it doesn't work, how can i solve this? i can't seem to understand why this is happening.
$dbservice :
service.factory('$dbservice', ['$constants',
function ($constants) {
return {
'testConnection': function (params, callback) {
$.ajax({
url: $constants.URL_TEST_CONNECTION,
dataType: 'json',
type: 'post',
contentType: 'application/x-www-form-urlencoded',
data: params,
success: callback,
error: callback
});
}
};
}]);
The problem is using $.ajax and you should switch to using $http.
Any events that occur outside of angular core that change the scope need to notify angular so it can run digest in view.
You can call $scope.$apply() in the callback of your $.ajax to run digest

AngularJS resolve an AJAX request with arbitrary data w/o making an AJAX call

I have a service that calls a URL for fetching details of a user.
...
this.getUserDetail = function (userId) {
// deal cache
var request = $http({
method: "get",
url: "/users/"+userId
});
return request.then(successFn, errorFn);
};
But at another place, I am fetching the user details too and creating a map of newly fetched users. I want to reuse an already fetched user from my JavaScript object.
this.getUserDetail = function (userId) {
if (userMap[userId]) {
return $q.resolve({
'result': userMap['userId']
});
}
var request = $http({
method: "get",
url: "/users/"+userId
});
return request.then(successFn, errorFn);
};
But this doesn't work. I have included $q. I don't get JavaScript errors, except that at a place where I am using this.getUserDetail(userId).then(..., it throws error, as I am may be not returning a succesFn from the way I am doing it.
Am I doing it properly?
The function that you call is using AJAX.
Now from your question, since you are using then, this.getUserDetail(userId).then(), it means getUserDetail must return a promise itself.
Now if I understand it correctly, you want to resolve a promise with random data, without making AJAX call when an item is cached.
In that case, make your function to conditionally use promise object.
this.getUserDetail = function (userId) {
var cachedUser = userMap(userId),
deferredData = $q.defer();
var request = cachedUser ? deferredData.promise : $http({
method: "get",
url: "/users/" + userId
});
if (cachedUser) {
deferredData.resolve({
'data': {
'result': cachedUser
}
});
}
return request.then(successFn, errorFn);
};
Edit:
And then use it in your controller as:
this.getUserDetail.then(function(response){
// this response object is same object with which
// promise was resolved.
// Doesn't matter whether the promise was AJAX or your own deferred.
});
Doesn't matter whether the promise was AJAX or your own deferred.
You can use AngularJs built in cache:
var request = $http({
method: "get",
url: "/users/"+userId,
cache: true
});
this.getUserDetail = function (userId) {
if (userMap[userId]) {
return $q.when(userMap[userId]);
} else {
return $http({
method: "get",
url: "/users/"+userId
})
.then(function (result) {
// add to userMap;
return result;
});
}
};

setup $http url from .properties file in angularjs

I have some services in my App.
loginApp.factory('urlService', function() {
return {
baseUrl : function(){
return 'http://localhost:8080/myAppName'
}
}
});
consume this service by one another services.
loginApp.factory('loginServices', function($http,urlService) {
return {
loginAuth : function(aut,resp){
return $http({
method: 'GET',
url: urlService.baseUrl()+'auth',
}).success(function(result) {
return result;
});
}
}
});
I want configure http://localhost:8080/myAppName from a .properties file which is present on application root.
You can do some thing like this
angular.module('app.properties', []).provider('properties', function() {
var resource;
$.ajax({
url: 'properties.json',
dataType: 'json',
async: false,
success: function(data) {
resource = data;
}
});
this.properties= resource;
this.$get = function() {
return this.properties;
};
});
Then use this provider in you controller/services to access the properties
angular.module('loginApp', ['app.properties']).factory('urlService', function(properties) {
return {
baseUrl : function(){
return properties.baseUrl;
}
}
});
And your properties.json should be like
{
"baseUrl" :"http://localhost:8080/myAppName"
}
NB : I have used jquery ajax to load the properties.json because it should not be an async call, so I set async: false
$.ajax({
url: 'properties.json',
dataType: 'json',
**async: false**,
success: function(data) {
resource = data;
}
});
I think the best option in that case would be to create a service that then can be injected and in that service pull the config file and assign content to a returned variable (hope it makes sense so far)
Although that will leave you with possible race issues when i.e. your loginService will be called before config was loaded but if you make a good use of promises all this will be trivial for you

Categories