I have a problem with handling the multiple timeouts in displaying the alert messages. In my app i get several alert messages when create a task, play the task, pause the task and delete a task. I set the timeout for all alerts as 5000 using $timeout().
This is the code for creating a task::
$scope.create = function () {
console.log('Taskkkkkkkkkk Title create function is called : ');
for (var i = 0; i < $scope.tasks.length; i++) {
if ($scope.tasks[i].title === this.title) {
$scope.duplicateTitle = true;
return;
}
}
var task = new Tasks({
'title': this.title,
'description': this.description,
'duration': 0,
'lastStart': '',
'archive': false,
'active': true
});
console.log('Taskkkkkkkkkk Title : ' + task.title);
if (task.title) {
task.$save(function (response) {
$scope.alerts.push({
type: 'success',
msg: 'Task have been Added!!' + '   <button type="button" class="close" data-dismiss="alert" ng-click="closeAlert()">×</button>'
});
$scope.closeAlert = function (index) {
$scope.alerts.splice(index, 1);
};
$timeout(function () {
$scope.alerts.splice($scope.alerts.indexOf(alert), 1);
}, 5000);
$scope.tasks.unshift(response);
//$scope.tasks = Tasks.query();
$scope.title = '';
$scope.description = '';
$state.go('listTasks');
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
} else {
var message = 'Title cannot be blank';
$scope.error = message;
}
};
But When i click the multiple tasks within 5sec, the last task alert message will de disappearing. But not the first one, means it is folling the stack order i.e., FIFO principle. I am writing the alert messages in the controllers.
I want the tasks to be disappeared in the order which they are arised. Any suggestions will be more helpful to me.
There in the timeout i just added the index value for the splice function.
$timeout(function () {
$scope.alerts.splice(index, 1);
}, 5000);
its working fine now...
Related
On success message I want to navigate from uploaded page to customer page and highlight my alert as success , but my alert is not getting open. Need solution
Upload.js
if (status == 200){
$state.go('customer', {"id": $scope.customer});
$rootScope.$emit('custSucess');
}
customer.js
$rootScope.$on('custSucess',function(event){
$scope.message = {
content: [{
title: '',
msg:'hi'
}],
type: 'success'
};
});
So what I ended up doing is creating a service for handling my alerts. Here is the service code:
app.factory('AlertService', function () {
var success = {},
error = {},
alert = false;
return {
getSuccess: function () {
return success;
},
setSuccess: function (value) {
success = value;
alert = true;
},
getError: function () {
return error;
},
setError: function (value) {
error = value;
alert = true;
},
reset: function () {
success = {};
error = {};
alert = false;
},
hasAlert: function () {
return alert;
}
}
});
//And I simply set it when I need to like so:
AlertService.setSuccess({ show: true, msg: name + ' has been updated successfully.' });
//And check for it on the page that would display it like this:
if (AlertService.hasAlert()) {
$scope.success = AlertService.getSuccess();
AlertService.reset();
}`enter code here`
I'm using ngCordova File Transfer plugin in an ionic project to download set of images from urls. Here is the code i'm using for that.
// Save a image file in a given directory
$scope.saveImage = function(dir,imgUrl,imageName) {
var url = imgUrl;
var targetPath = cordova.file.dataDirectory+ dir+"/" + imageName;
var trustHosts = true;
var options = {};
// Download the image using cordovafiletransfer plugin
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
$scope.loadedCount ++;
$ionicLoading.show({template : "<ion-spinner class='spinner-energized'></ion-spinner><p> Downloading pages : "+ $scope.loadedCount+" of "+ $scope.pages.length+ "</p><p>Please wait...</p><p><button class=\"button button-block button-positive\">continue in background</button></p>"});
if($scope.loadedCount == $scope.pages.length) {
$ionicLoading.hide();
$scope.showDownloadSuccessAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Success!',
template: "Your magazine successfully downloaded. You can view it on Downloads!"
});
};
$scope.showDownloadSuccessAlert();
}
}, function(err) {
alert(JSON.stringify(err));
}, function (progress) {
if($scope.loadedCount > 80) {
}
});
};
// Download the current magazine
$scope.downloadMagazine = function() {
if($rootScope.user.user_id == undefined) {
$scope.showLoginAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Oops!',
template: "Your must login to download magazines"
});
};
$scope.showLoginAlert();
return;
}
document.addEventListener('deviceready', function () {
var dirName = $rootScope.currentIssue.slug+'_VOL_'+$rootScope.currentIssue.vol+'_ISU_'+$rootScope.currentIssue.issue;
// First create the directory
$cordovaFile.createDir(cordova.file.dataDirectory, dirName, false)
.then(function (success) {
var count = 1;
$scope.loadedCount = 0;
angular.forEach($scope.pages, function(value, key) {
var imgName = count+".png";
$scope.saveImage(dirName,value.link,imgName); // Then save images one by one to the created directory.
count++;
});
}, function (error) {
// Directory already exists means that the magazine is already downloaded.
$scope.showDownloadedAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Why worry!',
template: "Your have already downloaded this magazine. You can view it on downloads"
});
};
$scope.showDownloadedAlert();
});
}, false);
};
})
Problem here is that program try to download everything at once without waiting for previous one to finish. How to wait for one file to finish downloading and then start the other?
Thanks
If you want to do that automatically (you're not the first one : How can I execute array of promises in sequential order?), you could try reducing the list of address to a single Promise that will do the whole chain.
$scope.pages.reduce(function (curr,next) {
return curr.then(function(){
return $scope.saveImage(dirName, curr.link, imgName);
});
}, Promise.resolve()).then(function(result) {
$ionicLoading.show({template : "<ion-spinner class='spinner-energized'></ion-spinner><p> Downloading pages : "+ $scope.loadedCount+" of "+ $scope.pages.length+ "</p><p>Please wait...</p><p><button class=\"button button-block button-positive\">continue in background</button></p>"});
if($scope.loadedCount == $scope.pages.length) {
$ionicLoading.hide();
$scope.showDownloadSuccessAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Success!',
template: "Your magazine successfully downloaded. You can view it on Downloads!"
});
};
$scope.showDownloadSuccessAlert();
}
});
And don't forget to make your saveImage async which returns a promise.
UPDATE:
You will need to remove the then logic from your save method and return the download method call:
return $cordovaFileTransfer.download(url, targetPath, options, trustHosts).promise;
Then you can put your download handler into Promise.resolve()).then. See above.
There's no other way other than chaining your promises. Here's an example:
angular.module('app', [])
.service('fakeDownloadService', function($timeout) {
this.download = (file) => $timeout(() => file, 100);
return this;
})
.run(function($rootScope, $q, fakeDownloadService) {
var listOfFiles = [];
for (var i = 0; i < 10; i++)
listOfFiles.push('file' + i);
$rootScope.log = [];
$rootScope.download = () => {
listOfFiles
.reduce((prev, curr) => {
return prev.then((result) => {
if(result)
$rootScope.log.push(result + ' downloaded');
return fakeDownloadService.download(curr);
});
}, $q.resolve())
.then(() => $rootScope.log.push('all done'));
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<div ng-app="app">
<button ng-click="download()">Start</button>
<div>Log:</div>
<ul>
<li ng-repeat="entry in log track by $index">
{{entry}}
</li>
</ul>
</div>
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.
I have several rows in a table, each having a select menu in the last cell. The initial value is populated by one controller and the select options being populated by a second controller. The second controller also updates the value on ng-change. If I use ng-selected, I get the initial value but does not change the value on change. (it does log it to the console though). If I use ng-init, it does not give a value on load, but does update after changing the value.
app.controller('agents', function($scope, $http){
$scope.getAgents = function(){
$http.get("getagents.php").then(function(response) {
$scope.agents = response.data;
});
}
$scope.getActiveAgents = function(){
$http.get("activeagents.php").then(function(response) {
// console.log(response.data);
$scope.activeagents = response.data;
});
}
$scope.updateAgenttoLead = function(agent, id){
console.log('ID:'+ id);
console.log('Agent:'+ agent);
}
$scope.updateForm = {};
$scope.updateAgent = function() {
$http.post('updateagent.php', {
'id' : $scope.updateForm.id,
'username' : $scope.updateForm.username,
'password' : $scope.updateForm.password
}
).success(function(data) {
// console.log(data);
$scope.updateForm = {};
$scope.getAgents();
// if (!data.success) {
// // if not successful, bind errors to error variables
// $scope.errorName = data.errors.name;
// $scope.errorSuperhero = data.errors.superheroAlias;
// } else {
// // if successful, bind success message to message
// $scope.message = data.message;
// }
});
};
$scope.addForm = {};
$scope.addAgent = function() {
$http.put('createagent.php', {
'username' : $scope.addForm.username,
'password' : $scope.addForm.password,
'type' : $scope.addForm.type
}
).success(function(data) {
$scope.addForm = {};
$scope.getAgents();
});
};
$scope.deleteagent = function(newid){
var r =confirm('Are you sure you want to delete '+ newid+'?');
if(r){
$http.post('deleteagent.php', {
'newid':newid
}
).success(function(data) {
$scope.getAgents();
console.log(data);
});
}
};
}); // end controller
app.controller('leads', function($scope, $http){
$scope.getLeads = function(){
$http.get("getleads.php").then(function(server) {
$scope.leads = server.data;
});
}
$scope.dispositions =[
'Never Called',
'Not Available',
'Left Message',
'Call Later',
'Not Interested',
'Not Qualified',
'Bad Phone',
'No Dates',
'DNC',
'Post Date',
'Sold'
];
$scope.updateDisp = function(disp, id){
var r = confirm('Update record '+ id +' to '+disp+'?');
if(r){
$http.post('updatedisp.php', {
'id' : id,
'disp' : disp
}
).success(function(data) {
console.log(data);
});
}else{
$scope.leads={};
$scope.getLeads();
}
}
}); // end controller
You are using controllers as services. Controllers are meant to be used as a way to bind a UI to implementation, not to provide functionality for retrieving data.
I would refactor your code to have a single controller for your page/table and then put all of this agent/leads code in separate services that your controller then consumes when needed.
See this blog post for more insight:
http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/
I need to save data and then I need to dispaly the changes immediately afterwards.
That's why I Have a
updateSaisine which allows me to update data
getOneSaisine which allows me get the data and display them:
Which is the more correct way and for which reasons ?
Should I write:
$scope.saveSaisine = function() {
saisineSrv.updateSaisine($scope.currentSaisine.idSaisine, $scope.currentSaisine).
then(
function() {
$scope.errorMessages = [];
if ($scope.currentSaisine.idMotif) {
toaster.pop('success', 'Réponse', 'Success');
angular.element('#modalSaisine').modal('hide');
saisineSrv.getOneSaisine($scope.currentSaisine.idSaisine, $scope.currentSaisine).then(function(response) {
$scope.currentSaisine.dateModif = response.dateModif;
});
},
function error(response) {
$scope.errorMessages = response.data;
toaster.pop('error', 'Réponse', 'We have a problem');
}
);
};
OR
$scope.saveSaisine = function() {
saisineSrv.updateSaisine($scope.currentSaisine.idSaisine, $scope.currentSaisine).
then(
function() {
$scope.errorMessages = [];
if ($scope.currentSaisine.idMotif) {
toaster.pop('success', 'Réponse', 'Success');
angular.element('#modalSaisine').modal('hide');
},
function error(response) {
$scope.errorMessages = response.data;
toaster.pop('error', 'Réponse', 'We have a problem');
}
);
saisineSrv.getOneSaisine($scope.currentSaisine.idSaisine, $scope.currentSaisine).then(function(response) {
$scope.currentSaisine.dateModif = response.dateModif;
});
};
the first option is a correct way how you should refresh your data because these services are asynchronous thus in the second example you may don't get fresh data (the getOneSaisine can finish before updateSaisine).