Update $http return data to html view - angularjs

I am getting my data form angular service
.service('SelectedMemberDetail', function ($http) {
return {
get : function(id) {
return $http.get('/api/members/'+ id);
},
create : function(id) {
return $http.post('/api/members/'+ id);
},
delete : function(id) {
return $http.delete('/api/members/'+ id);
}
}
})
This is the controller function which calling that service.
$scope.show = function (user_id) {
$scope.selectedMember = SelectedMemberDetail.get(user_id);
}
And i am trying to get view in html like this
<h2>
<span class="glyphicon glyphicon-user mleft_10 icon_big"></span>
{{ selectedMember.firstName[0] }}
</h2>
<div>
<p class="clear_margin"><b>Address: </b>
{{ selectedMember.address[0] }}
</p>
<p><b>Contact: </b>{{ selectedMember.contact[0] }}</p>
</div>
I checked, the service function is returning json data, which is here,
_id: "552386cb880611101168ab4b"
address: ["pata nai", "text"]
contact: ["23456", "tel"]
email: ["anoop#email", "email"]
firstName: ["Anoop", "text"]
lastName: ["singh", "text"]
I am not able to see the updated data on browser. What's wrong with my code?

Use promise return by $http and then assign value.It is not showing anything because you are directly assigning promise to the assignment it will not show anything in the view.
SelectedMemberDetail.get(user_id).then(function(response){
$scope.selectedMember = response.data
});
SelectedMemberDetail.get(user_id).success(function(response){
$scope.selectedMember = response.data
});
There is two way to capture promise return from $http one is then and another is success.
Look at the Doc.

When you use $http.get it returns a promise not the data itself. You need to do this:
$scope.show = function (user_id) {
SelectedMemberDetail.get(user_id)
.success(function (result) {
$scope.selectedMember = result;
});
}
see more here:
https://docs.angularjs.org/api/ng/service/$http

I like this paradigm:
.service('SelectedMemberDetail', function ($http) {
return {
get : function(id) {
var member = {};
member.$promise = $http.get('/api/members/'+ id)
.success(function(data) {
angular.copy(data, member);
});
return member;
}
}
})
The get method returns a reference to the member right away. When the $http call completes successfully, it uses angular.copy to assign the member's properties, while preserving the reference.
That way you can still do this (main use case):
$scope.show = function (user_id) {
$scope.selectedMember = SelectedMemberDetail.get(user_id);
}
The member also has a $promise property, so if you need to handle success or error (edge use case):
$scope.selectedMember = SelectedMemberDetail.get(user_id);
$scope.selectedMember.$promise.success(function(data) {
// do something else with member
});

Related

Angular Components does not work with Promise and Service

I have a really strange problem with Angular Components calling a service.
For example, i have a simple service with some mockup data as an array inside. The i add two methods, one synchron and one asynchron which returns a promise (if i correct understood).
Now a have a angular component which is well loaded in a example application.
On the frontend i have two buttons, one for each method in the service.
If i press now the button "btn1" the list is well loaded, all works fine.
If i now press the button "btn2" i see in the console that the service returns all data correctly, but the list in the frontend will not be loaded.
Service
var myItems = [
{id: 1, name: "item1"},
{id: 2, name: "item2"}
];
function ItemsService($q) { // inject the $q service
this.$q = $q;
}
ItemsService.prototype = {
loadItems: function () {
return myItems;
},
loadItemsAsync: function () {
var $qme = this.$q; // if i do not this, "this.$q" is undefined
return this.$q.resolve(myItems);
}
};
module.exports = {
ItemsService: ItemsService
}
Controller
function Foo(ItemsService) {
this.itemsService = ItemsService;
}
Foo.prototype = {
loadItems: function () {
this.items = this.itemsService.loadItems();
},
loadItemsAsync: function () {
this.itemsService.loadItemsAsync().then(
function (response) {
this.items = response;
console.log('data->' + this.items + ' -> ' + this.items[0].name);
},
function (error) {
console.log('error->' + error); // ignore
}
);
}
};
Component HTML
<section>
<button id="btn1" ng-click="$ctrl.loadItems()">Load</button>
<button id="btn2" ng-click="$ctrl.loadItemsAsync()">Load Async</button>
<ul>
<li ng-repeat="item in $ctrl.items">{{item.id}} // {{item.name}}</li>
</ul>
</section>
In future i want to replace the code in the service method of "loadItemsAsync" with a service call, but actually nothing works.
Future planned service method code
loadTreasuriesAsync: function () {
var $qme = this.$q;
return this.$http.get(this.url).then(
function (response) {
return $qme.resolve(response.data);
},
function (error) {
throw error;
}
);
}
I also tried this service call, but it also returns a promise object.
loadItems: function () {
return this.$http.get(this.url).then(function (response) {
return response.data;
});
},
Can anyone help me finding a solution?
this.items = response;
this does not exist anymore in the context. Try to save the context previously either by an outside variable (i.e. _this) or use arrow functions if you have those available.

How to dynamical set de widgetDefinitions in malhar angular dashboard via rest client?

I have installed malhar-angular-dashboard module and I want to populate some widgetDefinitions with my rest data.
HTML
<div ng-controller="widgetCtrl">
<div dashboard-layouts="layoutOptions" class="dashboard-container"></div>
</div>
widgetRestService
.factory('widgetRestService',['$http','UrlService','$log','$q',
function($http,UrlService,$log,$q){
var serviceInstance = {};
serviceInstance.getInfo = function(){
var request = $http({method: 'GET', url: '/rest/widgets/getListInfoDashboards'})
.then(function(success){
serviceInstance.widgets = success.data;
$log.debug('serviceInstance.widgets SUCCESS',serviceInstance.widgets);
},function(error){
$log.debug('Error ', error);
$log.debug('serviceInstance.widgets ERROR',serviceInstance.widgets);
});
return request;
};
serviceInstance.getAllWidgets = function () {
if (serviceInstance.widgets) {
return serviceInstance.widgets;
} else {
return [];
}
};
return serviceInstance;
}])
My rest service returns me this array of 3 objects :[{"name":"widgetList","title":" "},{"name":"widgetPie","title":" "},{"name":"widgetTable","title":" "}]
OtherService
.factory("OtherService", ["widgetRestService", "$log", "$q",
function (widgetRestService, $log, $q) {
var deferred = $q.defer();
widgetRestService.getInfo().then(function () {
deferred.resolve(widgetRestService.getAllWidgets());
});
return deferred.promise;
}])
Controller
OtherService.then(function(response){
$scope.layoutOptions = { // layout with explicit save
storageId: 'demo-layouts-explicit-save',
storage: localStorage,
storageHash: 'fs4df4d51',
widgetDefinitions:response , //must be a list
defaultWidgets: [],
explicitSave: true,
defaultLayouts: [
{title: 'Layout 1', active: true, defaultWidgets: []}
]
};
$log.debug('layoutOptions =',$scope.layoutOptions);
});
Result
layoutOptions: Object{defaultLayouts:Array[1],
defaultWidgets:Array[0],
explicitSave:true,
storage:Storage,
storageHash:'fs4df4d51',
storageId: 'demo-layouts-explicit-save',
widgetDefinitions: Array[3]}
TypeError: Cannot read property '$$hashKey' of undefined
at Object.extend (http://localhost:9000/bower_components/angular/angular.js:406:14)
at Object.LayoutStorage (http://localhost:9000/bower_components/malhar-angular-dashboard/dist/malhar-angular-dashboard.js:1064:15)
I searched at line 2: Object.LayoutStorage and I found out this:
angular.extend(defaults, options); //options = undefined (should have some keys and my widgetDefinitions array)
angular.extend(options, defaults);
The options variable is undefined only when I want to setup the $scope.layoutOptions within the then callback function.
Any advice how to set / avoid this ?
The problem is that the dashboard-layouts directive will compile before the asynchronous call from OtherService has finished, which means $scope.layoutOptions will be undefined.
A simple solution is to prevent the dashboard-layouts directive from compiling before $scope.layoutOptions is available.
You can do this by using ng-if:
<div ng-if="layoutOptions" dashboard-layouts="layoutOptions" class="dashboard-container">
</div>

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.

Map AngularJS restAPI request via URL

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}]);

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>

Resources