I'm attempting to learn the MEAN stack and learning to use the $http service.
I currently have a global check in place that is suppose to update my Sprints model, which looks like:
var SprintSchema = new Schema({
tasks: [{
type: String,
ref: 'Task'
}],
name: {
type: String
},
start: {
type: Date
},
end: {
type: Date
},
active: Boolean
});
The following controller should update the Sprint model when requested, and when I console.log the variable in my success function, it looks like what I would expect it to pass but it doesn't actually end up updating my model. Below is my code and an example of the console.log.
'use strict';
angular.module('inBucktApp')
.service('VariableService', function () {
// AngularJS will instantiate a singleton by calling "new" on this function
var ticketId = 'noTicketYet';
var ticketAssigneeName = 'noTicketNameYet';
return {
getPropertyId: function () {
return ticketId;
},
getPropertyName: function () {
return ticketAssigneeName;
}
,
setProperty: function(value, valueName) {
ticketId = value;
ticketAssigneeName = valueName;
}
};
})
.run(['$rootScope', '$http', 'socket', 'VariableService', function($rootScope, $http, socket, VariableService) {
$rootScope.sprintStart;
$http.get('/api/sprints').success(function(sprints) {
$rootScope.sprints = sprints.pop();
$rootScope.sprintStart = new Date($rootScope.sprints.start);
$rootScope.sprintEnd = new Date($rootScope.sprints.end);
socket.syncUpdates('sprints', $rootScope.sprints);
$http.get('/api/tasks').success(function(task) {
$rootScope.task = task;
$rootScope.taskPop = _.flatten($rootScope.task);
$rootScope.taskPopAgain = $rootScope.task.pop();
socket.syncUpdates('task', $rootScope.task);
$rootScope.updateTicket = function(){
//Goes through the entire array and check each element based on critera.
var taskIdsToAdd = [];
for(var i = 0; i < $rootScope.taskPop.length; i++){
var taskFind = $rootScope.taskPop[i];
//Logic if ticket is not in the sprint
if ((new Date(taskFind.start) >= $rootScope.sprintStart) && (new Date(taskFind.start) <= $rootScope.sprintEnd)){
taskFind.sprint = true;
taskIdsToAdd.push(taskFind._id);
$rootScope.sprints.tasks.push(taskFind._id);
$http.put("/api/tasks/"+taskFind._id,taskFind).success(function(task){
console.log('Logic 1 Ran!');
console.log($rootScope.sprintStart);
// socket.syncUpdates('taskPopAgain', taskFindPopAgain);
});
$http.put("/api/sprints/"+$rootScope.sprints._id,$rootScope.sprints).success(function(sprints){
console.log('Logic 2 Ran!');
console.log($rootScope.sprintStart);
console.log(sprints)
});
console.log($rootScope.sprints);
} else{
console.log('this doesnt work first');
};
//Logic if ticket is not in the sprint
if (new Date(taskFind.start) < $rootScope.sprintStart || new Date(taskFind.start) > $rootScope.sprintEnd){
taskFind.sprint = false;
$http.put("/api/tasks/"+taskFind._id,taskFind).success(function(task){
console.log(task);
});
}else{
console.log('this doesnt work');
};
}
};
$rootScope.updateTicket();
});
});
}]);
Console.Log of console.log(sprints)
Anyone have any idea what I'm doing incorrect here?
Thanks for the help guys.
Related
Original code from the Point of Sale module
In the point_of_sale module there is a list of objects as the following
module.PosModel = Backbone.Model.extend({
models: {
// [...]
{
model: 'pos.session',
fields: ['id', 'journal_ids','name','user_id','config_id','start_at','stop_at','sequence_number','login_number'],
domain: function(self){ return [['state','=','opened'],['user_id','=',self.session.uid]]; },
loaded: function(self,pos_sessions){
self.pos_session = pos_sessions[0];
var orders = self.db.get_orders();
for (var i = 0; i < orders.length; i++) {
self.pos_session.sequence_number = Math.max(self.pos_session.sequence_number, orders[i].data.sequence_number+1);
}
},
},
{
model: 'product.product',
fields: ['display_name', 'list_price','price','pos_categ_id', 'taxes_id', 'ean13', 'default_code',
'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type', 'description_sale', 'description',
'product_tmpl_id'],
domain: [['sale_ok','=',true],['available_in_pos','=',true]],
context: function(self){ return { pricelist: self.pricelist.id, display_default_code: false }; },
loaded: function(self, products){
self.db.add_products(products);
},
// [...]
}
And then the information of the data is loaded like this
load_server_data: function(){
var self = this;
var loaded = new $.Deferred();
var progress = 0;
var progress_step = 1.0 / self.models.length;
var tmp = {}; // this is used to share a temporary state between models loaders
function load_model(index){
if(index >= self.models.length){
loaded.resolve();
}else{
var model = self.models[index];
self.pos_widget.loading_message(_t('Loading')+' '+(model.label || model.model || ''), progress);
var fields = typeof model.fields === 'function' ? model.fields(self,tmp) : model.fields;
var domain = typeof model.domain === 'function' ? model.domain(self,tmp) : model.domain;
var context = typeof model.context === 'function' ? model.context(self,tmp) : model.context;
var ids = typeof model.ids === 'function' ? model.ids(self,tmp) : model.ids;
progress += progress_step;
if( model.model ){
if (model.ids) {
var records = new instance.web.Model(model.model).call('read',[ids,fields],context);
} else {
var records = new instance.web.Model(model.model).query(fields).filter(domain).context(context).all()
}
// [...]
What I have tried. First try
So, I would like to change the domain field of the product.product model. I am trying with this
if (typeof jQuery === 'undefined') { throw new Error('Product multi POS needs jQuery'); }
+function ($) {
'use strict';
openerp.pos_product_multi_shop = function(instance, module) {
var PosModelParent = instance.point_of_sale.PosModel;
instance.point_of_sale.PosModel = instance.point_of_sale.PosModel.extend({
load_server_data: function(){
console.log('-- LOAD SERVER DATA');
var self = this;
self.models.forEach(function(elem) {
if (elem.model == 'product.product') {
// return [['id', 'in', [2]]]; // if I return this domain it works well
domain_loaded = function() {
return new instance.web.Model('product.product').call(
'get_available_in_pos_ids',
[self.pos_session.config_id[0]],
)
}
elem.domain = $.when(domain_loaded);
}
})
var loaded = PosModelParent.prototype.load_server_data.apply(this, arguments);
return loaded;
},
});
}
}(jQuery);
If I return a domain directly it works. But if I replace it with a function that calls a python function with call, the domain is not loaded well: [['sale_ok','=',true],['available_in_pos','=',true]]. I've tried with $.when and without it and it does not work.
In addition elem.domain must be a function because self.pos_session only exists when all the previous model information is executed.
Second try
I have tried this following code as well:
if (elem.model == 'product.product') {
// return [['id', 'in', [2]]]; // if I return the domain like this it works
console.log('>> OLD DOMAIN')
console.log(elem.domain);
elem.domain = function() {
console.log('>>> PRODUCT SESSION');
console.log(self.pos_session);
var product_product_obj = new instance.web.Model('product.product');
return product_product_obj.call(
'get_available_in_pos_ids',
[self.pos_session.config_id[0]],
)
}
console.log('>> NEW DOMAIN')
console.log(elem.domain);
}
So first '>> OLD DOMAIN' is printed, then '>> NEW DOMAIN' and, at last '>>> PRODUCT SESSION' is printed. So the function is executed. But the the domains is not being returned well.
Third try. With "then"
And I cannot use then because I need to do the variable assignation. But on the other hand the assignation is well done becase when I print the new domain the function appears in the log.
Even if I use then I am getting the result well from python
var domain_return = product_product_obj.call(
'get_available_in_pos_ids',
[self.pos_session.config_id[0]],
).then(function(result) {
console.log('>> RESULT: ');
console.log(result)
});
I also tried with other promise, but I get a pending result that is ignored and all the products are shown
elem.domain = function() {
return new Promise(function next(resolve, reject) {
console.log('>>> PRODUCT SESSION');
console.log(self.pos_session);
var product_product_obj = new instance.web.Model('product.product');
var domain_return = product_product_obj.call(
'get_available_in_pos_ids',
[self.pos_session.config_id[0]],
).then(function(result) {
console.log('>> RETURN: ');
console.log(result);
resolve(result);
});
console.log('>> DOMAIN RETURN: ');
console.log(domain_return);
});
}
The rest of the domains of the object are calculated without calling python functions. So I can't copy an example from other place
So, is there a way to avoid the pending result? I cannot use async/await yet.
Maybe to make it syncronous will help but I know this should be avoided
Finally I found a workaround overriding the loaded function where all the products are already loaded
var PosModelParent = instance.point_of_sale.PosModel;
instance.point_of_sale.PosModel = instance.point_of_sale.PosModel.extend({
load_server_data: function(){
let self = this;
self.models.forEach(function(elem) {
if (elem.model == 'product.product') {
elem.fields = ['display_name', 'list_price','price','pos_categ_id', 'taxes_id', 'ean13', 'default_code',
'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type', 'description_sale', 'description',
'product_tmpl_id', 'available_in_pos_ids'];
elem.loaded = function(self, products){
console.log('>> PRODUCTS: ');
console.log(products);
var shop_id = self.pos_session.config_id[0];
var new_products = [];
products.forEach(function(prod) {
if (prod.available_in_pos_ids.includes(shop_id)) {
new_products.push(prod);
}
})
self.db.add_products(new_products);
}
}
})
var loaded = PosModelParent.prototype.load_server_data.apply(this, arguments);
return loaded;
},
});
I am trying to consume my spring rest service using angularjs client following this link
Create,update and read parts are working. When I try to delete, its showing this error.
Error: [$resource:badcfg] Error in resource configuration for action
get. Expected response to contain an object but got an array
(Request: GET http://localhost:8080/SpringRestExample/employee)
Why i am getting GET request in DELETE method?
employee_service.js
'use strict';
App.factory('Employee', ['$resource', function ($resource) {
return $resource(
'http://localhost:8080/SpringRestExample/employee/:id',
{id: '#employeeId'},
{
update: {
method: 'PUT'
}
}
);
}]);
employee_controller.js
'use strict';
App.controller('EmployeeController', ['$scope', 'Employee', function($scope, Employee) {
var self = this;
self.employee= new Employee();
self.employees=[];
self.fetchAllEmployees = function(){
self.employees = Employee.query();
};
self.createEmployee = function(){
self.employee.$save(function(){
self.fetchAllEmployees();
});
};
self.updateEmployee = function(){
self.employee.$update(function(){
self.fetchAllEmployees();
});
};
self.deleteEmployee = function(identity){
var employee = Employee.get({employeeId:identity}, function() {
employee.$delete(function(){
console.log('Deleting employee with id ', identity);
self.fetchAllEmployees();
});
});
};
self.fetchAllEmployees();
self.submit = function() {
if(self.employee.employeeId==null){
console.log('Saving New Employee', self.employee);
self.createEmployee();
}else{
console.log('Updating employee with id ', self.employee.employeeId);
self.updateEmployee();
console.log('Employee updated with id ', self.employee.employeeId);
}
self.reset();
};
self.edit = function(employeeId){
console.log('id to be edited', employeeId);
for(var i = 0; i < self.employees.length; i++){
if(self.employees[i].employeeId === employeeId) {
self.employee = angular.copy(self.employees[i]);
break;
}
}
};
self.remove = function(employeeId){
console.log('id to be deleted', employeeId);
if(self.employee.employeeId === employeeId) {//If it is the one shown on screen, reset screen
self.reset();
}
self.deleteEmployee(employeeId);
};
self.reset = function(){
self.employee= new Employee();
$scope.myForm.$setPristine(); //reset Form
};
}]);
Your issue could be when you call Employee.get({employeeId:identity}, ...) prior to deleting the employee. This will load the employee before deletion and it will do a GET request on 'http://localhost:8080/SpringRestExample/employee/:id'.
For this query to work properly, you need to provide id, which you haven't done, so it might just be leaving out that part of the URL. You provided employeeId, which is only used for mapping the id parameter to the Employee objects. Try replacing the query above with {id: identity}.
I am struggling with some Javascript that I am currently working on. So I have a simple web application and the following is the AngularJS stuff:
app.filter('startFrom', function () {
return function (input, start) {
if (input) {
start = +start;
return input.slice(start);
}
return [];
};
});
app.controller('MainCtrl', ['$scope', 'filterFilter', function ($scope, filterFilter) {
$scope.items = ["name 1", "name 2", "name 3"
];
$scope.addLink = function () {
$scope.errortext = "";
if (!$scope.newItem) {return;}
if ($scope.items.indexOf($scope.newItem) == -1) {
$scope.items.push($scope.newItem);
$scope.errortext = "submitted";
} else {
$scope.errortext = " in list";
}
};
So I have these and I there is html side of it which displays the list of items. Users have options to add and delete these items from items array.
Question. How do I make sure that when user added or deleted items from the array can still see the edited list after reloading the page? Can someone suggest a way of dealing with it? Would it be possible to store in cookies and after each add/delete action update them, if so how?
thanks
UPDATE:
So I changed the script but it still does not seem to be working.
var app = angular.module('App', ['ui.bootstrap']);
app.filter('startFrom', function () {
return function (input, start) {
if (input) {
start = +start;
return input.slice(start);
}
return [];
};
});
app.factory('ItemsService', ['$window', function ($window) {
var storageKey = 'items',
_sessionStorage = $window.sessionStorage;
return {
// Returns stored items array if available or return undefined
getItems: function () {
var itemsStr = _sessionStorage.getItem(storageKey);
if (itemsStr) {
return angular.fromJson(itemsStr);
}
},
// Adds the given item to the stored array and persists the array to sessionStorage
putItem: function (item) {
var itemsStr = _sessionStorage.getItem(storageKey),
items = [];
if (itemStr) {
items = angular.fromJson(itemsStr);
}
items.push(item);
_sessionStorage.setItem(storageKey, angular.toJson(items));
}
}
}]);
app.controller('MainCtrl', ['$scope', 'filterFilter', 'ItemsService', function ($scope, filterFilter, ItemsService) {
$scope.items = ItemsService.get($scope.items)
$scope.addLink = function () {
$scope.errortext = "";
if (!$scope.newItem) {
return;
}
if ($scope.items.indexOf($scope.newItem) == -1) {
$scope.items.push($scope.newItem);
$scope.errortext = "Submitted";
$scope.items = ItemsService.put($scope.items)
} else {
$scope.errortext = "Link in the list";
}
};
$scope.removeItem = function (item) {
$scope.items.splice($scope.items.indexOf(item), 1);
$scope.items = ItemsService.put($scope.items)
$scope.resetFilters;
};
}]);
Any help how to fix it and how to make sure that if user does not have any items it will use the default $scope.items = ["name 1", "name 2", "name 3"]; ?
You could create a simple get/set service that is using $cookies. It could be like this :
angular.module('myApp')
.factory('ItemsService', ['$cookies', function($cookies) {
var cookieName = 'items'
return {
get: function(defaults) {
return $cookies.get(cookieName).split(',') || defaults
},
put: function(items) {
var expireDate = new Date()
expireDate.setDate(expireDate.getDate() + 1);
$cookies.put(cookieName, items.join(','), { expires: expireDate } )
}
}
}]);
Include ItemsService in your controller and in the main function
$scope.items = ItemsService.get($scope.items)
to get the edited list stored in $cookies (if any), and save the list in addLink() by
ItemsService.put($scope.items)
I would like to extend #davidkonrad's answer here, by making his service to use sessionStorage. Since using sessionStorage is most suited for your usecase.
angular.module('myApp')
.factory('ItemsService', ['$window', function($window) {
var storageKey = 'items',
_sessionStorage = $window.sessionStorage;
return {
// Returns stored items array if available or return undefined
getItems: function() {
var itemsStr = _sessionStorage.getItem(storageKey);
if(itemsStr) {
return angular.fromJson(itemsStr);
}
return ['name1', 'name2', 'name3']; // return default value when there is nothing stored in sessionStore
},
// Adds the given item to the stored array and persists the array to sessionStorage
putItem: function(item) {
var itemsStr = _sessionStorage.getItem(storageKey),
items = [];
if(itemStr) {
items = angular.fromJson(itemsStr);
}
items.push(item);
_sessionStorage.setItem(storageKey, angular.toJson(items));
}
}
}]);
I am just playing around with ionic and local storage. I am messing with the ionic example app to customise it a bit and I am running into a snag. Basically the home page lists items. Once the user goes into the item they can add to a task list.
To create an item on the home page the user opens a modal and enters info (title,date, etc...) and then stores the items in local storage. The item array has a nested array for the task list.
once the user goes into an item they can open a modal that adds a task. Once submitted the task is pushed to the nested array which works great and outputs:
However, when the user goes back to the home page where all items are listed there are just a number of empty objects repeated (looking in local storage the object is perfect).
My list controller and inner list controller:
.controller('ProfileCtrl', function ($filter, $scope, $stateParams, $timeout, $ionicModal, Eventers) {
var createEventer = function(eventerId, eventerTitle, eventerVenue, eventerDay, eventerMonth, eventerYear, eventerDate) {
var newEventer = Eventers.newEventer(eventerId,eventerTitle, eventerVenue, eventerDay, eventerMonth, eventerYear, eventerDate);
$scope.eventers.push(newEventer);
Eventers.save($scope.eventers);
}
$scope.eventers = Eventers.all();
$ionicModal.fromTemplateUrl('new-event.html', function(modal) {
$scope.eventerModal = modal;
},
{
focusFirstInput: false,
scope: $scope
});
////////////////////////////////
$scope.date = new Date();
console.log($scope.date);
////////////////////////////////
$scope.createEventer = function(eventer, index) {
var eventerId = localStorage.clickcount;
var eventerTitle = eventer.title;
var eventerVenue = eventer.venue;
var eventerDay = eventer.day;
var eventerMonth = eventer.month;
var eventerYear = eventer.year;
var eventerDate = $scope.date;
if (eventerId,eventerTitle, eventerVenue, eventerDay, eventerMonth, eventerYear, eventerDate) {
createEventer(eventerId,eventerTitle, eventerVenue, eventerDay, eventerMonth, eventerYear, eventerDate);
$scope.eventerModal.hide();
eventer.title = "";
eventer.venue = "";
eventer.day = "";
eventer.month = "";
eventer.year = "";
}
console.log(eventer);
};
})
and my inner controller:
.controller('ProfileInnerCtrl', function ($scope, $stateParams,$ionicModal, $timeout, Eventers) {
$scope.eventer = Eventers.get($stateParams.eventerId);
$ionicModal.fromTemplateUrl('new-task.html', function(modal) {
$scope.eventerModal = modal;
},
{
focusFirstInput: false,
scope: $scope
});
$scope.createTask = function(task) {
$scope.eventer.tasks.push({
title: task.title
});
console.log(task.title);
Eventers.save($scope.eventer);
task.title = "";
$scope.eventerModal.hide();
};
$scope.newTask = function() {
$scope.eventerModal.show();
};
$scope.closeNewTask = function() {
$scope.eventerModal.hide();
}
$scope.completionChanged = function() {
Eventers.save($scope.eventers);
};
})
--------EDIT: Add Factory-------
.factory('Eventers', function() {
/**/
return {
all: function() {
var eventerString = window.localStorage['eventers'];
if (eventerString) {
return angular.fromJson(eventerString);
}
return [];
},
save: function(eventers) {
window.localStorage['eventers'] = angular.toJson(eventers);
},
newEventer: function(eventerId, eventerTitle,eventerVenue , eventerDay, eventerMonth, eventerYear, eventerDate) {
return {
id: eventerId,
title: eventerTitle,
venue: eventerVenue,
day: eventerDay,
month: eventerMonth,
year: eventerYear,
date: eventerDate,
tasks: []
};
},
get: function(eventerId){
var hell = window.localStorage['eventers'];
var eventers = JSON.parse(hell);
for (var i = 0; i < eventers.length; i++) {
if (parseInt(eventers[i].id) === parseInt(eventerId)){
console.log(eventerId);
return eventers[i];
}
}
return null;
}
}
});
Added images: the first 2 show the home page and local storage before added a task. the last 2 show local storage after adding task and the home page
Well, when you create a new task you save $scope.eventer in the localStorage, which only has titles in it.
Why not push the whole task object in the $scope.eventer?
$scope.createTask = function(task) {
$scope.eventer.tasks.push(task);
...
EDIT:
Your eventers in localStorage after adding task are not an array, so the ng-repeat takes each key in the object.
try Eventers.save([$scope.eventer]); for test, but you'lll have to rethink the whole proccess, what when you have more than one object in the array? you will lose the old ones this way
I am creating a simple AngularJS SPA using an API to load data into Mongoose.
My app just adds, displays and edits a list of members. It works when I just store the members in an array in my factory service but now I want to change it to hook up to Mongoose via an API.
Factory
app.factory('SimpleFactory', ['$http', function($http){
var factory = {};
var members = $http.get('/api/members')
factory.getMembers = function ()
{
return members = $http.get('/api/members');
}
factory.getMember = function (index) {
if (index >=0 && index < members.length ) {
return members[index] = $http.get('/api/members/' + member_id )
}
return undefined
}
factory.addMember = function(member) {
return $http.post('/api/members',member)
}
factory.updateMember = function(index,member) {
$http.put('/api/members/' + member_id, member)
}
return factory;
}])
Controller
app.controller('MembersController', ['$scope','SimpleFactory',
function ($scope,SimpleFactory) {
SimpleFactory.getMembers()
.success(function(members) {
$scope.members = members;
});
$scope.addMember = function()
{
var member = {
name: $scope.newMember.name,
address: $scope.newMember.address,
age : $scope.newMember.age,
level : $scope.newMember.level,
swimmer : $scope.newMember.swimmer,
email : $scope.newMember.email,
regdate : $scope.newMember.regdate,
}
SimpleFactory.addMember(member)
.success(function(added_member)
{
$scope.members.push(added_member);
$scope.newMember = { }
} );
}
}])
But I am not sure how to change my controller for updating a member, it is coded as follows to pick up the members from an array in my factory setting, how do I code it to pick up members from Mongoose via API:
app.controller('MemberDetailController', ['$scope', '$location', '$routeParams', 'SimpleFactory',
function($scope, $location, $routeParams, SimpleFactory) {
$scope.member = {
index: $routeParams.member_index,
detail: SimpleFactory.getMember($routeParams.member_index)
}
$scope.updateMember = function() {
SimpleFactory.updateMember($scope.member.index,
$scope.member.detail)
$location.path('/members')
}
}
])
Can anyone help, its not a complicated app but I'm only learning and I am stuck here!
Thanks
You $scope.member object should set after getMember promise success.
Code
SimpleFactory.getMember($routeParams.member_index).then(function(data){
$scope.member = {
index : $routeParams.member_index,
detail : data.user
};
});
Apart from that you need to make sure getMember method should always return a promise while index is 0
factory.getMember = function (index) {
var deferred = $q.defer();
if (index >=0 && index < members.length ) {
return members[index] = $http.get('/api/members/' + member_id )
}
deferred.resolve;
}
Update
For calling update method you need to do change service first which would return a promise
factory.updateMember = function(index,member) {
return $http.put('/api/members/' + member_id, member)
}
Then call factory.updateMember resolve that promise and then do $location.path
$scope.updateMember = function() {
SimpleFactory.updateMember($scope.member.index, $scope.member.detail)
.then(function(data) {
$location.path('/members')
});
};