finding $resource objects in array and skip push if exists / angular - arrays

I'm breaking my head on this one.
From my backend I fetch json data for my typeahead input field.
once a value is selected I fetch the full object from the backend by using the unique id that came with the auto complete response.
next thing i do is to push this object into an array and then i itterate over this array to display in the html all fine.
but i would like to test first if the object is already in the array.
for that i'm using array.indexOf property, however for some reason it will never find a match: i hope someone can help me:
here is the code:
the factory:
productServices.factory('Product', ['$resource',
function($resource){
return $resource('http://127.0.0.1:5000/products/:id', {id: '#id'}, {
query: { method:'GET',
isArray:false,
responseType:'json',
cache:true},
update: { method:'PUT' }
fetch product from backend and push to an array:
$scope.onSelect = function ($item, $model, $label) {
$scope.$item = $item
// call the .addProduct service to push the product.get result into a list
acProductService.addProduct(Product.get({ id: $scope.$item.id }));
// this is to retrieve the list
$scope.products = acProductService.getProducts();
// reset field
$scope.selected = '';
};
service to push the data to the array and to list the array (so here on addProduct i would like to test if the object is already in the array)
autocompServices.service('acProductService', function() {
var productList = [];
var addProduct = function(newObj) {
console.log(productList.indexOf(newObj)); ---- here is my issue it will never find the newObj despite i've added it many times
productList.push(newObj);
console.log(productList.indexOf(newObj)); -- does work but i need to check before pushing to the list and not after;
};
var getProducts = function(){
return productList;
};
return {
addProduct: addProduct,
getProducts: getProducts
};
i'm guessing the $resource.get returns something that is unique irrespective of the object retrieved from the back-end is actually unique. any help please.. thanks

Related

Getting data from a service always return the same value (not the updated) on AngularJs

i'm doing a crud like a phone list,
in a view i want to add persons to my list, and in another view i want to show that peoples,
for do that, i'm using two controllers, and a service to store my array with the persons.
to add peoples i'm using set way to pushing it to array when i click on a button and thats works fine(possible to see with console.log at salvar function in service).
My problem is, when i go to show the list with the get method after added some persons with set, the get method still returning my list like she starts (empty). how i can fix this?
angular
.module('moduloLista')
.factory('addMostrarService', addMostrarService);
function addMostrarService() {
var listacontatos = [
];
var salvar = function(obj){
listacontatos.push(obj);
};
var getLista = function(){
return listacontatos;
};
return{
salvar: function(obj){
salvar(obj);
},
getLista: function(){
return getLista();
}
}
}
^ Service Code
angular
.module('moduloLista')
.controller('testeController',testeController);
testeController.$inject = ['addMostrarService'];
function testeController(addMostrarService) {
var vm = this;
vm.dadoslista = addMostrarService.getLista();
console.log('vm.dadoslista');
}
^ controller to get the list from service.

populating data from multiple async sources in angularjs and merging in an object

I'm new to angularJS and the whole concept of deferred/promises so this might not be the cleanest of the codes but want to know what am i doing wrong here.
Basically in factory in my first async call I'm fetching data(stockname and quantity) from Firebase then
in my second async call I'm trying to get additional details like current price using $http. While i successfully get the details I'm unable to merge it in an object in my controller and show it as a table using ng-repeat.
//below is my Factory snippet
factory.getStocks = function(){
var promise = firebase.database().ref().child("Stock").once('value');
var qpromise = $q.when(promise).then(callback)
return stock;
};
function callback(snapshot){
var i=0;
snapshot.forEach(function(child)
{
stocks[i] = {
name: child.key,
holding: child.val(),
price: -1,
value: -1
};
i = i+1;
});
return stocks;
}
Controller as below: but get an error "Unable to get property '0' of undefined or null reference" I'm assuming since the stocks might not be populated yet. Is there a better way to populate the price
portfolio.controller('updatePortfolio', function($scope,stockFactory,$http){
init();
function init()
{
$scope.stocks = stockFactory.getStocks();
}
}
function updatePrice()
{
$http.get('//call for api')
.then(function(response))
{
$scope.stocks[0].price = response.data; //error "Unable to get property '0' of undefined or null reference"
}
// similar call to update rest of the stocks... planning to do it using $q.all if i can somehow figure how to merge this.
}
});
front end:
<table>
<tr>
<th>Stock</th><th>Price</th><th>Holding</th><th>Value</th>
</tr>
<tr data-ng-repeat="s in stocks">
<td>{{s.name}}</td>
<td>{{s.price}}</td>
<td>{{s.holding}}</td>
<td>{{s.price * s.holding}}</td>
</tr>
You're returning an undefined object in your factory method. Return the promise of stocks instead.
factory.getStocks = function(){
var promise = firebase.database().ref().child("Stock").once('value');
return promise.then(callback) //returns stocks
};
And in your controller
portfolio.controller('updatePortfolio', function($scope,stockFactory,$http){
init();
function init() {
//set your scope variables inside the promise success handler
stockFactory.getStocks().then(function(stocks) {
$scope.stocks = stocks;
}).then(function(){
$http.get(api call).then(function(response) {
$scope.stock[0].price = response.data;
});
}
});

angular grep or filter to get an object given an ID

I have a json array of Category objects from my database. (I am storing it in vm.data in my controller, which is bound to an angular repeater.)
Now I need to go back and get the SubCats in each category using the 'Category' field in each SubCat.
Here is my generic data getter:
function getData(params, callback) {
$http({
method: 'GET',
url: 'database.php',
params: params
}).then(function successCallback(response) {
callback(response.data);
});
}
So, to get my Categories, I do:
function getCats() {
var params = {};
params.table = "Categories";
getData(params,buildCats);
};
which calls back to
function buildCats(data) {
vm.data = data;
$.each(vm.data,function(index,value){
getSubCat(value.uID);
});
};
then, one by one it gets the SubCats:
function getSubCat(categoryId) {
var params = {};
params.table = "SubCats";
params.where_field = "Category";
params.where_value = categoryId;
getData(params, buildSubCat);
};
which calls back to this: (I no longer have the Category Id, so I have to go looking for it in my SubCat data)
function buildSubCat(data) {
var categoryId = data[0].Category;
$filter('filter')(vm.data, function(el){
el.uID==categoryId;
}, true).SubCats = data;
}
and it is here I am running into trouble.
I need to get hold of the unique Category object in vm.data - the actual object, not a copy of it - whose uID equals the ID of the SubCats I am currently processing, then ADD the current SubCat object to it. The above does not work. At least, I never see the SubCats within the Categories in vm.data.
I tried to pull it apart, like this:
var foo = $filter('filter')(vm.data, function(el){
el.uID==categoryId;
}, true);
foo.SubCats = data;
but foo is new instance of the Category object, not a reference to the one in vm.data, so my adding is not affecting vm.data.
I suppose I could try to replace vm.data[n] with foo, but this seems a poor practice.
How can I asynchronously retrieve the Categories and SubCats and combine them?
Something tickling the back of my brain tells me I should be passing the actual Category object into the getData, so it is directly available in the callback, but I'm not sure if that makes sense.
OK, I figured out a solution, just not sure if it's the best.
I accept a third param to pass the target object into the getData function:
function getData(params, target, callback) {
$http({
method: 'GET',
url: 'index.php',
params: params
}).then(function successCallback(response) {
callback(target, response.data);
});
}
In my getCats, I pass vm.data as the target param (though there is no need to, as will be seen in a moment).
function getCats() {
var params = {};
params.table = "Categories";
params.sort_field = "Order";
params.sort_dir = "ASC";
getData(params, vm.data, buildCats);
};
Now, I should be able to do this:
function buildCats(target, data) {
target = data;
$.each(target,function(index, catObj){
getSubCat(catObj);
});
};
But for some reason it does not work. target seems to have lost its reference to vm.data. Bonus points if you can figure out what went wrong.
But that's OK - I don't need the target - I can assign the results directly to vm.data:
function buildCats(target, data) {
vm.data = data;
$.each(vm.data,function(index, catObj){
getSubCat(catObj);
});
};
I can now pass the actual Category object itself to the getSubCat call:
function getSubCat(categoryObject) {
var params = {};
params.table = "SubCats";
params.where_field = "Category";
params.where_value = categoryObject.uID;
params.sort_field = "Order";
params.sort_dir = "ASC";
getData(params, categoryObject, buildSubCat);
};
which means I now have the actual object in the callback:
function buildSubCat(categoryObject, data) {
categoryObject.SubCats = data;
};
And my HTML looks like this:
<div class="category" ng-repeat="cat in vm.data">
<h2>{{cat.Name}}</h2>
<div class="subcategory" ng-repeat="SubCat in cat.SubCats">
<h3>{{SubCat.Name}}</h3>
</div>
</div>

Array populated witin 'service' but empty when referenced by any 'controller'

I have an AngularJS service which should get a JSON object and create three arrays based on differing criteria (all, searchable and has coordinates). These arrays need to be referenced by more than one controller, hence the use of a service.
When I test any of the three arrays the array within the service itself (as below), all three are correctly populated.
However, all three of my arrays are empty when referenced by any controller.
What am I missing here?
app.service('$stationsList', ['$http', function($http){
var stationsList = [],
searchableStations = [],
locatableStations = [];
$http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm){ // Map all stations...
stationsList = res.data; // Set all stations to 'stationsList'
if(elm.link.indexOf(".xml") > -1) // Check to see if the station is searchable (has a full link)
searchableStations.push(elm); // It does - add the station to 'searchableStations'
if( // Check to see if the station can be checked as the closest station (has coordinates)
isFinite(parseFloat(elm.latitude)) &&
isFinite(parseFloat(elm.longitude))
)
locatableStations.push(elm); // It does - add the station to 'locatableStations'
});
console.log(stationsList);
console.log(searchableStations);
console.log(locatableStations);
});
return{
getList: function(){
return stationsList;
},
setList: function(value){
stationsList = value;
},
getSearchable: function(){
return searchableStations;
},
setSearchable: function(value){
searchableStations = value;
},
getLocatable: function(){
return locatableStations;
},
setLocatable: function(value){
locatableStations = value;
}
};
}]);
Example of how I'm referencing service -
app.controller('searchCtrl', ['$scope', '$http', '$localStorage', '$stationsList', function($scope, $http, $localStorage, $stationsList){
$scope.stationsList = $stationsList.getSearchable(); // Grab a list of all stations
$scope.selectStation = click_selectStation; // Handle clicks of a station within the 'searchCtrl' controller
$scope.localStorage = $localStorage.$default({ // Grab the local storage (so that it can be updated when the user selects a station)
recentStations: [] // Set a default value of '[]' for recentStations in case it doesn't exist
});
}]);
Edit
Derived from the answer posted by PankajParkar below, here is the service that will return the three arrays that I require.
However, my issue here is that every call to a method within the service triggers another async call to $http.get my JSON data. This is exactly what I was trying to avoid by using a service.
My desired outcome is one JSON call per page load, with my 3 arrays being created from that JSON call and then accessible to my controllers as and when required. If a service is not the correct answer, I am certainly open to other suggestions.
app.service('$stationsList', ['$http', function($http){
var searchableStations = [],
locatableStations = [];
/**
* Grab all stations (for the master list)
*/
var getAllStations = function(){
return $http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
return res.data;
});
};
/**
* Grab only searchable stations (those with full links)
*/
var getSearchableStations = function(){
return $http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm){ // Map all stations...
if (elm.link.indexOf(".xml") > -1) // Check to see if the station is searchable
searchableStations.push(elm); // It is - add the station to 'searchableStations'
});
return searchableStations;
});
};
/**
* Grab only locatable stations (those with coordinates)
*/
var getLocatableStations = function(){
return $http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm){ // Map all stations...
if(
isFinite(parseFloat(elm.latitude)) &&
isFinite(parseFloat(elm.longitude))
) // Check to see if the station is locatable
locatableStations.push(elm); // It is - add the station to 'locatableStations'
});
return locatableStations;
});
};
return{
getAll: getAllStations,
getSearchable: getSearchableStations,
getLocatable: getLocatableStations
};
}]);
Your current code is failing because you made asynchronous ajax call & accepting value as soon as it made. That's why you are getting your values as undefined.
You need to wait till your ajax gets completed, that could be implemented using returning ajax promise to controller from service. So i'd suggest you to create a new method which will do $http ajax and will return promise from that function & that will execute .then function of controller that called the getSearchableStations. Below snippet will give you an Idea what I wanted to say.
Service
app.service('$stationsList', ['$http', function($http) {
var stationsList = [],
searchableStations = [],
locatableStations = [];
var getSearchableStations = function() {
return $http.get('stations.json').then(function(res) { // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm) { // Map all stations...
stationsList = res.data; // Set all stations to 'stationsList'
if (elm.link.indexOf(".xml") > -1) // Check to see if the station is searchable (has a full link)
searchableStations.push(elm); // It does - add the station to 'searchableStations'
if ( // Check to see if the station can be checked as the closest station (has coordinates)
isFinite(parseFloat(elm.latitude)) &&
isFinite(parseFloat(elm.longitude))
)
locatableStations.push(elm); // It does - add the station to 'locatableStations'
});
console.log(stationsList);
console.log(searchableStations);
console.log(locatableStations);
return locatableStations; //return data from here.
});
};
return {
getList: function() {
return stationsList;
},
setList: function(value) {
stationsList = value;
},
getSearchable: function() {
return searchableStations;
},
setSearchable: function(value) {
searchableStations = value;
},
getLocatable: function() {
return locatableStations;
},
setLocatable: function(value) {
locatableStations = value;
},
//added new function
getSearchableStations: getSearchableStations
};
}]);
Inside you controller you will call service getSearchableStations method that does return promise, You will use .then function that would get called when promise get resolved. Same has been shown below with code.
Controller
app.controller('searchCtrl', ['$scope', '$http', '$localStorage', '$stationsList',
function($scope, $http, $localStorage, $stationsList){
$stationsList.getSearchableStations().then(function(data){
$scope.stationsList = data;
$scope.selectStation = click_selectStation; // Handle clicks of a station within the 'searchCtrl' controller
$scope.localStorage = $localStorage.$default({ // Grab the local storage (so that it can be updated when the user selects a station)
recentStations: [] // Set a default value of '[]' for recentStations in case it doesn't exist
});
}); // Grab a list of all stations
}]);

angular firebase saving data as object

its my first time using angular with firebase.
I am having a hard time saving data as an object to firebase.
whenever i save a data, it doesn't provide index id or random generated id.
so first time name it saves the data and second time it overwrites the data because of not having any id.
here is my code
myApp.controller('MeetingsController', ['$scope','$firebaseObject', function ($scope, $firebaseObject) {
var ref = new Firebase('https://saddam.firebaseio.com/employees');
var obj = $firebaseObject(ref);
$scope.meetings = obj;
$scope.meetings.$loaded(function() {
console.log(obj);
});
$scope.addMeeting = function() {
obj.userinfo= {
meetingName : $scope.meetingname,
date : Firebase.ServerValue.TIMESTAMP
}
obj.$save();
}
}]);
Looking for some help

Resources