AngularJS - Strange behaviour of promises in connection with notify() - promise

As I want to implement a chat in AngularJS, I want to use the promise/deferred principle. My ChatService looks like the following:
factory('ChatService', ['$q', '$resource', function($q, $resource) {
var Service = {};
var connected = false;
var connection;
var chatResource = $resource('/guitars/chat/:action', {action: '#action'}, {
requestChatroomId: {
params: {
action: 'requestChatroomId'
},
method: 'GET'
},
sendMessage: {
params: {
action: 'sendMessage'
},
method: 'POST'
}
});
Service.connect = function(cb) {
var deferred = $q.defer();
chatResource.requestChatroomId(function(data) {
connection = new WebSocket('ws://127.0.0.1:8888/realtime/' + data.chatroomId);
connection.onerror = function (error) {
deferred.reject('Error: ' + error);
};
connection.onmessage = function (e) {
cb.call(this, e.data);
deferred.notify(e.data);
};
connected = true;
});
return deferred.promise;
};
Service.sendMessage = function(msg) {
if(!connected) {
return;
}
chatResource.sendMessage({message: msg});
}
return Service;
}])
My controller using the ChatService is:
app.controller('ChatCtrl', ['$scope', 'ChatService', function($scope, ChatService) {
$scope.chat = {};
$scope.chat.conversation = [];
var $messages = ChatService.connect(function(message) {
$scope.$apply(function() {
// #1 THIS FIRES EVERY TIME
$scope.chat.conversation.push(message);
});
});
$messages.then(function(message) {
console.log('Finishes - should never occur!')
}, function(error) {
console.log('An error occurred!')
}, function(message) {
// #2 THIS FIRES ONLY IF THERE IS AN INTERACTION WITH THE ANGULAR MODEL
console.log(message);
});
$scope.sendMessage = function(event) {
ChatService.sendMessage($scope.chat.message);
$scope.chat.message = '';
};
}]);
If something is pushed from the server, callback #1 is called, but callback #2 wont be called until there is some interaction with the angular-model, i.e. start writing something in the input-Box. What is the reason for that behaviour?

Okay the reason was, that AngularJS was not aware of a change. So I injected the $rootScope to my ChatService:
factory('ChatService', ['$q', '$resource', '$rootScope', function($q, $resource, $rootScope) {
and in connection.onmessage I called $apply() on $rootScope:
connection.onmessage = function (e) {
deferred.notify(e.data);
$rootScope.$apply();
};

Related

onsen ui2 - master detail page with angularjs

how can i create a master detail page with angularjs. I created a factory which calls the data from a json file then created a list controller to list the title for the list items but when i reach the view controller im getting an error. an example of the code is below
var cachedData;
function getData($scope, callback) {
$http.get('js/husbandry.json').success(function(data) { // call data from json file
$scope.items = data.items;
callback(data.items);
console.log(data);
}).error(function() {
ons.notification.alert({
message: 'Could not Connect to the Database.'
});
});
}
return {
list: getData,
find: function(data, callback) {
var hb = cachedData.filter(function(items) {
return items.title == data;
})[0];
callback(hb);
}
};
});
module.controller('ListCtrl', function($scope, HB) {
$scope.items = {
title: 'day 2'
}
HB.list($scope.items.title, function(items) {
$scope.items = items;
});
$scope.showDetail = function(title) {
$scope.navi.pushPage("day1.html", { animation: "fade", items: title });
}
});
module.controller('ViewCtrl', ['$scope', 'HB', function($scope, HB) {
var page = $scope.navi.topPage.data;
HB.find(page.options.data, function(hb) {
$scope.items = hb;
});
}]);

How can I handle a ajax request response in the Flux Architecture?

Looking at the Flux Documentation I can't figure out how the code to a ajax update, and a ajax fetch would fit into the dispatcher, store, component architecture.
Can anyone provide a simple, dummy example, of how an entity of data would be fetched from the server AFTER page load, and how this entity would be pushed to the server at a later date. How would the "complete" or "error" status of request be translated and treated by the views/components? How would a store wait for the ajax request to wait? :-?
Is this what you are looking for?
http://facebook.github.io/react/tips/initial-ajax.html
you can also implement a fetch in the store in order to manage the information.
Here is an example (it is a concept, not actually working code):
'use strict';
var React = require('react');
var Constants = require('constants');
var merge = require('react/lib/merge'); //This must be replaced for assign
var EventEmitter = require('events').EventEmitter;
var Dispatcher = require('dispatcher');
var CHANGE_EVENT = "change";
var data = {};
var message = "";
function _fetch () {
message = "Fetching data";
$.ajax({
type: 'GET',
url: 'Url',
contentType: 'application/json',
success: function(data){
message = "";
MyStore.emitChange();
},
error: function(error){
message = error;
MyStore.emitChange();
}
});
};
function _post (myData) {
//Make post
$.ajax({
type: 'POST',
url: 'Url',
// post payload:
data: JSON.stringify(myData),
contentType: 'application/json',
success: function(data){
message = "";
MyStore.emitChange();
},
error: function(error){
message = "update failed";
MyStore.emitChange();
}
});
};
var MyStore = merge(EventEmitter.prototype, {
emitChange: function () {
this.emit(CHANGE_EVENT);
},
addChangeListener: function (callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function (callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getData: function (){
if(!data){
_fetch();
}
return data;
},
getMessage: function (){
return message;
},
dispatcherIndex: Dispatcher.register( function(payload) {
var action = payload.action; // this is our action from handleViewAction
switch(action.actionType){
case Constants.UPDATE:
message = "updating...";
_post(payload.action.data);
break;
}
MyStore.emitChange();
return true;
})
});
module.exports = MyStore;
Then you need to subscribe your component to the store change events
var React = require('react');
var MyStore = require('my-store');
function getComments (){
return {
message: null,
data: MyStore.getData()
}
};
var AlbumComments = module.exports = React.createClass({
getInitialState: function() {
return getData();
},
componentWillMount: function(){
MyStore.addChangeListener(this._onChange);
},
componentWillUnmount: function(){
MyStore.removeChangeListener(this._onChange);
},
_onChange: function(){
var msg = MyStore.getMessage();
if (!message){
this.setState(getData());
} else {
this.setState({
message: msg,
data: null
});
}
},
render: function() {
console.log('render');
return (
<div>
{ this.state.message }
{this.state.data.map(function(item){
return <div>{ item }</div>
})}
</div>
);
}
});
I hope it is clear enough.

Signalr 2.0.0 doesn't behave as previous version

I have updated my server solution to work with MVC 5 and latest version of signalr and have two major issues:
I have overriden the OnConnected function and it is not being invoked.
Messages to client are not being received , calls from the client are being received
this is the client code
define(['jquery', 'toastr', 'Q'], function($, toastr, Q) {
var incidentHubProxy;
var deferred = Q.defer();
var connect = function() {
var connection = $.hubConnection(localStorage.url);
$.connection.hub.logging = true;
incidentHubProxy = connection.createHubProxy('notification');
connection.start()
.done(function () {
toastr.success('Now connected, connection ID=' + connection.id);
setInterval(function () {
incidentHubProxy.invoke('ping');
}, 3000);
deferred.resolve();
})
.fail(function () { toastr.error('Could not connect'); });
incidentHubProxy.on('notify', function (data) {
toastr.info(data.topic);
toastr.info(data.data);
});
incidentHubProxy.on('pong', function (data) {
toastr.info('got pong');
});
return deferred.promise;
};
var joinGroup = function (groupName) {
incidentHubProxy.invoke('joinGroup', groupName);
};
return {
connect: connect,
joinGroup: joinGroup
};
});
i have updated the code to that and still dont work
define(['jquery', 'toastr', 'Q'], function($, toastr, Q) {
var incidentHubProxy;
var deferred = Q.defer();
var connect = function() {
var connection = $.hubConnection(localStorage.url);
$.connection.hub.logging = true;
incidentHubProxy = connection.createHubProxy('notification');
incidentHubProxy.notify = function(data) {
toastr.info(data.topic);
toastr.info(data.data);
};
incidentHubProxy.pong = function(data) {
toastr.info('got pong');
};
connection.start()
.done(function () {
toastr.success('Now connected, connection ID=' + connection.id);
setInterval(function () {
incidentHubProxy.invoke('ping');
}, 3000);
deferred.resolve();
})
.fail(function () { toastr.error('Could not connect'); });
return deferred.promise;
};
var joinGroup = function (groupName) {
incidentHubProxy.invoke('joinGroup', groupName);
};
return {
connect: connect,
joinGroup: joinGroup
};
});

How to work with $resource in angularjs

I am trying to get data form this url http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo
through $resource below is my resource code
angular.module('myApp.services', ['ngResource']).
value('version', '0.1').factory('recipes1',['$resource', '$http', '$log', function ($resource, $http, $log) {
return $resource('http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo',{ },{ locate: {method: 'GET', isArray: true, transformResponse: $http.defaults.transformResponse.concat(function(data, headersGetter) {
// probably be better if you examined the results in here
alert(data);
})}
});
}]);
but i am not getting response. i am getting out put from my controller as
function Resource(value){
"use strict";
copy(value || {}, this);
}
Use $http with promise factory:
See working Demo in fiddle
JS
var fessmodule = angular.module('myModule', ['ngResource']);
fessmodule.controller('fessCntrl', function ($scope, Data) {
$scope.runMe = function () {
Data.query($scope.url)
.then(function (result) {
$scope.data = result;
}, function (result) {
alert("Error: No data returned");
});
}
});
fessmodule.$inject = ['$scope', 'Data'];
fessmodule.factory('Data', ['$http','$q', function($http, $q) {
var data = $http({method: 'GET', url: 'http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo'});
var factory = {
query: function (address) {
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
}]);

How make nested http query in AngularJs?

Iam build single page app in AngularJs,and I need call Facebook UI dialog.And if user click 'ok',or 'cancel',successReport methos not call immediately.This method call after i click on any button in page,or link.Similar to internal queue
service.showStreamDialog=function (json) {
if (json.stream) {
var newCardSentId = json.cardSentId;
FB.ui(json.stream, function (resp) {
if (resp && resp.post_id) {
reportService.successReport(newCardSentId,newCardSentId,resp.post_id);
} else {
reportService.cancelReport(newCardSentId);
}
});
}
};
// in other file
var successReport=function(cardId,cardSentId,postId){
var defered = $q.defer();
$http.post(reportUrl,$.param({
cardId:cardId,
cardSentId:cardSentId,
postId:postId,
accessToken: ACCESS_TOKEN
}))
.success(function(data){
defered.resolve(data);})
.error(function(data){
defered.reject(data);
});
return defered.promise;
};
I found problem. It was in integration facebook api in my app.I add $rootScope.$apply call,
and all working as i expected
service.showStreamDialog = function (json) {
if (json.stream) {
var newCardSentId = json.cardSentId;
FB.ui(json.stream, function (resp) {
if (resp && resp.post_id) {
$rootScope.$apply(function () {
$rootScope.$broadcast('CARD_SENT_SUCCESS', {cardSentId: newCardSentId,post_id:resp.post_id});
});
} else {
$rootScope.$apply(function () {
$rootScope.$broadcast('CARD_SENT_CANCEL', {cardSentId: newCardSentId});
});
}
});
}
};

Resources