Map AngularJS restAPI request via URL - angularjs

Being new to angular I'm stocked to figure out how to call a web service which should be parsed and maped via URL, like if the URL is getting called directly to get listed request with the given params
what I mean let say I have
/api/products -- calling all products(this is the access point)
/api/products/?page=2&orderby=asc -- calls products with pagination and orderby and here is what's bothering me because the api is getting called via ajax and there is no URL mapping of the target
My Codes
Html markup
<div ng-controller="MainCtrl">
<div class="row">
<div class="col-lg-7 col-md-7 col-sm-7">
<pagination total-items="totalItems" num-pages="totalPages" ng-model="currentPage" ng-change="selectPage(currentPage)" max-size="5" class="pagination-sm" boundary-links="true"></pagination>
</div>
<div ng-repeat="product in products"></div>
</div>
</div>
contoller
//called when navigate to another page in the pagination
$scope.selectPage = function(page) {
$scope.filterCriteria.pageNumber = page;
$scope.fetchResult();
};
//The function that is responsible of fetching the result from the server and setting the grid to the new result
$scope.fetchResult = function() {
return api.items.search($scope.filterCriteria).then(function(data) {
$scope.products = data;
$scope.totalPages = data.total;
$scope.productsCount = data.TotalItems;
}, function() {
$scope.products = [];
$scope.totalPages = 0;
$scope.productsCount = 0;
});
};
Service
.factory('api', function(Restangular) {
//api call to
return {
products: function() {
return Restangular.all('products').getList();
},
product: function(id) {
Restangular.one("products", id ).get().then(function(c) {
return c;
});
},
update: function(id) {
Restangular.one("products", id).put().then(function(c) {
return c;
});
},
items: {
search: function(query) {
return Restangular.all('products').getList(query);
}
},
};
});
How do I create params URL and function of this make restAPI calls or what are the workarounds in this case

You can get at the search parameters with the $location service. So if a user goes to somedomain.com/products/?page=2&orderby=asc then $location.search() will equal {page: 2, orderby: 'asc'}.
So when your controller loads you just need to set the filterCriteria and fetch the results.
controller
var myCtrl = function($location, $scope) {
$scope.selectPage = function(page) {
...
};
$scope.fetchResult = function() {
...
};
$scope.filterCriteria = $location.search();
$scope.fetchResults();
}

First you need to create a restangular object by mentioning the base url. In your case it will be
// It will creat a url /api
var base = Restangular.all('api');
Now you can create multiple scenarios like if you want to get all products then it will be:
// /api/products/
base.getList('products')
.then(function(products) {
$scope.products= products
})
Now if you want to apply pagination as well as include orderBy param
$scope.products = base.getList("products", [{page: 2},{orderby:asc}]);

Related

Initialise AngularJS service - factory on the document load

Sorry for a very stupid question but I just started working with AngularJS and OnsenUI.
I have got a service to get a data from SQLite:
module.factory('$update', function () {
var update = {};
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM event_updates', [], function (tx, results) {
var rows = results.rows;
update.items = [];
if (!rows.length) {} else {
for (var index = 0; index < rows.length; index++) {
update.items.push({
"title": rows.item(index).title,
"date": rows.item(index).date,
"desc": rows.item(index).desc
});
}
}
}, function (error) {
console.log(error);
});
});
return update;
});
And a controller which is using the data:
module.controller('UpdatesController', function ($scope, $update) {
$scope.items = $update.items;
});
As soon as my page is loaded the content is not displayed and I need to click twice to call a page with the code below to see the content:
<ons-list ng-controller="UpdatesController">
<ons-list-item modifier="chevron" class="list-item-container" ng-repeat="item in items" ng-click="showUpdate($index)">
<div class="list-item-left">
</div>
<div class="list-item-right">
<div class="list-item-content">
<div class="name">{{item.title}}</div> <span class="desc">{{item.desc}}</span>
</div>
</div>
</ons-list-item>
</ons-list>
Can anybody help how can I initialise the controller as soon as page is loaded with all content. Sorry if it is a stupid question but I am really struggling. Appreciate your help a lot.
You could store the result of the request in the factory and retrieve those instead.
module.factory('$update', function () {
var update = {};
var requestValues = function(){ // store the results of the request in 'update'
// Your db.transaction function here
}
var getUpdates = function(){ // retrieve the values from 'update'
return update;
}
return{
requestValues : requestValues,
getUpdates : getUpdates
}
});
And then in you controller:
module.controller('UpdatesController', function ($scope, $update) {
$update.requestValues();
$scope.items = $update.getUpdates();
});
You could then get the values from anywhere in you solution (by using $update.getUpdates) without having to make an extra http request.

Linking user's contacts in firebase with md-contacts-chips

I am having difficulty getting my head around on how I could link my users contacts in Firebase with md-contacts-chips from https://material.angularjs.org/0.11.2/#/demo/material.components.chips
Basically, each registered user can add people they know via email to their contacts list. The users firebase structure is as follows:
firebase
-$uid1
contacts
$uid2 - userObject
$uid3 - userObject
-$uid2
contacts
$uid1 - userObject
$uid3 - userObject
-$uid3
contacts
$uid1 - userObject
$uid2 - userObject
etc..
Is it possible to ng-repeat a users contacts as an array of objects?
How should I configure the md-contacts-chip?
The example has a function called loadContacts() which has the contacts set.
How would I be able to set my user objects as contacts? The return object is contact and I would like to find a way for it to return the queried object.
function loadContacts() {
var contacts = [
'Marina Augustine',
'Oddr Sarno',
'Nick Giannopoulos',
'Narayana Garner',
'Anita Gros',
'Megan Smith',
'Tsvetko Metzger',
'Hector Simek',
'Some-guy withalongalastaname'
];
return contacts.map(function (c, index) {
var cParts = c.split(' ');
var contact = {
name: c,
email: cParts[0][0].toLowerCase() + '.' + cParts[1].toLowerCase() + '#example.com',
image: 'http://lorempixel.com/50/50/people?' + index
};
contact._lowername = contact.name.toLowerCase();
return contact;
});
}
Thanks
I'm by no means an expert, just a trial and error fanatic. That being said I did get this to work. I the issues is that "md-contact-chip" uses "push and splice" to adjust the array, and as firebase states that's a bad idea. If we had access to replace push with $add() or splice with $remove() this should work properly.
I was looking at the custom chips setup and it seems possible because you can call a function during the chip's add and remove, then with a custom chip template could maybe get the same look as the contact-chips.
Anyway here is what I did to get it working with md-contact-chips. Also I've adjusted this one to work with a list of items, not contacts, cause I wanted the picture for the items.
The key to it should be get your whole person obj, then set the ng-model="ctrl.person.contacts" inside the controller make sure to have an array created if person.contacts does not exist. "ctrl.person.contacts = ctrl.person.contacts || [];
Yes your are not properly updating the firebase object but you when you run
ctrl.person.$save() you are just completely updating the db.
Html
<div layout="column" ng-cloak>
<div>
<p>Items selected</p>
<pre>{{ctrl.item.installedItems}}</pre>
</div>
<input type="button" ng-click="ctrl.updateInstalledItems()" value='update'>
<md-content class="md-padding autocomplete" layout="column">
<md-contact-chips
ng-model="ctrl.item.installedItems"
md-contacts="ctrl.querySearch($query)"
md-contact-name="alseSn"
md-contact-image="image"
md-require-match="true"
md-highlight-flags="i"
filter-selected="ctrl.filterSelected"
placeholder="Select installed items">
</md-contact-chips>
</md-content>
</div>
Controller
app.controller('ItemChipCtrl', ['items', 'item', '$q', '$log',
function (items, item, $q, $log) {
var ctrl = this;
ctrl.items = items;
ctrl.item = item;
ctrl.item.installedItems = ctrl.item.installedItems || [];
ctrl.querySearch = querySearch;
ctrl.allItems = loadItems(ctrl.items);
ctrl.filterSelected = true;
ctrl.updateInstalledItems = function() {
$log.info('Update....')
$log.log(ctrl.installedItems);
ctrl.item.$save();
}
/**
* Search for contacts.
*/
function querySearch (query) {
var results = query ?
ctrl.allItems.filter(createFilterFor(query)) : [];
return results;
}
/**
* Create filter function for a query string
*/
function createFilterFor(query) {
var lowercaseQuery = angular.lowercase(query);
return function filterFn(item) {
return (item.alseSn.indexOf(lowercaseQuery) != -1);
};
}
function loadItems(items) {
/*var items = $scope.items */
return items.map(function (c, index) {
var item = {
alseSn: c.alseSn || c,
alseCard: c.alseCard,
installedOn: c.installedOn || null,
image: 'img/items/47/'+c.alseCard+'.jpg' || null
};
return item;
});
}
}
]);
route injections
.when('/settings/:alseSn', {
templateUrl: 'settings.html',
controller: 'ItemChipCtrl as ctrl',
resolve: {
auth: function($location, Auth){
return Auth.$requireAuth().then(function(auth) {
return auth;
},function(error){
$location.path('/login');
});
},
item: function($route, Items, Auth){
return Auth.$requireAuth().then(function(){
return Items.getItem($route.current.params.alseSn).$loaded();
});
},
items: function(Items, Auth){
return Auth.$requireAuth().then(function(){
return Items.all.$loaded();
});
}
}
})

AngularJS - RestAngular - after post add new category, update category list in other controller

what is the best way to update a list of categories (in a nav for example) after adding a category with a different controller?
Here is my code
// add new category
app.controller('AddCategoryController', ['$scope', 'CategoryService', function($scope, CategoryService) {
$scope.category = {};
$scope.added = false;
$scope.addCategory = function() {
CategoryService.addCategory($scope.category).then(function(response) {
if(response == 'ok') {
$scope.added = true;
}
});
};
}]);
and here is the controller for showing the categories
app.controller('CategoriesController', ['$scope', 'CategoryService', function($scope, CategoryService) {
CategoryService.getCategories().then(function(categories) {
$scope.categories = categories;
});
}]);
Categories are shown in a nav
<nav>
<div class="list-group" ng-controller="CategoriesController">
<a ng-href="#category/{{category.id}}" class="list-group-item" ng-repeat="category in categories" ng-bind="category.name"></a>
</div>
<div class="list-group">
Add category
</div>
</nav>
EDIT This is the service
services.factory('CategoryService', ['$route', 'Restangular', function($route, Restangular) {
var Category = Restangular.all('categories');
return {
getCategories: function() {
return Category.getList();
},
getCategory: function(id) {
id = id ? id : $route.current.params.categoryId;
return Category.get(id);
},
addCategory: function(category) {
return Category.post(category);
},
editCategory: function(category) {
return category.put()
},
removeCategory: function(id) {
id = id ? id : $route.current.params.categoryId;
return Category.remove(id);
}
};
}]);
Services are singleton in AngularJS. Therefore, after you called CategoryService.addCategory you can update the category list in your service and it will be available for other controllers.
You can also enrich your service to cache the categories. This will help you to avoid unnecessary requests to your backend.
Either you build your own caching logic or use:
RestangularProvider.setDefaultHttpFields({cache: true});
In addition you can use $rootScope.$on and $rootScope.$emit to receive and send events. This helps you to communicate between components in real-time fashion.
// send event
$rootScope.$emit(nameOfEvent, args...);
In some other controller/ service
// subscription
var unbind = $rootScope.$on(nameOfEvent, function(event, args...) { /* do stuff */ });
// don't forget to unbind
$scope.$on('$destroy', function() {
unbind();
});

Angular call service on asynchronous data

I have a service that make some calls to retrieve data to use in my app. After I've loaded data, I need to call another service to make some operations on my data. The problem is that second service will not have access to the data of the first service.
I've made a plunker: plunkr
First service
app.factory('Report', ['$http', function($http,$q){
var Authors = {
reports : [],
requests :[{'url':'data.json','response':'first'},
{'url':'data2.json','response':'second'},
{'url':'data3.json','response':'third'}]
};
Authors.getReport = function(target, source, response, callback) {
return $http({ url:source,
method:"GET",
//params:{url : target}
}).success(function(result) {
angular.extend(Authors.reports, result)
callback(result)
}
).error(function(error){
})
}
Authors.startQueue = function (target,callback) {
var promises = [];
this.requests.forEach(function (obj, i) {
console.log(obj.url)
promises.push(Authors.getReport(target, obj.url, obj.response, function(response,reports){
callback(obj.response,Authors.reports)
}));
});
}
return Authors;
}])
Second service
app.service('keyService', function(){
this.analyze = function(value) {
console.log(value)
return value.length
}
});
Conroller
In the controller I try something like:
$scope.result = Report.startQueue('http://www.prestitiinpdap.it', function (response,reports,keyService) {
$scope.progressBar +=33;
$scope.progress = response;
$scope.report = reports;
});
$scope.test = function(value){
keyService.analyze($scope.report.about);
}
I think this is what you are going for? Essentially, you want to call the second service after the first succeeds. There are other ways of doing this, but based on your example this is the simplest.
http://plnkr.co/edit/J2fGXR?p=preview
$scope.result = Report.startQueue('http://www.prestitiinpdap.it', function (response,reports) {
$scope.progressBar +=33;
$scope.progress = response;
$scope.report = reports;
$scope.test($scope.report.about); //added this line
});
$scope.test = function(value){
$scope.example = keyService.analyze(value); //changed this line to assign property "example"
}
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<p>Progress notification : {{progress}}!</p>
<div ng-show="show">
<progress percent="progressBar" class="progress-striped active"></progress>
</div>
<pre>{{report}}</pre>
<pre>{{report.about}}</pre>
{{example}} <!-- changed this binding -->
</body>

How treat data with Firebase and AngularJS

I'm trying building an App with AngularJS and Firebase - any one have tried?
I'm following this and using the fist method (implicit sync.) to synchronise my models with Firebase.
In my app I want to have two db/json files (Firebase Url) (kind of stuff) one for users and one for votes.
So I did :
var url = 'mypath.firebaseio.com/votes';
var promise = angularFire(url, $scope, 'votes', []);
promise.then(function() {
$scope.removeVotes = function() {
$scope.votes.splice($scope.toRemove, 1);
$scope.toRemove = null;
};
});
//then I push my votes with a function
$scope.addVote = function() {
$scope.votes.push({
from:user.username,
to:$scope.voteTo,
motivation:$scope.voteMotivation, date:today
});
};
and this works fine I can see my votes in the html rendered with my
<li ng-repeat="vote in votes">
ok
so I did same thing for users:
var url1 = 'mypath.firebaseio.com/users';
var promise1 = angularFire(url1, $scope, 'users', []);
promise1.then(function() {
$scope.users.push({
name: user.username,
pic: user.profile_image_url
});
$scope.removeUser = function() {
$scope.users.splice($scope.toRemove, 1);
$scope.toRemove = null;
};
});
Now I can see my users rendered in my html markup with
<li ng-repeat="user in users">
but that s no trace of my data at https://alex-jpcreative.firebaseio.com/users
Any ideas why?

Resources