I have a factory defined like this:
mob.factory("OrderHelper", function() {
return {
lineItemPrice: function(lineItem) {
return lineItem.price * lineItem.quantity;
},
orderTotal: function(order) {
order.items.forEach(function (item)) {
total += lineItemPrice(item);
}
}
}
});
That problem is that I can't use the method "lineItemPrice" in "orderTotal" method.
It throws this error: Error: [$interpolate:interr] Can't interpolate: £{{orderTotal(order)}}
Can somebody please tell how can I call a method from a function in the same factory.
Thanks.
you could also do it like this:
mob.factory("OrderHelper", function() {
var methods = {};
methods.lineItemPrice = function(lineItem) {
return lineItem.price * lineItem.quantity;
};
methods.orderTotal = function(order) {
order.items.forEach(function (item)) {
total += methods.lineItemPrice(item);
}
};
return methods;
});
Try this (the revealing module pattern):
mob.factory("OrderHelper", function() {
var lineItemPrice = function(lineItem) {
return lineItem.price * lineItem.quantity;
};
var orderTotal = function(order) {
order.items.forEach(function (item)) {
total += lineItemPrice(item);
}
};
return {
lineItemPrice: lineItemPrice,
orderTotal: orderTotal
}
});
You can use angular.foreach() to iterate each items and supply the third parameter as the context of the callback function.
mob.factory("OrderHelper", function() {
return {
lineItemPrice: function(lineItem) {
return lineItem.price * lineItem.quantity;
},
orderTotal: function(order) {
var total = 0;
angular.forEach(order.items, function(item) {
total += this.lineItemPrice(item)
}, this); // add `this` as the context of the callback
return total;
}
}
});
Related
My filterProducts function makes a call to findIntersection which is present but I get an error findIntersection is undefined.
angular.module('BrandService', [])
.service('BrandService', function ($filter, DataService) {
var productDb;
var products;
return {
filterProducts(brands, priceRange) {
var filteredProducts = [];
var brandProducts = [];
var priceProducts = [];
var productsArray = [];
var brandChecked = false;
var priceChecked = false;
angular.forEach(brands, function (brand) {
if (brand.checked) {
brandChecked = true;
angular.extend(brandProducts,
$filter('filter')(productDb, { 'brand': brand.name }));
}
if (brandChecked) {
productsArray.push(brandProducts);
console.log('brandProducts = ', brandProducts)
}
});
angular.forEach(priceRange, function (price) {
if (price.checked) {
priceChecked = true;
let filteredProductDb = productDb.filter((prod) => {
return (prod.price >= price.low && prod.price <= price.high);
});
angular.extend(priceProducts, filteredProductDb);
}
});
if (priceChecked) {
productsArray.push(priceProducts);
// console.log('priceProducts = ', priceProducts)
}
if (!brandChecked && !priceChecked) {
filteredProducts = products;
} else {
if (productsArray.length > 1) {
filteredProducts = findIntersection(productsArray);
} else {
filteredProducts = productsArray[0];
}
}
return filteredProducts;
},
findIntersection(productsArray) {
console.log('findIntersection called')
var filteredProducts = [];
var filteredSet = new Set();
for(var i=0; i < productsArray.length - 1; i++) {
var products1 = productsArray[i];
var products2 = productsArray[i+1];
angular.forEach(products1, function(product1) {
angular.forEach(products2, function(product2) {
if(product1._id == product2._id) {
filteredSet.add(product1);
}
});
});
}
filteredProducts = Array.from(filteredSet);
return filteredProducts;
}
}
})
My filterProducts function makes a call to findIntersection which is present but I get an error findIntersection is undefined.
My filterProducts function makes a call to findIntersection which is present but I get an error findIntersection is undefined.
You are returning a javascript object with properties. You are not defining global functions.
You need to store the service returned before :
var service = { findProducts: ... , findIntersection: ... };
return service;
And instead of calling findIntersection, call service.findIntersection.
You have to make a reference to local object.
Simply change this: filteredProducts = findIntersection(productsArray);
to this: filteredProducts = this.findIntersection(productsArray);
I had this plnkr, working with an array. It had some problems (data being pushed into two arrays), but it was doing its job. Now I moved that array into a .json, and pizze.n is no longer being pushed into $scope.pizze nor $scope.orderList. I guess at this point a good solution would be to create a second .json and use it as my new orderList, or am I wrong? By the way, how do I do it or a better solution? Here's the updated code.
app.factory('elencoPizze', function($http) {
return {
getdata: function() {
return $http.get('json/pizze.json');
}
};
});
app.controller('showcaseCtrl', function($scope, $timeout, elencoPizze) {
$scope.pizze = [];
elencoPizze.getdata().success(function(data) {
$scope.pizze = data;
});
return;
$scope.orderList = [];
$scope.add = function(pizza) {
$scope.placeholder = 'Aggiungi altro?';
$scope.empty = false;
if ($scope.orderList.indexOf(pizza) === -1) {
pizza.n = 1;
return $scope.orderList.push(pizza);
} else {
return pizza.n += 1;
}
};
return $scope.remove = function(pizza) {
var lastRemoving;
if (pizza.n <= 1) {
pizza.n = 0;
lastRemoving = function() {
return $timeout((function() {
var index;
pizza.n = '';
index = $scope.orderList.indexOf(pizza);
$scope.orderList.splice(index, 1);
if ($scope.orderList.length === 0) {
$scope.example();
return $scope.empty = true;
}
}), 300);
};
return lastRemoving();
} else {
return pizza.n -= 1;
}
};
});
// ---
// generated by coffee-script 1.9.2
You haven't returned a promise from your factory. Change to:
return {
getdata: function() {
return $http.get('json/pizze.json').then(function(data) {
return data;
})
}
};
I have an AngularJS factory for some common local storage manipulation. It's a common set of functions against different variables. I am constructing it so that the functions are repeated depending on which variable needs to be manipulated. Likely not an elegant way to go about this so open to options.
The factory looks as follows. Is there a way to reuse functions depending on the variable without so much code bloat?
angular.module('app.datastore', [])
.factory('DataStore', function() {
var venue = angular.fromJson(window.localStorage['venue'] || '[]');
var prize = angular.fromJson(window.localStorage['prize'] || '[]');
function persist_venue() {
window.localStorage['venue'] = angular.toJson(venue);
}
return {
list_venue: function () {
return venue;
},
get_venue: function(venueId) {
for (var i=0; i<venue.length; i++) {
if (venue[i].id === venueId) {
return venue[i];
}
}
return undefined;
},
create_venue: function(venueItem) {
venue.push(venueItem);
persist_venue();
},
list_prize: function () {
return prize;
},
get_prize: function(prizeId) {
for (var i=0; i<prize.length; i++) {
if (prize[i].id === prizeId) {
return prize[i];
}
}
return undefined;
},
create_prize: function(prizeItem) {
venue.push(prizeIem);
persist_prize();
}
};
});
My approach is to return in the factory a function which will return a store of a type (venue, prize, ...)
angular.module('app.datastore', [])
.factory('DataStore', function () {
var getStoreFunction = function (storeName) {
var store = angular.fromJson(window.localStorage[storeName] || '[]');
function persist() {
window.localStorage[storeName] = angular.toJson(store);
};
return {
list: function () {
return store;
},
getItem: function (id) {
return store.find(function (elem) {
return elem.id === id;
});
},
createItem: function (item) {
store.push(item);
persist(store);
}
}
};
return { getStore : getStoreFunction };
});
you can create unlimited store by using
var venueStore = DataStore.getStore('venue');
//use of your store
venueStore.createItem({
id : venueStore.list().length + 1,
name : 'myVenue' + venueStore.list().length + 1
});
$scope.venues = venueStore.list();
you can create a factory per type if you want or use it directly in your controller as in this example : https://jsfiddle.net/royto/cgxfmv4q/
i dont know if your familiar with John Papa's angular style guide but you really should take a look it might help you with a lot of design questions.
https://github.com/johnpapa/angular-styleguide
anyway - i would recommend you use this approach -
angular.module('app.datastore', [])
.factory('DataStore', function () {
var venue = angular.fromJson(window.localStorage['venue'] || '[]');
var prize = angular.fromJson(window.localStorage['prize'] || '[]');
return {
list_venue: list_venue,
persist_venue: persist_venue,
get_venue: get_venue,
create_venue: create_venue,
list_prize: list_prize,
get_prize: get_prize,
create_prize: create_prize
};
function persist_venue() {
window.localStorage['venue'] = angular.toJson(venue);
}
function list_venue() {
return venue;
}
function get_venue(venueId) {
for (var i = 0; i < venue.length; i++) {
if (venue[i].id === venueId) {
return venue[i];
}
}
return undefined;
}
function create_venue(venueItem) {
venue.push(venueItem);
persist_venue();
}
function list_prize() {
return prize;
}
function get_prize(prizeId) {
for (var i = 0; i < prize.length; i++) {
if (prize[i].id === prizeId) {
return prize[i];
}
}
return undefined;
}
function create_prize(prizeItem) {
venue.push(prizeIem);
persist_prize();
} });
i like this approach because on the top you can see all the functions available in this factory nice and easy,
and you can also reuse every function you expose outside, inside also, so its very effective and organized,
hope that helped,
good luck.
I always manage pagination with angular
retrieve all the data from the server
and cache it client side (simply put it in a service)
now I have to cope with quite lot of data
ie 10000/100000.
I'm wondering if can get into trouble
using the same method.
Imo passing parameter to server like
page search it's very annoying for a good
user experience.
UPDATE (for the point in the comment)
So a possible way to go
could be get from the server
like 1000 items at once if the user go too close
to the offset (ie it's on the 800 items)
retrieve the next 1000 items from the server
merge cache and so on
it's quite strange not even ng-grid manage pagination
sending parameters to the server
UPDATE
I ended up like:
(function(window, angular, undefined) {
'use strict';
angular.module('my.modal.stream',[])
.provider('Stream', function() {
var apiBaseUrl = null;
this.setBaseUrl = function(url) {
apiBaseUrl = url;
};
this.$get = function($http,$q) {
return {
get: function(id) {
if(apiBaseUrl===null){
throw new Error('You should set a base api url');
}
if(typeof id !== 'number'){
throw new Error('Only integer is allowed');
}
if(id < 1){
throw new Error('Only integer greater than 1 is allowed');
}
var url = apiBaseUrl + '/' + id;
var deferred = $q.defer();
$http.get(url)
.success(function (response) {
deferred.resolve(response);
})
.error(function(data, status, headers, config) {
deferred.reject([]);
});
return deferred.promise;
}
};
};
});
})(window, angular);
(function(window, angular, undefined) {
'use strict';
angular.module('my.mod.pagination',['my.mod.stream'])
.factory('Paginator', function(Stream) {
return function(pageSize) {
var cache =[];
var staticCache =[];
var hasNext = false;
var currentOffset= 0;
var numOfItemsXpage = pageSize;
var numOfItems = 0;
var totPages = 0;
var currentPage = 1;
var end = 0;
var start = 0;
var chunk = 0;
var currentChunk = 1;
var offSetLimit = 0;
var load = function() {
Stream.get(currentChunk).then(function(response){
staticCache = _.union(staticCache,response.data);
cache = _.union(cache,response.data);
chunk = response.chunk;
loadFromCache();
});
};
var loadFromCache= function() {
numOfItems = cache.length;
offSetLimit = (currentPage*numOfItemsXpage)+numOfItemsXpage;
if(offSetLimit > numOfItems){
currentChunk++;
load();
}
hasNext = numOfItems > numOfItemsXpage;
totPages = Math.ceil(numOfItems/numOfItemsXpage);
paginator.items = cache.slice(currentOffset, numOfItemsXpage*currentPage);
start = totPages + 1;
end = totPages+1;
hasNext = numOfItems > (currentPage * numOfItemsXpage);
};
var paginator = {
items : [],
notFilterLabel: '',
hasNext: function() {
return hasNext;
},
hasPrevious: function() {
return currentOffset !== 0;
},
hasFirst: function() {
return currentPage !== 1;
},
hasLast: function() {
return totPages > 2 && currentPage!==totPages;
},
next: function() {
if (this.hasNext()) {
currentPage++;
currentOffset += numOfItemsXpage;
loadFromCache();
}
},
previous: function() {
if(this.hasPrevious()) {
currentPage--;
currentOffset -= numOfItemsXpage;
loadFromCache();
}
},
toPageId:function(num){
currentPage=num;
currentOffset= (num-1) * numOfItemsXpage;
loadFromCache();
},
first:function(){
this.toPageId(1);
},
last:function(){
this.toPageId(totPages);
},
getNumOfItems : function(){
return numOfItems;
},
getCurrentPage: function() {
return currentPage;
},
getEnd: function() {
return end;
},
getStart: function() {
return start;
},
getTotPages: function() {
return totPages;
},
getNumOfItemsXpage:function(){
return numOfItemsXpage;
},
search:function(str){
if(str===this.notFilterLabel){
if(angular.equals(staticCache, cache)){
return;
}
cache = staticCache;
}
else{
cache = staticCache;
cache = _.filter(cache, function(item){ return item.type == str; });
}
currentPage = 1;
currentOffset= 0;
loadFromCache();
}
};
load();
return paginator;
}
});
})(window, angular);
server side with laravel (All the items are cached)
public function tag($page)
{
$service = new ApiTagService(new ApiTagModel());
$items = $service->all();
$numOfItems = count($items);
if($numOfItems > 0){
$length = self::CHUNK;
if($length > $numOfItems){
$length = $numOfItems;
}
$numOfPages = ceil($numOfItems/$length);
if($page > $numOfPages){
$page = $numOfPages;
}
$offSet = ($page - 1) * $length;
$chunk = array_slice($items, $offSet, $length);
return Response::json(array(
'status'=>200,
'pages'=>$numOfPages,
'chunk'=>$length,
'data'=> $chunk
),200);
}
return Response::json(array(
'status'=>200,
'data'=> array()
),200);
}
The only trouble by now is managing filter
I've no idea how to treat filtering :(
Why function getPrice('Table') doesn't work in controller? It return undefined instead 400. That quite works in plain JS (without $scope).
function MyCtrl($scope) {
$scope.prices = [{
name: 'Bed',
price: 900
}, {
name: 'Table',
price: 400
}];
$scope.getPrice = function (name) {
$scope.prices.forEach(
function (el) {
if (el.name == name) {
return el.price;
} else {
return null;
}
}
);
}
};
Your getPrice function does not return anything. Try this one :
$scope.getPrice = function (name) {
$price = null;
$scope.prices.forEach(
function (el) {
if (el.name == name) {
$price = el.price;
return;
} else {
return;
}
}
);
return $price;
}