AngularJS - $watch not working - angularjs

Scenario: Integrated Stomp with our Angular. On user login, calling a stomp service which sends data and then fetching the same in module controller.
Stomp Service
var wrappedSocket = {
init: function(url) {
stompClient = Stomp.over(new SockJS(url));
},
connect: function(successCallback, errorCallback) {
stompClient.connect({}, function(frame) {
//$rootScope.$apply(function() {
$timeout(function () {
successCallback(frame);
});
}, function(error) {
//$rootScope.$apply(function(){
$timeout(function () {
errorCallback(error);
});
});
},
subscribe : function(destination, callback) {
stompClient.subscribe(destination, function(message,headers) {
//$rootScope.$apply(function(){
$timeout(function () {
callback(message,headers);
});
});
},
send: function(destination, headers, object) {
stompClient.send(destination, headers, object);
}
}
return wrappedSocket;
Module Controller
var initializing = false;
$timeout(function () {
alert('timeout');
$scope.$watch(svc.getMessage, function (v) {
if (initializing) {
$timeout(function () { initializing = false; });
} else {
if (v != '') {
console.log(v);
$scope.notifications = v;
$scope.notification_count = $scope.notifications.length;
}
}
});
}, 3000);
Here svc is an instance of Sockjs svc.setMessage($scope.messages);
Eventually changed $rootScope.$apply(function() { to $timeout(function () { in service. But later figured out in module controller, $watch is not working/calling.
Expected Result - Stomp message should be fetched inside $watch
Whats happening - $watch not called leading to no stomp message being displayed.
How do I call function inside $scope.$watch(svc.getMessage,
function (v) ?
Alternative solution for $watch that works every time ?

Related

Angular $http issues and promises issues

I am Not able to pass Id in my modal which makes me impossible to pass data
Controller.js
app.controller('faq', function ($scope, faqservice, $ionicModal) {
$scope.faq = faqservice;
console.log($scope.faq); //upto this everything i working properly and i am able to render in my HTML page !
$ionicModal.fromTemplateUrl('templates/faqDetails.html', {
scope: $scope
}).then(function (modal) {
$scope.faqDetails = modal;
});
// Triggered in the FAQ detail modal to close it
$scope.faqClose = function () {
$scope.faqDetails.hide();
};
// Open the FAQ detail modal
$scope.faqOpen = function (id) {
$scope.faqDetails.show();
$scope.notes = faqservice.getid(id);
console.log($scope.notes); //**i am geting this null.. and when i console.log() in getID method in service my for loop is not executing **
};
});
Service.js
app.service("faqservice", function ($q, $http,Events,$ionicPopup) {
var self = {
'results': [],
getid: function (id) {
for (var i = 0; i < self.results.length; i++) {
if (self.results[i].id === parseInt(id)) {
return self.results[i];
}
}
return null;
},
'load': function () {
$http.get(Events.url +"/faqs")
.then(function (response) {
angular.forEach(response.data, function (data) {
self.results.push(data);
window.localStorage.setItem("faqs", JSON.stringify(data));
});
}
,function (data) {
$ionicPopup.alert({
title: 'Slow Internet connection',
template: 'Please check your internet connection for updates !'
});
if (window.localStorage.getItem("faqs") !== undefined) {
self.results.push(JSON.parse(window.localStorage.getItem("faqs")));
}
});
}
};
self.load();
return self;
});
*my error callback is not working when my internet connection is off! i am not getting error notifications whrn my internet connection is off *
I am Getting My $scope.notes null pls help me with this issue !!
and I am really new to Angular.js and ionic so can u pls suggest me what to
use success() or then() while working with HTTP ?
And what if You console.log(self.results.length) just before for loop ?
And i think success() method of $http is deprecated.

Not receiving data in controller in Cordova Angular Ionic app

I have the following controller:
.controller('GitCtrl', function ($scope, $http, Chats) {
$scope.search = function () {
$id = 1;
$scope.repos = Chats.all($http);
$scope.repos2 = Chats.get($id);
}
})
The only thing which does not work when I click a button which invokes the search function is Chats.all, which comes from the following service (along with Chats.get):
.factory('Chats', function ($http) {
var chats = [{
id: 0,
name: 'Ben Sparrow',
lastText: 'You on your way?',
face: 'img/ben.png'
}, {
id: 1,
name: 'Max Lynx',
lastText: 'Hey, it\'s me',
face: 'img/max.png'
}];
return {
all: function () {
var user = $('#gitdata-input').val();
$http.get("https://api.github.com/users/" + user + '/repos').then(function (resp) {
console.log('Success', resp);
var repos = resp.data;
return repos;
}, function (err) {
console.error('ERR', err);
})
},
get: function(chatId) {
for (var i = 0; i < chats.length; i++) {
if (chats[i].id === parseInt(chatId)) {
return chats[i];
}
}
return null;
}
};
});
Chats.get and the chats array are merely for testing purposes.
I have verified that the service works, as I 'Succes' gets logged to my console and I also see that ver repos contains my data. In the controller however,$scope.repos stays undefined. $scope.repos2 does work. Then I noticed in the console that the Chats.all function from the service (in which I have a breakpoint) gets called AFTER $scope.repos2 is already filled with the result of Chats.get. So why is this? And is it also what is causing me to not receive the data from Chats.All in my controller?
while Chats.get() and Chats.remove() are synchronous, the function Chats.all() is asynchronous since it contains an http call, hence when you do:
$scope.repos = Chats.all($http);
You are basically returning undefined.
I would suggest you to use promises, hence changing your Chats.all() code to this:
all: function () {
return $q(function(resolve,reject) {
var user = $('#gitdata-input').val();
$http.get("https://api.github.com/users/" + user + '/repos').then(function (resp) {
console.log('Success', resp);
resolve(resp.data);
}, function (err) {
reject(err);
});
}
},
And the line in the controller as following:
Chats.all($http).then(function(data) {$scope.repos = data;});
Cheers!
The accepted answer is bad practice and should be avoided when possible.
An angular $http call is returning a promise and should not be wrapped in another promise ($q). It would suffice to return the promise of the $http call itself.
In short:
app.factory('Chats', function($http) {
return {
all: function(user) {
return $http.get("https://api.github.com/users/" + user + "/repos")
.then(function(resp) {
return resp.data;
}, function(err) {
console.log('ERR', err);
});
}
};
});
should do the trick. (See plunker) and surely do read why wrapping promises in promises should be avoided here.

Angular + Play Framework. When calling $http inside $scope.function server receives null

I'm facing the following problem with Play Framework and AngularJs. I'm trying to send an json object to my play controller but when I called the http request inside a scope function on my angular controller the server receives null. If I put the http call outside the scope function the server receives the json just fine. I appreciate any help guys
=== Scope Function ===
$scope.addComment = function () {
$scope.userComment = {};
$scope.userComment.client = $scope.client;
$scope.userComment.description = $scope.comment;
//Here is made the request to my server. If I put this piece of code out of
//this scope function works fine
ClientRepository.addComment($scope.userComment).then(function (response) {
$scope.comment = '';
$scope.client.contactsClientHistory.unshift(response);
$scope.tableComments.total = $scope.client.contactsClientHistory.length;
$scope.tableComments.reload();
});
}
=== On My Play Controller ===
public static Result addComment() {
try {
JsonNode request = request().body().asJson(); // Returns null
....More code here
=== Client Repository ===
'use strict';
define(['app', 'AbstractRepository'], function (app) {
app.factory('ClientRepository', ['Restangular', 'AbstractRepository', function (restangular, AbstractRepository) {
function ClientRepository() {
AbstractRepository.call(this, restangular, 'client');
this.addComment = function (newResource) {
return this.restangular.all(this.route + "/comment").post(newResource);
}
}
AbstractRepository.extend(ClientRepository);
return new ClientRepository();
}]);
});
=== AbstractRepository ===
'use strict';
define(['app', 'Alert'], function (app) {
app.factory('AbstractRepository', [ 'Alert', function (Alert) {
function AbstractRepository(restangular, route) {
this.restangular = restangular;
this.route = route;
restangular.setErrorInterceptor(function (response, deferred, responseHandler) {
if (response.status == 400 || response.status == 500) {
Alert.handle(response);
} else if(response.status == 403){
Alert.error("commons.message.error.authFailure");
}
return true;
});
}
AbstractRepository.prototype = {
getList: function (params) {
return this.restangular.all(this.route).getList(params);
},
get: function (id) {
return this.restangular.one(this.route, id).get();
},
update: function (updatedResource) {
return updatedResource.put();
},
create: function (newResource) {
return this.restangular.all(this.route).post(newResource);
},
remove: function (id) {
return this.restangular.one(this.route, id).remove();
},
getPaginatedResult: function (params) {
return this.restangular.one(this.route).get(params);
}
};
AbstractRepository.extend = function (repository) {
repository.prototype = Object.create(AbstractRepository.prototype);
repository.prototype.constructor = repository;
};
return AbstractRepository;
}]);
});
It seam the problem was with the size of my json data. After I reduce the size of the json sent everything started working againg

Angular promise resolves inside function but not outside

I have a recursive function checking for some data every half second or so. The function returns a promise. Once I find the data, I want to resolve the promise and pass the data as the resolution. The problem is, the promise won't call .then() outside of the function. Here's the fiddle: http://jsfiddle.net/btyg1u0g/1/.
Here's the fiddle code:
Service:
myApp.factory('myService', function($q, $timeout) {
var checkStartTime = false;
var checkTimeout = 30000;
function checkForContent() {
var deferred = $q.defer();
// simulating an $http request here
$timeout(function () {
console.log("Checking...");
if (!checkStartTime) checkStartTime = new Date();
// this would normally be 'if (data)'
if ((new Date()) - checkStartTime > 3000) {
deferred.resolve("Finished check");
checkStartTime = false; // reset the timeout start time
} else {
// if we didn't find data, wait a bit and check again
$timeout(function () {
checkForContent();
}, 400);
}
}, 5);
// then is called in here when we find data
deferred.promise.then(function(message) {
console.log("Resolved inside checkForContent");
});
return deferred.promise;
}
return {
runCheck: function() {
return checkForContent()
}
}
});
Controller:
myApp.controller('MyCtrl', function ($scope, myService) {
$scope.name = 'Superhero';
// then is never called
myService.runCheck()
.then(function (message) {
console.log("Resolved outside checkForContent");
});
});
Check out this fiddle.
The outter $timeout function is named so it can be called from within itself.
$timeout(function inner() {
// ...
Then it is called recursively like this:
$timeout(function () {
inner();
}, 400);

Using WebSockets with AngularJS and $broadcast

I've setup an AngularJS app using websockets and it seems to be working. Here is a summary of whats going on:
var app = angular.module('websocketApp',[]);
app.factory('WebSocket',function($rootScope) {
var websocket = new WebSocket(websocket_url);
var items = [];
websocket.onmessage = function(msg) {
items.push(JSON.parse(msg.data));
$rootScope.$broadcast('new_message');
}
return {
fetchItems: function() {
return items;
}
}
});
app.controller('ItemsCtrl',function($scope,WebSocket) {
$scope.$on('new_message',function() {
$scope.$apply(function() {
$scope.items = WebSocket.fetchItems();
});
});
});
My question is if anyone else has setup an Angular app using websockets and if this implementation is the correct way to go about it or if there is a better solution. I've read many cons on using $broadcast but this seems to be the correct usage of the $broadcast functionality.
The way you have done it seems fine. An alternative way I do it though is to store an event/callback array, and register the events on it that I want to receive specifically.
For example:
angular.module('myapp.services.socket', [])
.factory('io', ['$rootScope', 'globals', function ($rootScope, globals) {
var socket;
var curChannel;
var eventCache = [];
function isConnected() {
return socket && socket.socket.connected;
}
function on(eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
}
function emit(eventName, data, callback) {
socket.emit(eventName, data, function () {
var args = arguments;
$rootScope.$apply(function () {
if (callback) {
callback.apply(socket, args);
}
});
});
}
return {
registerEvent: function(eventName, callback) {
eventCache.push({ name: eventName, cb: callback });
if(isConnected()){
on(eventName, callback);
}
},
emit: function (eventName, data, callback) {
// firstly check that the socket is connected
if(isConnected()){
emit(eventName, data, callback);
}else{
// connect to the server and subscribe upon connection
socket = io.connect(globals.api + ':80');
socket.on('connect', function(){
emit(eventName, data, callback);
// add the events from the cache
for(var i in eventCache){
on(eventCache[i].name, eventCache[i].cb);
}
});
}
}
};
}]);
This way, you can simply register event callbacks whenever you want, by injecting this service, and running:
io.registerEvent('some_event', function(){ /* some logic */ });

Resources