button text not updating from controller function in AngularJS - angularjs

I'm trying to change the text of a button to "Loading" while an api request is processing within AngularJS. I use a scope variable of buttontext. I noticed the variable gets updated in the browser developer console but doesn't get updated in the ng-inspector panel in Chrome. I can't figure out why the button text doesn't change. I figure it has to do with the fact the corresponding variable is inside a controller function. Here's my AngularJS code:
angular.module('twitterApp', ['ngResource'])
.controller('mainController', function($scope, TwitterUser, KloutUser) {
$scope.buttontext = "Get Insight";
$scope.error = false;
$scope.users = [];
$scope.getResult = function(id){
$scope.users = [];
$scope.buttontext = "Loading";
$scope.loading = true;
TwitterUser.get({
id: id
}, function(user) {
if(user.error) {
$scope.error = true;
$scope.message = "Validation Error please fill the user_id or screen_name field";
}else{
if(!user.errors){
console.log(user);
$scope.users.push(user);
$scope.error = false;
}else{
$scope.error = true;
$scope.message = user.errors[0]['message']+" - "+user.errors[0]['code'] ;
}
}
}).$promise.then(function(user){
KloutUser.get({
id: user.id
}, function(userkloutscore) {
if(!userkloutscore) {
console.log('An error occurred. No Klout score returned.');
}else{
$scope.kloutscore = userkloutscore.score;
var score_stringified = JSON.stringify(userkloutscore);
console.log('The Klout API response: ' + score_stringified);
}
});
});
$scope.buttontext = "Get Insight";
};
$scope.removeUser = function(index){
$scope.users.splice(index, 1);
};
});
And here's the button HTML:
<a class="btn btn-primary" role="button" ng-click="getResult(id)">{{ buttontext }}</a>

You need to put
$scope.buttontext = "Get Insight";
Inside the promise callback, because at this moment your flow is:
Change text to "Loading"
Make the API request (and wait in background)
Change text to "Get Insight" inmediately
So your text makes the change from "Get Insight" -> "Loading" -> "Get Insight" so rapidly that it goes unnoticed.

Move the last line to inside your callback/promise logic, like:
angular.module('twitterApp', ['ngResource'])
.controller('mainController', function($scope, TwitterUser, KloutUser) {
$scope.buttontext = "Get Insight";
$scope.error = false;
$scope.users = [];
$scope.getResult = function(id){
$scope.users = [];
$scope.buttontext = "Loading";
$scope.loading = true;
TwitterUser.get({
id: id
}, function(user) {
if(user.error) {
$scope.error = true;
$scope.message = "Validation Error please fill the user_id or screen_name field";
}else{
if(!user.errors){
console.log(user);
$scope.users.push(user);
$scope.error = false;
}else{
$scope.error = true;
$scope.message = user.errors[0]['message']+" - "+user.errors[0]['code'] ;
}
}
}).$promise.then(function(user){
KloutUser.get({
id: user.id
}, function(userkloutscore) {
if(!userkloutscore) {
console.log('An error occurred. No Klout score returned.');
}else{
$scope.kloutscore = userkloutscore.score;
var score_stringified = JSON.stringify(userkloutscore);
console.log('The Klout API response: ' + score_stringified);
}
$scope.buttontext = "Get Insight";
});
});
};
$scope.removeUser = function(index){
$scope.users.splice(index, 1);
};
});
But you still need to handle some error scenarios.

Related

Bootstrap angular error message leave space after fading

I've found an example: Here. But after the error message fades, the content keeps the space occupied by the message.
Here's my code. In my view:
<div data-ng-show="showError" ng-class="{fade:doFade}" class="alert alert-danger"> {{authmessage}}</div>
And in my controller:
$scope.userLogin = function () {
http.post('/api/login/', $scope.formData).then(function (response) {
$rootScope.message = response.config.data.email;
$location.url('/Projects');
}).catch(function(response){
$scope.showError = false;
$scope.doFade = false;
$scope.showError = true;
$scope.authmessage = response.data;
$timeout(function(){
$scope.doFade = true;
}, 2500); });
} ;
Please set $scope.showError to false in $timeout function
$timeout(function(){
$scope.doFade = true;
$scope.showError = false;
}, 2500);

ngResourc:generate unique number

I'm trying to post new data comment and I want $resource serviceto give every comment unique id automatically.but I don't know how to do it . the data was past but in id was property empty ,it don't have id number.
Code for controller.js
.controller('ContactController', ['$scope','FeedbackFactory', function($scope,FeedbackFactory) {
$scope.feedback = {mychannel:"", firstName:"", lastName:"", agree:false, email:"" ,id:""};
var channels = [{value:"tel", label:"Tel."}, {value:"Email",label:"Email"}];
$scope.channels = channels;
$scope.invalidChannelSelection = false;
$scope.fback= FeedbackFactory.putFeedback().query(
function(response){
$scope.fback = response;
},
function(response) {
$scope.message = "Error: "+response.status + " " + response.statusText;
}
);
}])
.controller('FeedbackController', ['$scope', 'FeedbackFactory',function($scope,FeedbackFactory) {
$scope.sendFeedback = function() {
console.log($scope.feedback);
if ($scope.feedback.agree && ($scope.feedback.mychannel === "")) {
$scope.invalidChannelSelection = true;
console.log('incorrect');
}
else {
$scope.invalidChannelSelection = false;
$scope.fback.push($scope.feedback);
FeedbackFactory.putFeedback().save($scope.fback);
$scope.feedback = {mychannel:"", firstName:"", lastName:"", agree:false, email:"" };
$scope.feedback.mychannel="";
$scope.feedbackForm.$setPristine();
console.log($scope.feedback);
}
};
}])
service.js
.service('FeedbackFactory',['$resource','baseURL',function($resource,baseURL){
this.putFeedback = function(){
return $resource(baseURL+"feedback/",{'update':{method:'POST'}});
};
} ])
;
note:the data comment will save in form of JSON data.

AngularJS update Service values when connected or disconnected to firebase

I wish to change the icon color when connected or disconnected to the firebase server. I got this far:
HTML
<button class="button button-icon ion-cloud" ng-style="dbConnectedStyle"></button>
Controller
firebaseRef.$loaded().then( function() {
$scope.dbConnectedStyle = {'color': dbConnectStatus.color};
}
Service
.service('dbConnectStatus', function(firebaseRef){
var status = false;
var color = 'transparent';
var connectedRef = firebaseRef.child(".info/connected");
connectedRef.on("value", function(snap) {
status = snap.val();
if (status) {
color = 'lightgrey';
console.log("Connected to DB (" + color + ")" );
} else {
color = 'transparent';
console.log("Disonnected to DB (" + color + ")" );
}
});
return {
'boolean': status,
'color': color
}
})
It change color the first time. But when disconnecting it doesn't change... seems like it's not two-way binding to the service. How do I achieve this?
UPDATE
Tried to do a reference to the Service as an object rather than doing primitives assignments as explained in the good tutorial A Tale of Frankenstein and Binding to Service Values in Angular.js
I changed the code to the following
HTML
<button class="button button-icon ion-cloud"
ng-style="dbConnectionStatus.connectionStyle">
</button>
Service
.service('dbConnectStatus', function(firebaseRef, $rootScope){
this.status = false;
var styles = {
'offlineStyle': {'color': 'red'},
'onlineStyle': {'color': 'lightgrey'}
};
this.connectionStyle = styles.offlineStyle;
firebaseRef.child(".info/connected")
.on("value",
function(snap) {
this.status = snap.val();
if (snap.val()) {
console.log("Connected to DB.");
this.connectionStyle = styles.onlineStyle;
console.log(this.connectionStyle);
} else {
console.log("Disconnected to DB.");
this.connectionStyle = styles.offlineStyle;
console.log(this.connectionStyle);
}
console.log(this.status);
$rootScope.$broadcast('dbConnection:changed');
}
);
})
Controller
$scope.dbConnectionStatus = dbConnectStatus;
$scope.$on('dbConnection:changed', function() {
console.log("'on(...)' called. This is the $scope.dbConnectionStatus.connectionStyle:");
$scope.dbConnectionStatus = dbConnectStatus;
console.log($scope.dbConnectionStatus.connectionStyle);
console.log("This is the dbConnectStatus.connectionStyle:");
console.log(dbConnectStatus.connectionStyle);
});
$rootScope.$watch('dbConnectStatus', function (){
$scope.dbConnectionStatus = dbConnectStatus;
});
//$rootScope.$apply();
I then reloaded the code and got this console message
I then turned off the connection
I then turn on the connection
It is clear to me that the service dbConnectionStatus isn't updated as a global variable in the way that I expected. I was on the assumption that a service is called once when the application is load and that assigning a scope variable to a service (object) is not a call but a reference...
What am I doing wrong?
I worked in a jsFiddle using $emit and $on to handle the status changes inside the service. The main problem is that when going online the angular binding was not working properly so I needed to force an angular cycle with $scope.$apply().
I started working on the first version of your code but made some refactoring. You can find the full code on the jsFiddle but the service and the controller look like the following:
Service
.service('dbConnectStatus', function($rootScope){
var status = false;
var color = 'red';
var self = {
startWatchingConnectionStatus: function(){
var connectedRef = firebase.database().ref().child(".info/connected");
connectedRef.on("value", function(snap) {
console.log(snap.val());
status = snap.val();
if (status) {
color = 'blue';
console.log("Connected to DB (" + color + ")" );
} else {
color = 'red';
console.log("Disonnected to DB (" + color + ")" );
}
$rootScope.$emit('connectionStatus:change', {style: {'color': color}, status: status}});
});
},
getStatus: function(){
return status;
},
getColor: function(){
return color;
}
};
return self;
})
Controller
.controller('HomeCtrl', ['$scope', 'dbConnectStatus', '$rootScope',function($scope, dbConnectStatus, $rootScope) {
dbConnectStatus.startWatchingConnectionStatus();
$rootScope.$on('connectionStatus:change', function currentCityChanged(event, value){
$scope.color = value.style;
//if changed to connected then force the $apply
if(value.status === true){
$scope.$apply();
}
});
}]);
Let me know if there is anything that is still not clear.
Inspired from #adolfosrs great answer I found the following solution to work for me.
Service
.service('dbConnectStatus', function(firebaseRef, $rootScope){
// Initial setup
var styles = {
'offlineStyle': {'color': 'red'},
'onlineStyle': {'color': 'skyeblue'}
};
// Functions to switch status
var offline = function () {
this.boolean = false;
this.style = styles.offlineStyle;
}
var online = function () {
this.boolean = true;
this.style = styles.onlineStyle;
}
var get_status = function(){
return {
boolean: this.boolean,
style: this.style
}
}
// Read the firebase info and update when changed
firebaseRef.child(".info/connected")
.on("value", function(snap) {
if (snap.val()) {
online();
} else {
offline();
}
$rootScope.$emit('dbConnection:changed', get_status() );
});
})
Controller
// Hide it before the status is known.
$scope.dbConnectionStatus = {'color': 'transparent'};
// Getting and reading status changes
$rootScope.$on('dbConnection:changed', function(event, status) {
$scope.dbConnectionStatus = status.style;
$scope.$apply();
});
You should be able to get this working simply by storing the color in an object in the service and referencing it from the controller. e.g.
View
<button class="button button-icon ion-cloud" ng-style="dbStatusService.style"></button>
Controller
$scope.dbStatusService = dbConnectStatus;
Service
.service('dbConnectStatus', function(firebaseRef){
var status = false;
var style = {color: 'transparent'};
var connectedRef = firebaseRef.child(".info/connected");
connectedRef.on("value", function(snap) {
status = snap.val();
if (status) {
style.color = 'lightgrey';
} else {
style.color = 'transparent';
}
});
return {
'boolean': status,
'style': style
}
});

Ionic Infinite Scroll with http.post results

I am trying to create an infinite scroll based on Gajotres post (http://www.gajotres.net/ionic-framework-tutorial-11-infinite-scroll/)
My problems are:
If i write : $scope.searchObjects($scope.formData); all $scope objects are printed on the screen, how can it be avoided?
Can i pass form data by using $scope.formData, this way: .
$scope.searchObjects($scope.formData);
Until now the list freezes with 7000 itens and can not get the infinite scroll to work , seems it load all the itens.
There is a better know solution to ionic infinite scroll with http.post ?
Here is my attempt code any help would be apreciated :
.controller('someObjectsCtrl', function( $scope, $http) {
$scope.data = null;
$scope.itens = [];
$scope.data = {
'state' : '',
'city' : '',
}
$http.get('http://someservice.com/states.php').then( function response(response){
$scope.states = response.data;
},function(error){
$scope.error = JSON.stringfy(error);
});
$scope.getCities = function(id) {
$http.get('http://someservice.com/state.php?stateid='+id).then( function response(result) {
$scope.cities = result.data;
$ionicLoading.hide();
},function(error) {
$scope.error = JSON.stringfy(error);
});
};
$scope.originForm = angular.copy($scope.data);
$scope.searchObjects = function(data) {
$scope.formData = {};
$scope.formData.state = data.state;
$scope.formData.city = data.city;
$http.post("http://someservice.com/objectsToSearch.php", $scope.formData )
.success( function(data) {
$scope.result = data;
for (var i = 0; i <= 6; i++) {
$scope.itens.push({ foundObjects: $scope.result.OBJECTS});
}
$scope.$broadcast('scroll.infiniteScrollComplete');
if( $scope.result.length == 0 ){
$scope.data = null;
}
$scope.headers = ['Some Objects', 'Another Objects' ];
})
.error(function(error){
$ionicLoading.show({ template: '<p>Error ...</p>',duration :6000 });
})
}
$scope.canWeLoadMoreContent = function() {
return ($scope.itens.length > 10) ? false : true;
console.log(' scope.itens.length '+$scope.itens.length );
}
$scope.searchObjects($scope.formData);
})
Until now the only solution i find was to use collectio-repeat instead of ng-repeat. Collection-repeat is very fast rendering the result list.

Firebase child_removed not working in real-time

I am following tutsplus Real time web apps with Angularjs and Firebase.
I have main.js (below) which allows me to add and change items in Firebase in real time with no refresh of the browser (in Chrome and Safari).
However when I delete a message from Firebase I have to refresh the browser for the message list to update - so not in real time. I can't see where the problem is.
/*global Firebase*/
'use strict';
/**
* #ngdoc function
* #name firebaseProjectApp.controller:MainCtrl
* #description
* # MainCtrl
* Controller of the firebaseProjectApp
*/
angular.module('firebaseProjectApp')
.controller('MainCtrl', function ($scope, $timeout) {
var rootRef = new Firebase('https://popping-inferno-9738.firebaseio.com/');
var messagesRef = rootRef.child('messages');
$scope.currentUser=null;
$scope.currentText=null;
$scope.messages=[];
messagesRef.on('child_added', function(snapshot){
$timeout(function() {
var snapshotVal = snapshot.val();
console.log(snapshotVal);
$scope.messages.push({
text: snapshotVal.text,
user: snapshotVal.user,
name: snapshot.key()
});
});
});
messagesRef.on('child_changed', function(snapshot){
$timeout(function() {
var snapshotVal = snapshot.val();
var message = findMessageByName(snapshot.key());
message.text = snapshotVal.text;
});
});
messagesRef.on('child_removed', function(snapshot){
$timeout(function() {
var snapshotVal = snapshot.val();
var message = findMessageByName(snapshot.key());
message.text = snapshotVal.text;
});
});
function deleteMessageByName(name){
for(var i=0; i < $scope.messages.length; i++){
var currentMessage = $scope.messages[i];
if(currentMessage.name === name){
$scope.messages.splice(i, 1);
break;
}
}
}
function findMessageByName(name){
var messageFound = null;
for(var i=0; i < $scope.messages.length; i++){
var currentMessage = $scope.messages[i];
if(currentMessage.name === name){
messageFound = currentMessage;
break;
}
}
return messageFound;
}
$scope.sendMessage = function(){
var newMessage = {
user: $scope.currentUser,
text: $scope.currentText
};
messagesRef.push(newMessage);
};
});
The code that is invoked when a message is deleted from Firebase:
messagesRef.on('child_removed', function(snapshot){
$timeout(function() {
var snapshotVal = snapshot.val();
var message = findMessageByName(snapshot.key());
message.text = snapshotVal.text;
});
});
This code never actually deletes the message from the HTML/DOM.
There is a convenient deleteMessageByName method to handle the deletion. So if you modify the above to this, it'll work:
messagesRef.on('child_removed', function(snapshot){
$timeout(function() {
deleteMessageByName(snapshot.key());
});
});

Resources