I create a factory where I put my http request for adding, retrieving and deleting tasks.
Now when I add a task you don't see the visual change. I have to refresh the browser. Now to fix this I figured I would write a function to check the length of the old array against the length of the new one and set an interval off 1 minutes on it to make this change and then pull in the tasks. I am able to log my length change of the array but nothing happens visually (still have to refresh the browser).
If anybody could help me out here.
Part of my app.js code:
global vars -> defaultStart, defaultEnd, clickDate
zazzleApp.factory('TaskService', function ($http) {
var TaskService = {};
TaskService.taskList = [];
TaskService.getTasks = function(cb){
$http.get('api/task/all')
.success(function(dataFromServer){
for (var i = 0; i < dataFromServer.length; i++) {
TaskService.taskList[i] = dataFromServer[i];
};
//console.log('LOGGING GET_TASK ', TaskService.taskList);
if(cb){
cb(dataFromServer);
}else{
return dataFromServer;
}
//return dataFromServer;
})
.error(function(errorFromServer){
//something went wrong, process the error here
console.log("Error in getting the users from the server ", errorFromServer);
})
};
TaskService.addTask = function(pTask){
var newClickDate = clickDate;
console.log('LOGGGING NEW CLICK DATE = ', newClickDate);
var newEditId = editId;
//console.log('LOGGGING NEW edit id = ', newEditId);
var url;
if (newEditId) {
url = 'api/task/update/' + newEditId;
} else {
url = 'api/task/create';
}
//console.log("URL URL USA", url, newEditId, newClickDate);
defaultStart = new Date(newClickDate);
defaultStart = defaultStart.getFullYear() + "-" + (defaultStart.getMonth() + 1) + "-" + defaultStart.getDate();
defaultStart += " 00:00:00";
defaultEnd = new Date(newClickDate).addDays(1);
defaultEnd = defaultEnd.getFullYear() + "-" + (defaultEnd.getMonth() + 1) + "-" + defaultEnd.getDate();
defaultEnd += " 00:00:00";
console.log('LOGGING DEFAULT START AND DEFAULT END ' , defaultStart, defaultEnd);
pTask.color = $('#containerColorPicker').attr('ng-data-id');
// returns makes sure the promis is returned from the server
return $http.post(url, {
'name': pTask.project_name,
'project_id': pTask.project_type,
'location_id': pTask.location,
'estimate_time': pTask.estimate_time || 2,
'project_client_name': pTask.project_client_name,
'url': pTask.url,
'resource_link': pTask.resource_link,
'notes': pTask.notes,
'start_time': pTask.start_time || defaultStart,
'end_time': pTask.end_time || defaultEnd,
/*'start_time': defaultStart,
'end_time': defaultEnd,*/
'color': pTask.color
}, {
headers: {
"Content-Type": "text/plain"
}
})
.success(function(data, status, headers, config) {
console.log(data);
TaskService.getTasks();
TaskService.taskList.push(data);//pushing the new task
//console.log("YYYYYYYYYYYYY -------->>>>>", defaultStart);
})
.error(function(data, status, headers, config) {
console.log("Failed to add the task to DB");
});
};
TaskService.deleteTask = function (){
var newEditId= editId;
$http.delete('api/task/delete/' + newEditId)
.success(function(dataFromServer){
console.log('logging edit id in delete taks func server ', newEditId);
var index;
for (var i = 0; i < TaskService.taskList.length; i++) {
if(TaskService.taskList[i]._id == newEditId){
//index = i;
console.log ("removing the element from the array, index: ", newEditId, i);
TaskService.taskList.splice(i,1);
}
};
/* if(editId !== -1){
console.log ("removing the element from the array, index: ", editId, index);
UserService.userList.splice(index,1);
}*/
console.log('TaskArray ', TaskService.taskList)
$('div[ng-data-id="'+ newEditId +'"]').remove();
})
.error(function(errorFromServer){
//something went wrong, process the error here
console.log("Error in deleting a user from the server");
})
};
return TaskService;
})
//START CONTROLLER
angular.module('zazzleToolPlannerApp')
.controller('CalendarCtrl', function ($scope, $mdDialog, $http, $rootScope, $timeout, User, Auth, UserService, TaskService) {
$scope.newTask = {};
$scope.newTask.project_name = "";
$scope.newTask.project_type = "";
$scope.newTask.location = "";
$scope.newTask.estimate_time = "";
$scope.newTask.project_client_name = "";
$scope.newTask.url = "";
$scope.newTask.resource_link = "";
$scope.newTask.notes = "";
$scope.newTask.color = "";
$scope.tasks = TaskService.taskList;
$scope.getTasksFromService = function () {
TaskService.getTasks(); //after this gets called, the data will be shown in the page automatically
}
$scope.getTasksFromService();
$scope.addTaskWithService = function () {
//note that you can process the promise right here (because of the return $http in the service)
TaskService.addTask($scope.newTask)
.success(function(data){
//here you can process the data or format it or do whatever you want with it
console.log("Controller: the task has been added");
$scope.tasks = [];// EMPTY THE ARRAY
$scope.tasks = TaskService.getTasks();
//console.log('Taskservice Controller ', $scope.updateGridDataAwesome);
})
.error(function(data){
//something went wrong
console.log("Controller: error in adding task");
});
}
$scope.deleteTaskWithService = function(){
TaskService.deleteTask();
}
TaskService.getTasks(function(data){
$scope.tasks = data;
});
var interval = setInterval(function(){
var oldLength = $scope.tasks.length;
TaskService.getTasks(function(data){
console.log('lengths', oldLength, data.length)
if(oldLength != data.length){
//$scope.tasks = data;
//TaskService.taskList.push(data);
$scope.tasks = TaskService.getTasks();
}
});
}, 6000)
This might be what you're looking for, by using $interval you can set an interval every x seconds:
$interval(function() {
// Something to be executed after 1min (60000ms)
}, 60000);
And then inject $interval into your factory:
zazzleApp.factory('TaskService', function ($http, $interval).....
Try this:
$http
.post("/api/pin", {})
.success(function(data) {
$scope.$apply(function() {
$scope.pins.push(data);
});
});
reference: https://stackoverflow.com/a/24836089/3330947
Update:
I did it like this:
Service (fetch all accounts):
.factory('accountService', function ($http) {
var accountObj = {
async: function () {
var promise = $http.get('account/').then(function (response) {
return response;
});
return promise;
}
};
return accountObj;
})
Controller:
//Call get accounts service and put all accounts in $scope.accounts
var getAccounts = function () {
accountService.async().then(function (d) {
$scope.accounts = d.data;}
}
//Create new account and update array of accounts
$scope.createAccount = function () {
$scope.data = {
'id' : 0,
'customerId' : $scope.outputCustomer[0].id,
'camsId' : $scope.outputCams[0].id,
'camsPin' : parseInt($scope.camsPin),
'username' : $scope.username,
'password' : $scope.password,
'email' : $scope.email,
'acfUsername' : $scope.acfUsername,
'accountActive' : $scope.accountActive,
'agentId' : $scope.outputAgent[0].id,
'freeswitchIds' : freeswitchIds
};
$http.post('account/save', $scope.data).success(
function (data, status) {
$scope.accounts.push(data);
}).error(function () {
});
};
My add function is in controller, i thin it can be redone to be service but this work soo
The problem may be in success of addTask. TaskService.getTaskis async. So the execute order will be: 1. http request in TaskService.getTasks 2. TaskService.taskList.push(data); 3. $http success callback.
.success(function(data, status, headers, config) {
console.log(data);
TaskService.getTasks();
TaskService.taskList.push(data);//pushing the new task
//console.log("YYYYYYYYYYYYY -------->>>>>", defaultStart);
})
In this order, step 2 is pointless. Because step 3 code may override TaskService.taskList
for (var i = 0; i < dataFromServer.length; i++) {
TaskService.taskList[i] = dataFromServer[i];
};
And another wrong place:
$scope.tasks = TaskService.getTasks();
this line code appears twice. But TaskService.getTasks() returns undefined because you don't put keyword return.
In addition, your practice to use promise is wrong. $http leverages promise specification. Don't use callback since you used promise. You may need read promise docs.
Related
I make a call to a function that makes an ajax call like this:
send.startMonitoring({'fetchMethod': 'notificationInterval', 'lastmodif':0}).then(function(value){
console.debug(value);
});
But the error I'm getting is this:
Uncaught TypeError: Cannot read property 'then' of undefined in
jquery
As in above, I'm calling startMonitoring function which is on another page and passing an object for it to make ajax call to the server. That function returns value from server and I want to be able to do something with it. That's why I'm trying to use .then to process the value returned.
Since I'm getting the above error, how could I modify it so that
returned value can be processed? Also how and when I can use .then()?
var interface = (function(config) {
return {
transporter: function(options) {
return config.ajax(options);
},
startMonitoring: function(options) {
var PERIOD_NOT_VISIBLE = 60000;
var PERIOD_VISIBLE = 5000;
var timer = 0;
var timestring = 0;
(function callThis(timestamp) {
interface.transporter(options).then(function(value) {
if (value[1].notification[0].output == null) {
timestring = value[1].notification[0].lastmodif;
console.log(timestring);
return value;
}
}).catch(function(e) {
});
timer = setTimeout(function(){
callThis();
if (interface.isMonitoring() == 0 ) {
clearTimeout(timer);
}
}, (document.hidden) ? PERIOD_NOT_VISIBLE : PERIOD_VISIBLE);
})();
}
};
})(settings);
This is how ajax calls made:
ajax: function(opt) {
var defaultData = settings.getDefaultDataset();
var self = this;
var opt = $.extend({}, defaultData, opt);
var output = [];
return new Promise(function(resolve, reject) {
token = window.es.token;
opt[token] = "1";
jQuery.ajax({
method: "POST",
url: self.system.path+"/index.php",
"data": opt,
error: function() {
reject('error');
},
success: function(result) {
output.push(opt, result);
resolve(output);
}
});
});
}
Change startMonitoring to accept and call a callback parameter
startMonitoring: function(options, callback) {
var PERIOD_NOT_VISIBLE = 60000;
var PERIOD_VISIBLE = 5000;
var timer = 0;
var timestring = 0;
(function callThis(timestamp) {
interface.transporter(options).then(function(value) {
callback(value);
}).catch(function(e) {
});
timer = setTimeout(callThis, (document.hidden) ? PERIOD_NOT_VISIBLE : PERIOD_VISIBLE);
})();
},
Tidy up ajax to remove the Promise constructor anti-pattern, and to use .then of the promise returned by jQuery.ajax
ajax: function(opt) {
var defaultData = settings.getDefaultDataset();
var opt = $.extend({}, defaultData, opt);
var output = [];
var token = window.es.token;
opt[token] = "1";
return jQuery.ajax({
method: "POST",
url: this.system.path + "/index.php",
"data": opt,
})
.then(function(result) {
output.push(opt, result);
return output;
});
}
Change how you call startMonitoring to pass in a callback function
send.startMonitoring({'fetchMethod': 'notificationInterval', 'lastmodif':0}, function callback(value){
console.debug(value);
});
In jQuery, you can use the $.Deferred() function. For example :
function startMonitoring() {
var deferred = $.Deferred();
jQuery.ajax({
url: your_url,
type: 'GET',
success: function (data) {
deferred.resolve(data);
},
error: function (error) {
deferred.reject(error);
}
});
return deferred.promise();
}
Then, you can call your function :
startMonitoring().done(function (data) {
//Went well
}).fail(function (error) {
//Error
});
I'm trying to create a cloud Job that takes the users full name or username and saves it in lower case in another column. here's what I have so far:
Parse.Cloud.job('normaliseUsername',function(request, status) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.find({
success: function(items){
for (var i=0;i<items.length;i++) {
var user = items[i];
console.log(user);
var changed = user["nameChanged"];
if (changed === true) {
var username = user.username;
user.set("lowerCaseName",username.toLowerCase());
} else {
var realName = user["firstName"] + " " + user["lastName"];
user.set("lowerCaseName",realName.toLowerCase());
}
user.save();
}
}
});
});
This results in a new column, lowerCaseName, full of undefined.
how do I access properties of a PFUser in this instance? I have tried using user.get(''); but it says Cannot call method 'get' of undefined
Do it this way :
Parse.Cloud.job("normaliseUsername", function(request, status) {
Parse.Cloud.useMasterKey();
var count_user = 0;
var query = new Parse.Query(Parse.User);
query.descending('updatedAt');
query.Exist('nameChanged');
query.limit(1000);
return query.find().then(function(users) {
return Parse.Promise.when(users.map(function(user) {
count_user+= 1;
if (user.get("nameChanged")) {
user.set("canonical_firstname", user.get("username").toLowerCase());
} else {
var realName = user.get("firstname") + ' ' + user.get("lastname");
user.set("lowerCaseName", realName.toLowerCase());
}
return user.save();
}));
}).then(function() {
status.success("normaliseUsername with " + count_user + " user(s) updated.");
}, function(error) {
status.error("Uh oh, something went wrong.");
});
});
Your loop with for, will never works, you need to use Promise. More information here : http://blog.parse.com/learn/engineering/whats-so-great-about-javascript-promises/
The way the above script works, you will work with Promise in Parallel, not in Series : https://parse.com/docs/js/guide#promises
I have written a function , which is returning a value. In my main i am calling the function like this:
var fn_return_val = lesson.select_lesson(lesson1_text);
console.log("returned value is : " + fn_return_val);
And my function implementation is like(other file.js) :
module.exports = {
select_lesson:
function select_lesson(lesson_name) {
console.log('\n ************************* Lessson name: ' + lesson_name);
var desiredOption, status;
var repeter = element.all(by.repeater('item in items'));
repeter.then(function (items) {
items.forEach(function (icon) {
console.log('\n ************************* item');
icon.getText().then(function (txt) {
if (txt == lesson_name) {
desiredOption = icon;
}
})
}).then(function clickOption() {
if (desiredOption) {
var el = desiredOption.all(by.css('[ng-click="launchActivity()"]'));
var el_progress = desiredOption.all(by.css('.pna-progress'));
var abc = el.getAttribute('value').then(function (txt) {
status = txt;
return status
});
el_progress.getAttribute('style').then(function (progress) {
console.log('\n ************************* Lessson progress : ' + progress);
});
el.click();
}
});
});
}
};
The problem is function is returning "undefined" value, and the print statement console.log("returned value is : " + fn_return_val);
is executing before the function implementation
Can anyone help me on resolving this?
This is all about promises and protractor's Control Flow.
You need to resolve the promise and log the results inside then:
lesson.select_lesson(lesson1_text).then(function(fn_return_val) {
console.log("returned value is : " + fn_return_val);
});
And you also need to return from a function:
function select_lesson(lesson_name) {
...
// return here
return repeter.then(function (items) {
...
}).then(function clickOption() {
...
});
});
}
I am calling many services from a controller in angularJs, Some of my code depends with other service result. Sometimes it works well and but sometimes I am getting undefined error because service execution is not completed.
If I am waiting for completion of service execution(nested code,ie one service inside another service success function etc),which means the nested $http request only start once after parent completed,It will effect performance.
HOw can I solve this situation?
Sample code,
//init client list
clientService.list().success(function (data, status) {
$scope.clients = data.data;
console.log('clients retrieved');
//sales person
settingService.getSalesPerson().success(function (data, status) {
$scope.sales_persons = data;
console.log('sales persons retrieved');
//init item list
itemService.list().success(function (data, status) {
$scope.items = data.data;
console.log('items retrieved');
//quotation settings
settingService.getQuotationSettings().success(function (data, status) {
var qty = data[0];
$scope.quotation.note = data[0].note;
$scope.quotation.terms_and_condition = data[0].terms_and_condition;
console.log('settings retrieved');
//when change client,updating the address
var watchClientModel = function () {
$scope.$watch('selectedClient', function () {
$scope.quotation.client_id = $scope.selectedClient.id;
$scope.quotation.billing_street = $scope.selectedClient.address_info.billing_street;
$scope.quotation.billing_city = $scope.selectedClient.address_info.billing_city;
$scope.quotation.billing_pobox = $scope.selectedClient.address_info.billing_pobox;
$scope.quotation.billing_country = $scope.selectedClient.address_info.billing_country;
$scope.quotation.shipping_street = $scope.selectedClient.address_info.shipping_street;
$scope.quotation.shipping_city = $scope.selectedClient.address_info.shipping_city;
$scope.quotation.shipping_pobox = $scope.selectedClient.address_info.shipping_pobox;
$scope.quotation.shipping_country = $scope.selectedClient.address_info.shipping_country;
});
};
var watchSalesPersonModel = function () {
$scope.$watch('selectedPerson', function () {
$scope.quotation.sales_person_id = $scope.selectedPerson.id;
console.log('Sales person updated');
});
};
//when udpate
if ($scope.isUpdate) {
//Create Quotation
$scope.pageTitle = "Edit Quotation";
$scope.pageTitleIcon = "fa fa-pencil";
//init quotaion details
quotationService.get($routeParams.quotationId).success(function (data, status) {
$scope.quotation = data;
//get clients
$scope.selectedClient = _.findWhere($scope.clients, {id: $scope.quotation.client_id});
console.log('Client preselected');
//get sales person
$scope.selectedPerson = _.findWhere($scope.sales_persons, {id: $scope.quotation.sales_person_id});
console.log('Sales person preselected');
});
} else {
//when insert
$scope.selectedClient = $scope.clients[0];
$scope.selectedPerson = $scope.sales_persons[0];
$scope.quotation.items.push({
'item': null,
'quantity': 0.00,
'rate': 0.00
});
if (qty.auto_generate) {
$scope.quotation.quotation_number = qty.prefix_string + 1000 + Math.floor((Math.random() * 100000) + 1);
}
}
watchClientModel()
watchSalesPersonModel();
});
});
});
});
Here I put all service call as nested ladder.it is working fine but effecting performance.
If I bring back all service call outside,Getting error is $scope.selectedClient is undefined
If you have queries that are not interdependent, you can perform them separately from each other, and then wait on the results:
//init client list
var clients = clientService.list().success(function (data, status) {
$scope.clients = data.data;
console.log('clients retrieved');
});
//sales person
var sales = settingService.getSalesPerson().success(function (data, status) {
$scope.sales_persons = data;
console.log('sales persons retrieved');
});
//init item list
var items = itemService.list().success(function (data, status) {
$scope.items = data.data;
console.log('items retrieved');
});
//quotation settings
var quotes = settingService.getQuotationSettings().success(function (data, status) {
$scope.qty = data[0];
$scope.quotation.note = data[0].note;
$scope.quotation.terms_and_condition = data[0].terms_and_condition;
console.log('settings retrieved');
});
//when change client,updating the address
$scope.$watch('selectedClient', function () {
var selectedClient = $scope.selectedClient,
address_info = selectedClient.address_info,
quotation = $scope.quotation;
quotation.client_id = selectedClient.id;
quotation.billing_street = address_info.billing_street;
quotation.billing_city = address_info.billing_city;
quotation.billing_pobox = address_info.billing_pobox;
quotation.billing_country = address_info.billing_country;
quotation.shipping_street = address_info.shipping_street;
quotation.shipping_city = address_info.shipping_city;
quotation.shipping_pobox = address_info.shipping_pobox;
quotation.shipping_country = address_info.shipping_country;
});
$scope.$watch('selectedPerson', function () {
$scope.quotation.sales_person_id = $scope.selectedPerson.id;
console.log('Sales person updated');
});
// when all finished loading
$q.all([clients, sales, items, quotes]).then(function () {
// when udpate
if ($scope.isUpdate) {
//Create Quotation
$scope.pageTitle = "Edit Quotation";
$scope.pageTitleIcon = "fa fa-pencil";
//init quotaion details
quotationService.get($routeParams.quotationId).success(function (data, status) {
$scope.quotation = data;
//get clients
$scope.selectedClient = _.findWhere($scope.clients, {id: $scope.quotation.client_id});
console.log('Client preselected');
//get sales person
$scope.selectedPerson = _.findWhere($scope.sales_persons, {id: $scope.quotation.sales_person_id});
console.log('Sales person preselected');
});
} else {
//when insert
$scope.selectedClient = $scope.clients[0];
$scope.selectedPerson = $scope.sales_persons[0];
$scope.quotation.items.push({
'item': null,
'quantity': 0.00,
'rate': 0.00
});
if (qty.auto_generate) {
$scope.quotation.quotation_number = $scope.qty.prefix_string + 1000 + Math.floor((Math.random() * 100000) + 1);
}
}
});
I have looked both here on SO and Googled it but I am struggling to find any solution to this.
I have the below function and when I don't use the setTimeout() function and just call my polling function it works as expected. But when I try to wrap my polling function inside a setTimeout() it works once and then doesn't get called again unless the page is refreshed, I have already included a timestamp in the GET request to prevent using a cached response so I don't think this is the issue. I have also checked and this behaviour happens in IE9, Firefox and Chrome.
$scope.progressPolling = function () {
var time = new Date().toString();
console.log("time :" + time);
$http.get('pollprogress?time=' + time + '&id=' + $scope.jobID)
.success(function (data, status, headers, config) {
var percent = data.percentage;
if (parseInt($scope.progress) < 100) {
if (percent <= 100) {
$scope.progress = percent;
}
setTimeout(function() {
if (parseInt($scope.progress) < 100) {
temp = parseInt($scope.progress) + 1;
$scope.progressPolling();
};
}, 5000);
}
})
.error(function (data, status, headers, config) {
console.log("Error updating Progress: " + data);
});
}
Try to change it to $timeout
$scope.progressPolling = function () {
var time = new Date().toString();
console.log("time :" + time);
var stop;
$http.get('pollprogress?time=' + time + '&id=' + $scope.jobID)
.success(function (data, status, headers, config) {
var percent = data.percentage;
if (parseInt($scope.progress) < 100) {
if (percent <= 100) {
$scope.progress = percent;
}
stop = $timeout(function() {
if (parseInt($scope.progress) < 100) {
temp = parseInt($scope.progress) + 1;
$scope.progressPolling();
}
else{
$timeout.cancel(stop);
}
}, 5000);
}
})
.error(function (data, status, headers, config) {
console.log("Error updating Progress: " + data);
});
}
As a side note, create factory:
myModule.factory('delay', ['$q', '$timeout', function ($q, $timeout) {
return {
start: function () {
var deferred = $q.defer();
$timeout(deferred.resolve, 5000);
return deferred.promise;
}
};
}]);
After you can call it like:
$q.all([delay.start(), /*your method */]);`
The reason setTimeout appears to not work is because the callback function is executing outside of a digest cycle, so the bindings aren't updated. The $timeout service wraps the call with $scope.$apply(...) so the UI is updated. You could do it yourself in the setTimeout callback.