Angular Two way databinding and http.post issue - angularjs

Objective: Two Way Databinding between database and view via scope and controller
I’m trying to post to a restful database using angular
When I click on the thumbs up or thumbs down the scope changes o.k and is reflected in the view
However how can this placed in real time to a restful database using http post ?
Here’s the HTML
<div ng-controller="ordersCtrl">
<div class="span0 well votingWidget">
<div class="votingButton" ng-click="upVoteOrder(order)">
<i class="icon-thumbs-up "></i>
</div>
<div class="badge ">
<div>{{order.upVoteCount}}</div>
</div>
<div class="votingButton" ng-click="downVoteOrder(order)">
<i class="icon-thumbs-down"></i>
</div>
Heres the Controller: My issue lies here in the http.post command
.controller("ordersCtrl", function ($scope, $http, ordersUrl) {
$scope.downVoteOrder = function(order) {
$scope.selectedOrder = order;
order.upVoteCount--;
$http.post(orderUrl, order.upVoteCount)
.success(function (data) {
$scope.data.orderupVoteCount = data.id;
})
};
});
Note : I can post form data to the restful database successfully using the following code
$scope.sendOrder = function (shippingDetails) {
var order = angular.copy(shippingDetails);
order.products = cart.getProducts();
$http.post(orderUrl, order)
.success(function (data) {
$scope.data.orderId = data.id;
cart.getProducts().length = 0;
})
.error(function (error) {
$scope.data.orderError = error;
}).finally(function () {
$location.path("/uploaded");
});
}

you should use a separate service to handle the http post .
var app = angular.module("myApp", []);
app.factory("OrderService", ["$http", function ($http) {
this.PostDownVote = function(orderUrl, upVoteCount) {
return $http.post(orderUrl, upVoteCount);
}
this.PostOrder = function(orderUrl, order) {
// do something
}
return this;
}]);
Now inject this OrderService to you controller and use it.
app.controller("ordersCtrl", function ($scope, $http, ordersUrl, OrderService) {
$scope.downVoteOrder = function(order) {
$scope.selectedOrder = order;
order.upVoteCount--;
OrderService.PostDownVote(ordersUrl, order.upVoteCount)
.success(data) {// do something}
.error(data) {// do something}
}
});

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.

How to check image exist on server or not in angular js?

I have a recent article section where i need to validate whether image is exist or not on server.
I try some tutorial it validate properly but it does not return any value to my ng-if directive.
Here is my recent article section:-
<div ng-controller="RecentCtrl">
<div class="col-md-3" ng-repeat="items in data.data" data-ng-class="{'last': ($index+1)%4 == 0}" bh-bookmark="items" bh-redirect>
<div class="forHoverInner">
<span class="inner">
<span class="defaultThumbnail">
<span ng-if="test(app.getEncodedUrl(items.bookmark_preview_image))" style="background-image: url('{{app.getEncodedUrl(items.bookmark_preview_image)}}'); width: 272px; height: 272px; " class="thumb" variant="2"></span></span></span> </div>
</div></div>
Here is my recent article controller:-
app.controller('RecentCtrl', function($scope, $http, $rootScope, RecentArticleFactory,$q) {
$scope.test = function(url) {
RecentArticleFactory.isImage(url).then(function(result) {
return result;
});
};
})
Here is recent aricle factory code:-
app.factory("RecentArticleFactory", ["$http", "$q", function ($http, $q) {
return {
isImage: function(src) {
var deferred = $q.defer();
var image = new Image();
image.onerror = function() {
deferred.resolve(false);
};
image.onload = function() {
deferred.resolve(true);
};
image.src = src;
return deferred.promise;
},
}
})
But
ng-if="test(app.getEncodedUrl(items.bookmark_preview_image))" does not return any value
Any Idea?
Thats because it is async due to deferred. Try calling the test function and binding the result value to a field in scope.
First, trigger the test function via $watch:
$scope.$watch("data.data", function() {
for(var i = 0; i < $scope.data.data.length; i++) {
var items = $scope.data.data[i];
$scope.test(items);
}
})
Then change your test function as follows:
$scope.test = function(items) {
items.isImageAvailable= false;
RecentArticleFactory.isImage(items.bookmark_preview_image).then(function(result) {
items.isImageAvailable= result;
});
};
})
Finally, you can use this in your view as:
<span ng-if="items.isImageAvailable" ...></span>
Of course you also need to call app.getEncodedUrl in between. But as I could not see, where app is defined, I omitted this. But the conversion is nevertheless necessary.

$scope is not binding data in view

I've been developing an e-commerce website and I am stuck at a point. I am using Stripe payment and all is working fine except data biding after token creation. Here is my controller
app.controller('shoppingCartController', ['$scope', '$http', '$sce', 'stripe', '$window', function ($scope, $http, $sce, stripe, $window) {
$window.Stripe.setPublishableKey('pk_test_saiYYlyCNgO2yZq6Mu******');
$scope.createToken = function () {
var expire = $scope.master[0].expire.split('/');
if ($scope.userDetail.$valid === true) {
$window.Stripe.card.createToken({
number: $scope.master[0].card,
cvc: $scope.master[0].cvv,
exp_month: expire[0],
exp_year: expire[1],
}, $scope.makepayment);
}
}
$scope.makepayment = function (status, response) {
if (response.error) {
$scope.handleStripeCallback(response);
} else {
// response contains id and card, which contains additional card details
var data = {token: response.id, data: $scope.cartData};
$http.post('make_payment', data).success(function (data) {
if (data.status) {
$scope.stripePaymentMessage = data.message;
$scope.stripePaymentMessageClass = "success";
} else {
$scope.stripePaymentMessage = data.message;
$scope.stripePaymentMessageClass = "danger";
}
})
}
}
$scope.handleStripeCallback = function (response) {
//alert(response.error.message);
$scope.stripChargeRequest = true;
$scope.stripePaymentMessage = response.error.message;
$scope.stripePaymentMessageClass = "danger";
}
}]);
In my view I am trying to handle error or success message with this code
<div ng-show="stripChargeRequest ">
<div class="alert alert-{{stripePaymentMessageClass}}" role="alert" >
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
{{stripePaymentMessage}}
</div>
</div>
My question is: stripChargeRequest angular variable contain true / false with normal scope binding but when I am trying to create a token by calling $scope.createToken() it not works. I guess I am forgetting something in calling callback function $scope.makepayment(). Fortunately it is working in controller's scope. I can see error after stripe request in controller but it is not showing in view. Please suggest me the proper way of doing that. Thanks in advance.
The stripe callbacks are outside of angular so you need to use $apply to tell angular whenever you update the scope so it can run a digest to update the view
Example:
$scope.handleStripeCallback = function (response) {
//alert(response.error.message);
$scope.stripChargeRequest = true;
$scope.stripePaymentMessage = response.error.message;
$scope.stripePaymentMessageClass = "danger";
$scope.$apply(); // tell angular to update view
}

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>

Resources