I am trying to create an app that counts likes for beer! This would updates the API the beers are stored on and in turn update the number of likes on the API and angularJS view using the PUT method. I am able to get the view to work correctly increasing every time the like is clicked. I am unsure why my PUT method continues to return a 404 and will not update the API. please see code below for my put method. I have also included my JS and HTML for this. I feel like I am close but cannot figure out how to get the "likes" to update on the API. Thank you in advance!! I think i am passing incorrect data to the PUT method.
HTML:
<div ng-app="beerApp" ng-controller="BeerController" class="jumbotron">
<div class="all-beer">
<div class="single-beer" ng-repeat="beer in allBeer">
<div>{{beer.name}}</div>
<div>{{beer.likes}}</div>
<button ng-click="decrease(beer)">X</button>
<button ng-click="increase(beer)">\3</button>
</div>
</div>
</div>
JS:
angular.module('beerApp', []).controller('BeerController', function($scope, $http) {
$scope.allBeer = [];
$scope.beerSum = function() {
$http({
method: 'GET',
url: /api/beers
}).
then( function(response) {
if(typeof response === 'object') {
var dataArr = response.data;
for (var i = 0; i < dataArr.length; i++) {
var beer = dataArr[i];
$scope.allBeer.push(beer);
}
} else {
return;
}
}, function(error) {
console.log('i am an error', error);
})
};
$scope.beerSum();
$scope.increase = function(beer){
var newLikes = beer.likes++;
$http({
method: 'PUT',
url: '/api/beer/',
data: JSON.stringify($scope.allBeer.likes),
}).then(function successCallback(response) {
console.log("Updated!");
}, function errorCallback(response) {
console.log("not updated")
});
};
First things first you are missing some syntax for the http api's. Secondly you are calling a property on an array that doesn't exist. Thirdly your api won't work because of the logic that you have. You have an array of beers and you want to increase the likes on a single beer. Create a method on the server that accepts a beer, the server will take that beer and increase it's likes by 1, then save to the database or whatever.
Depending on the server you are using you have two options.
You can define a command simply at /api/beers and configure the server to accept an object and use that objects id for the server update. If this is the case I recommend creating this endpoint, /api/beers/update and make it a POST, and pass it the object, then within this command do all your update logic.
Or for example the Microsoft Web Api the default put (update) endpoint looks like so, public void Update(int id, object data){} with a url of /api/beers/{id}. To use this method you need to change the code for the updateLikes method I wrote.
See Below:
$scope.updateLikes = function(beer, likeCount){
beer.likes+= likeCount;
$http({
method: 'PUT',
url: '/api/beer/' + beer.id,
data: JSON.stringify(beer),
}).then(function successCallback(response) {
console.log("Updated!");
//Trigger reload of data
$scope.beerSum();
}, function errorCallback(response) {
console.log("not updated")
});
};
Extra Help
If you are still having trouble and are working in a GitHub environment I would gladly help you with your code more directly. Other than that the answer I have posted answer's your question, and does so in what I believe to be good coding practices for AngularJS. With one minor exception there code be a changes to the line that reads, beer.likes += likeCount because this also updates the original beer object. I suppose that is preference, but please contact me if you need more help.
JS:
angular.module('beerApp', []).controller('BeerController', function($scope, $http) {
$scope.allBeer = [];
$scope.beerSum = function() {
$http({
method: 'GET',
url: '/api/beers' //<-- Added string opening and closing tags
}).
then( function(response) {
if(typeof response === 'object') {
var dataArr = response.data;
for (var i = 0; i < dataArr.length; i++) {
var beer = dataArr[i];
$scope.allBeer.push(beer);
}
} else {
return;
}
}, function(error) {
console.log('i am an error', error);
})
};
$scope.beerSum();
$scope.increase = function(beer){
var newLikes = beer.likes++;
//Your code
$http({
method: 'PUT',
url: '/api/beer/', //<-- closing
data: JSON.stringify($scope.allBeer.likes), //<-- Where does likes come from? $scope.allBeer is an array of beer but the array itself doesn't have a property called likes.
}).then(function successCallback(response) {
console.log("Updated!");
}, function errorCallback(response) {
console.log("not updated")
});
//End your code
//My Code
beer.likes+=1; //<-- My bad I fixed this.
$http({
method: 'PUT',
url: '/api/beer/', //<-- closing
data: JSON.stringify(beer), //<-- The object you passed into the function
}).then(function successCallback(response) {
console.log("Updated!");
}, function errorCallback(response) {
console.log("not updated")
});
//End my code
};
Possible problems
Your api doesn't work with put, in which case this question isn't the correct one.
Something else is internally wrong with your program, but from this point on I think you're looking at something wrong with your api, whatever that may be.
angular.module('beerApp', []).controller('BeerController', function($scope, $http) {
$scope.allBeer = [];
$scope.beerSum = function() {
$scope.allBeer.push({
"name": "Miller Lite",
"likes": 0
});
$http({
method: 'GET',
url: '/api/beers' //<-- Added string opening and closing tags
}).
then( function(response) {
if(typeof response === 'object') {
var dataArr = response.data;
for (var i = 0; i < dataArr.length; i++) {
var beer = dataArr[i];
$scope.allBeer.push(beer);
}
}
}, function(error) {
console.log('i am an error', error);
})
};
$scope.beerSum();
$scope.updateLikes = function(beer, likeCount){
beer.likes+= likeCount;
$http({
method: 'PUT',
url: '/api/beer/',
data: JSON.stringify(beer),
}).then(function successCallback(response) {
console.log("Updated!");
//Trigger reload of data
$scope.beerSum();
}, function errorCallback(response) {
console.log("not updated")
});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.6.2" data-semver="1.6.2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-app="beerApp" ng-controller="BeerController" class="jumbotron">
<h1>Beers on Tap</h1>
<div class="all-beer">
<div class="single-beer" ng-repeat="beer in allBeer">
<div>{{beer.name}}</div>
<div>{{beer.likes}}</div>
<button ng-click="updateLikes(beer, -1)">Down Vote</button>
<button ng-click="updateLikes(beer, 1)">Up Vote</button>
</div>
</div>
</div>
</body>
</html>
Related
app.controller('contentixaeng', function ($scope, $http) {
$scope.subject = function(){
$scope.code=101;
};
$http({
method: "POST",
data:{
'subj_code':$scope.code, 'action':'singledata'
},
url: "pages/Entries/connectixa.php"
}).then(function mySuccess(response) {
$scope.users = response.data;
}, function myError(response) {
$scope.error = response.data;
});
});
I am trying to pass the value of $scope.code to data in HTTP service. It's not working properly and no data value is shown as output. Instead, I get the error "ng-repeat dupes".
The function subject get called through this line
<li class="nav-item" ng-contoller="contentixaeng"><a class="nav-link" href="#" ui-sref="ixaeng" ng-click="subject()" >English</a></li>
If I change the code like shown below then it works
app.controller('contentixaeng', function ($scope, $http) {
$scope.subject = function(){
$scope.code=101;
};
$http({
method: "POST",
data:{
'subj_code':101, 'action':'singledata'
},
url: "pages/Entries/connectixa.php"
}).then(function mySuccess(response) {
$scope.users = response.data;
}, function myError(response) {
$scope.error = response.data;
});
});
I want different data to be passed to the database search based on the on-click event.
The http request is sent immediatly when the controller is created. At this point $scope.code is not yet set.
Try something like this:
app.controller('contentixaeng', function ($scope, $http) {
$scope.subject = function(){
$scope.code=101;
callBackend();
};
function callBackend() {
$http({
method: "POST",
data:{
'subj_code':$scope.code, 'action':'singledata'
},
url: "pages/Entries/connectixa.php"
}).then(function mySuccess(response) {
$scope.users = response.data;
}, function myError(response) {
$scope.error = response.data;
});
});
}
Like this the http request is sent only when the callBackend method is explicitly called.
If you're receiving ng-repeat dupes error that means that you've got duplicated entries in $scope.users- try debugging that and see what's going on there. Also, you can use track by option like below:
ng-repeat="user in users track by $index"
It will assure that each user will be treated as unique entity, even if you have duplicated entries in $users variable.
Another thing is, where this piece of code is run? I do not see it anywhere in the code you provided
$scope.subject = function(){
$scope.code=101;
};
In the following code I want to execute a series of $http requests that modify a list. When all the responses are received, I want to process the list and remove part of the content.
The problem is that when I print the list after $q.all, the Chrome console shows a length of 3, but when I expand it to read the content only 2 elements are shown. On JSFiddle I have no issues, though.
var app = angular.module('MyApp',[]);
app.controller('MyController',['$scope','$q',"$http", function($scope,$q,$http){
var loopPromises = [];
var workorders = null;
$scope.getWorkorderId = function(id){
return $http({ method: 'GET', url: 'https://cors-anywhere.herokuapp.com/https://blk.clojure.xyz/interdiv/api/v1/service/' + id })
.then(function success(response) {
return response.data;
}, function error(response) {
console.log(response);
});
}
$http({ method: 'GET', url: 'https://cors-anywhere.herokuapp.com/https://blk.clojure.xyz/interdiv/api/v1/workorder' })
.then(function success(response) {
workorders = response.data;
}, function error(response) {
console.log(response);
})
.then(function() {
if (workorders == null) {
return;
}
angular.forEach(workorders, function(value, index, obj) {
var deferred = $q.defer();
loopPromises.push(deferred.promise);
var waitResponse = $scope.getWorkorderId(value.id);
waitResponse
.then(function(res) {
obj[index].services = res;
deferred.resolve();
})
});
$q.all(loopPromises)
.then(function() {
// Should contain 3 elements, only 2 are shown
console.log(workorders);
});
});
}]);
see better in the screenshots. Console Requests
The problem was in the second part of the code not copied in the question: I was using .splice() inside angular.forEach() which changes the indices of the elements within the array.
i want to use my controller for getting images link of dog with an api but I am not able to use the result.
var images = function(breed) {
var promise = $http({
method: 'GET',
url: 'https://dog.ceo/api/breed/' + breed + '/images/random'
})
.then(function successCallback(response) {
return response.data.message;
},
function errorCallback(response) {
});
return promise;
}
console.log(images("kelpie"));
the problem is, i can't get the link in the object.
if I change response.data.message by only response.data, this is why i get
when I add console.log(response.data) before the return, this is what I get:
If I try JSON.parse(response.data), I got this:
Do you know how to do ?
Thank you for your help
What you are seeing in the console is the promise itself.
if you want to view the value (which in this case will be the url) then do it like this
console.log(images("kelpie").value);
If you want to see the response data then you need to add the console.log() in the then() callback.
Do it like this:
.then(function successCallback(response) {
console.log(response.data.message);
return response.data.message;
}
can you try one with JSON.parse(response.data) and then fetch message property from it.
You need to utilize promise here.
One way to do this is -
angular.module('demo', [])
.controller('myController', ['$scope', 'demoService', function($scope, demoService){
demoService.test().then(function(response) {
$scope.url = response;
})
}])
.factory('demoService', ['$http', '$q',
function($http, $q) {
var demoService = {};
demoService.test = function() {
var deferred = $q.defer();
$http.get('https://jsonplaceholder.typicode.com/posts/1').then(
function(response) {
response = "https://www.w3schools.com/bootstrap/paris.jpg";
deferred.resolve(response);
}, function(error) {
console.log("some error occur");
console.log(error);
deferred.reject(error);
}
)
return deferred.promise;
}
return demoService;
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo" ng-controller="myController">
<img ng-src="{{url}}" />
</div>
Use promise deffer object
Refference - https://docs.angularjs.org/api/ng/service/$q
JS fiddle working code - https://jsfiddle.net/Shubhamtri/9y9ezkdt/1/
$http({
method: 'POST',
url: '',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: {
}
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
if(response.data == 'true'){
swal("Good job!", "New case has been created", "success");
}
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
I want to show a progress bar or spin on bootstrap while http request on angularjs
Sugessting you to use this angular-loading-bar
Steps
Include the script references and css as mentioned in the above
github, you can use cdn as well as mentioned.
Add these two functions in your controller
$scope.start = function() {
cfpLoadingBar.start();
};
$scope.complete = function () {
cfpLoadingBar.complete();
}
Include the 'angular-loading-bar', 'ngAnimate' as dependencies.
Add the below code for the app configurations
If you are looking for the progress bar
app.config(['cfpLoadingBarProvider', function(cfpLoadingBarProvider) {
cfpLoadingBarProvider.includeSpinner = false;
}])
If you are looking for a spinner
app.config(['cfpLoadingBarProvider', function(cfpLoadingBarProvider) {
cfpLoadingBarProvider.includeSpinner = true;
}])
Finally, In your $http request call the $scope.start() function and in your success method call the $scope.complete()
LIVE DEMO
A simple way:
html:
<div class="spinner" ng-show="loading"></div>
js :
$scope.loading = true
$http.post(...).then(function(response){
$scope.data = response.data // or whatever you needs...
$scope.loading = false
},function(){
$scope.loading = false
console.log("error")
})
If you want to generalize, you can also have a look to http interceptor : https://docs.angularjs.org/api/ng/service/$http#interceptors
I am calling a json in controller using service but I am receiving an error saying "TypeError: Cannot read property 'then' of undefined". I tried existing answers but couldn't get it to work.
Controller:
app.controller("myController",["$scope","MyService","$http", function($scope,MyService,$http){
$scope.hi = "hello";
MyService.getMyData().then(function(response){
console.log(response);
});
}]);
Service:
app.service("MyService", ["$http", function($http) {
this.getMyData = function() {
return
$http({
method: 'GET',
url: 'myList.json',
headers: {
'Content-Type': 'application/json'
}
}).then(function successCallback(response) {
console.log(response);
return response;
}, function errorCallback(response) {
console.log(error);
return response;
});
};
}]);
Thank you.
Currently you had just return(on first line) thereafter on next line you returned $http promise. Basically you have return alone it returns nothing/undefined (this is how javascript works) & next statements are getting ignored from this.getMyData function.
You have to have return & $http({ promise to be together in one line, otherwise return will return empty statement.
this.getMyData = function() {
//`return` & `$http` promise should be on same line, otherwise undefined would get return
return $http({
method: 'GET',
url: 'myList.json',
headers: {
'Content-Type': 'application/json'
}
}).then(function successCallback(response) {
console.log(response);
return response;
}, function errorCallback(response) {
console.log(error);
return response;
});
};
#pankajparker is absolutely correct.
Implemented a codepen for kicks and adjusted to use Angular 1.5's components. Here's the link:
http://codepen.io/Lethargicgeek/pen/YWryoE
(function() {
angular.module("myApp", []);
angular.module("myApp").component('myCmp', {
controller: ctrlFn,
templateUrl: "myCmp.tpl.html"
});
ctrlFn.$inject = ["myService"];
function ctrlFn(myService) {
var $ctrl = this;
// BINDINGS
$ctrl.hi = "hello";
$ctrl.getData = getData;
$ctrl.data = null;
$ctrl.myService = myService; // Binding so that we can easily see results
// END BINDINGS
// FUNCTION
function getData() {
var returnedPrms = myService.getMyData();
returnedPrms.then(function(response) {
$ctrl.data = response;
});
}
// END FUNCTIONS
}
angular.module("myApp").service("myService", svcFn);
svcFn.$inject = ["$http"];
function svcFn($http) {
var svc = this;
//BINDINGS
svc.getMyData = getMyData;
//END BINDINGS
function getMyData() {
var firstPrms = $http.get("http://codepen.io/anon/pen/LVEwdw.js"); // Random bit of json pulled from internets
var secondPrms = firstPrms.then(function success(response) {
svc.successResp = response;
return response;
}, function error(response) {
svc.errorResp = response;
return response;
});
return secondPrms;
}
}
})(); // end iife
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.min.js"></script>
<div ng-app="myApp">
<script type="text/ng-template" id="myCmp.tpl.html">
<div>
<h1>{{$ctrl.hi}}</h1>
<a class="btn btn-primary" ng-click="$ctrl.getData()">
Trigger $Http Call
</a>
<dl class="dl-horizontal">
<dt>$ctrl.data:</dt>
<dd>{{$ctrl.data}}</dd>
<dt>$ctrl.myService.successResp:</dt>
<dd>{{$ctrl.myService.successResp}}</dd>
<dt>ctrl.myService.errorResp:</dt>
<dd>{{ctrl.myService.errorResp}}</dd>
</dl>
</div>
</script>
<my-cmp></my-cmp>
</div>