Call Angularjs HTTP request service from jquery call or Select open - javascript

I'm new in angular and I need help to call an http request.
I had this controller
var app = angular.module('myApp',[]);
app.controller('freeUserController', function($scope, $http) {
$http({
method: 'GET',
url: 'users'
}).then(function successCallback(response) {
$scope.users = response.data.result;
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
});
It allows to fill Select in a modal form
This Select change every time user click on confirm button(select shows free users) so I though to create a service with the above http call and use this or on confirm button ( or on inside javascript of confirm button) or when user clicks on select tho show user.
So I change angular code like this:
var app = angular.module('"modalUploadLicense"',[]);
app.controller('freeUserController', function() {
freeUserService();
});
app.service("freeUserService",function($scope, $http){
$http({
method: 'GET',
url: 'users'
}).then(function successCallback(response) {
$scope.users = response.data.result;
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
});
But it give me an error and moreover I don't know the best way to call the service when the user list change.
This is my confirm button javascript:
$("#createLicenseButton").click(
function() {
var form = $("#addLicenseForm");
$.ajax({
type : "POST",
url : form.attr("action"),
data : form.serialize(),
// all right with rest call
success : function(data) {
//No exception occurred
if (data.status==true){
//Also the field are right(for e.g. form value)
if(data.success==true){
//il risultato sta in data.result
//window.location.reload(true);
$('#licensesTable').load(document.URL + ' #licensesTable');
angular.element(document.getElementById('freeUserController')).scope().get();
//reload only the tag with id carsTable, so only the table
//$('#carsTable').load(document.URL + ' #carsTable');
$('#addLicenseModal').modal("hide");
notifyMessage("Your license has been created!", 'success');
}
else{
//code if there are some error into form for example
}
} else {
//code exception
$('#addLicenseModal').modal("hide");
notifyMessage("Error! Your license hasn't been created!", 'error');
}
},
//error during rest call
error : function(data) {
window.location.href = "/ATS/500";
}
});
});
Whereas html Select is:
<label>Username</label> <select class="form-control select2"
style="width: 100%;" name="user" ng-model="selectedItem" ng-options="user.username as user.username for user in users track by user.username">
</select>
How can I update my Select value?thanks

First, change your service so it has a function to call:
app.service("freeUserService",['$http', function($http){
var service = this;
service.getusers = getusers;
function getusers() {
var url = "your url gets here";
return $http.get(url);
}
}]);
Then like Arnab says, you need to change your controller:
app.controller('freeUserController', ['freeUserService', '$scope', function(freeUserService, '$scope') {
$scope.fetchusers = function() {
freeUserService.getusers()
.then(handleGetUsers)
.catch(handleErrors);
}
function handleGetUsers(result){
//This is a promise, because $http only does asynchronous calls. No
//need to wrap this in a jquery thingy.
//As soon as the async function is resolved, the result data is put
// on your scope. I used $scope.users on purpose, because of your
//html
$scope.users = result.data;
}
function handleErrors(error){
console.log(error);
}
}]);
As you can see, I have put the "variable" users on the scope. I did this on purpose because of your html
<label>Username</label> <select class="form-control select2"
style="width: 100%;" name="user" ng-model="selectedItem" ng-options="user.username as user.username for user in users track by user.username">
</select>
The select looks into the scope for a variable called users. Because the variable users is on your html, angular automatically watches the variable for changes.
What I understand from your question is that every time the http call is done, you get another result, right? So Angular will automatically watch for a change, and reflect the result on your select element. if interested in more information, you should read this. I also suggest following a 'start with Angular tutorial', because going from your question, I think you are missing the basics of Angular.
The last step you need to do (I think, if i understand your question), is bind the $http function to your HTML. There is a "ng-click" directive you can use. In your case, the button then could look like this:
<button ng-click="fetchusers()" type="submit">Get me new users</button>
As you can see, I use the $scope.fetchusers() function in the ng-click directive, wich will make a new http call, getting new uses (ofcourse, if the http call gets new users every time you call it).
Plunker with modified code here.
You can use the ng-init directive to initialize the value. I ll update my plunker so that you can see how the ng-init works. You should set it right next to your ng-controller. ng-init will make the first call and give you data from the start. Then every time you press the button, new data will come, and your select will be updated. I have updated the plunk. I have added one of my own webservices. Do mind, my webservices are on a free heroku account. If you wait too long, the heroku application will go to sleep mode and the first call for data will timeout.
About multiple asynchronous calls:
Angular promises can be chained! So you can do one asynchronous call (for example doing a post to a database), wait for it to finish, then get the updated data. In your service, you could do this:
function getUsers(parameters) {
var posturl = "url to post to";
return $http.post(url, data) //the update, it returns a promise
.then(handlePost)
.catch(handleError);
}
function handlePost(result){
//the $http.get will only be executed after the previous promise has been
//resolved!
var geturl = "url to get data from";
return $http.get(url); // this is the second asynchronous call
}
It is good practice to chain promises. It would be bad practice to use a jQuery ajax call for this.

Inject freeUserService to your controller freeUserController to atleast call the service from your controller, like:
app.controller('freeUserController', ['freeUserService', function(freeUserService) {
freeUserService();
}]);
Otherwise you write like this:
var app = angular.module('myApp',[]);
app.controller('freeUserController', ['freeUserService', function($scope, freeUserService) {
var promise = freeUserService();
promise.then(function successCallback(response) {
$scope.users = response.data.result;
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
// And bind the users variable in your template
}]);
app.service("freeUserService", ['$http', function($http){
return $http({
method: 'GET',
url: 'users' // Proper url to your api
});
}]);

Related

AngularJS, how do I use a service to capture HTTP data and bind it to my controller?

I have an API call that's working great, but I'd like to use it on several controllers so I moved it to it's own service. I'm running into what looks like a classic Scope issue or a misunderstanding of Angular's digest cycle.
'use strict';
myApp.factory('Stuff',['$http', function ($http) {
var Stuff = {};
Stuff.data = {};
Stuff.api = 'http://localhost:8080/api/';
Stuff.getStuff = function() {
var http_stuff_config = {
method: 'GET',
url: Stuff.api + 'stuff/'
};
$http(http_stuff_config).then(function successCallback(response) {
Stuff.data = (response.data);
console.log(Stuff.data); // Returns populated object.
},function errorCallback(response) {
console.log(response.statusText);
});
};
Stuff.getStuff();
console.log(Stuff.data); // Returns empty object.
return Stuff;
}]);
myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
$scope.stuff = Stuff;
console.log($scope.stuff.data); // Returns empty object.
$scope.stuff.getJobs();
console.log($scope.stuff.data); // Returns empty object.
}]);
Here's the big clue. The essential output of above, in order is...
empty object (in service after calling method)
empty object (in controller before calling method)
empty object (in controller after calling method)
populated object (in method execution from service)
populated object (in method execution from controller)
So somewhere between the scope of the getStuff() method and Angular's order of operations, I'm doing something remarkably foolish. Thank you in advance.
You need to add returns on your service, or else the promise will not be returned to the controller. It is not good practice to just store the returns in your services AND NOT return the result to the controller.
This is considered bad practice because, any time you update the data on the service everyone will need to apply $scope.$watch to the service to look for updates. This can be very expensive in large scale apps.
The best Idea is to return the data to the calling controller (if you do not need to cache it, this we can talk about later) and let the controller access it via the promise service.getthing().then(function(result){});
myApp.factory('Stuff',['$http', function ($http) {
var Stuff = {};
Stuff.data = {};
Stuff.api = 'http://localhost:8080/api/';
Stuff.getStuff = function() {
var http_stuff_config = {
method: 'GET',
url: Stuff.api + 'stuff/'
};
return $http(http_stuff_config).then(function successCallback(response) {
return response.data;
console.log(Stuff.data); // Returns populated object.
},function errorCallback(response) {
console.log(response.statusText);
});
};
Stuff.getStuff();
console.log(Stuff.data); // Returns empty object.
return Stuff;
}]);
myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
$scope.stuff = Stuff;
console.log($scope.stuff.data); // Returns empty object.
$scope.stuff.getJobs().then(function(result) {$scope.stuff = result; console.log(result);});
console.log($scope.stuff.data); // Returns empty object.
}]);
I recommend you not to store the result inside the service itself (Stuff.data). Just return your data in the getStuff function and let the appController's scope store the data instead.
remember that $scope.stuff.getJobs() is async
(meaning you can't actually call console.log($scope.stuff.data) on the next line and get the data)
Now if you had a view, with something like <span ng-bind="stuff.data.property"> you could see it work just fine because the view will update by itself when the async function is done. (this is part of angular)
You need to understand that when you run $http, it is making an AJAX request. therefore it will not return an result immediately.
Therefore, if you attempt to use the data coming from $scope.stuff.getJobs(); immediate after invoking this function, you are likely to get nothing.
What you should do is to have your Stuff.getJobs() return a promise, and use promise.then(your own success handler) to correctly handle the returned response.
I have cleaned up your code a little bit. The following is a running sample of your code retrieving data from Yahoo Weather API.
You can play with it on CODEPEN.
html:
<div ng-app="myApp" ng-controller="appController">
<p>{{data}}</p>
</div>
JS:
var myApp = angular.module("myApp", []);
myApp.factory('Stuff',['$http', function ($http) {
var Stuff = {};
Stuff.data = {};
//sample yahoo weather api
Stuff.api = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22nome%2C%20ak%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys';
Stuff.getData = function() {
var http_stuff_config = {
method: 'GET',
url: Stuff.api + 'stuff/'
};
return $http(http_stuff_config);
};
return Stuff;
}]);
myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
$scope.data = "$http service not ran";
var uncompletedAjaxCall = Stuff.getData();
uncompletedAjaxCall.then(
function(responseData){
$scope.data = responseData;
},
function(errorMsg){}
);
}]);

Ajax with external parameter Angular

I am new to angular and what I am willing to do is replace a piece of code I wrote in the past in jquery to angularjs.
The goal is to take a string from a span element, split it in two and pass the two strings as parameters in a GET request.
I am trying to learn best coding pratices and improving myself so any comments of any kind are always welcome.
Working Code in jquery:
//Get Song and Artists
setInterval(function () {
var data = $('#songPlaying').text();
var arr = data.split('-');
var artist = arr[0];
var songTitle = arr[1];
//Request Lyrics
$.get('lyricsRequester.php', { "song_author": artist, "song_name" : songTitle},
function(returnedData){
console.log(returnedData);
$('#refreshLyrics').html(returnedData);
});
},10000);
Code in Angular
var app = angular.module("myApp", []);
app.factory('lyricService', function($http) {
return {
getLyrics: function($scope) {
//$scope.songArr = $scope.currentSong.split('-'); <-- **undefined currentSong**
//$scope.artist = $scope.songArr[0];
//$scope.songTitle = $scope.songArr[1];
return
$http.get('/lyricsRequester.php', {
params: {
song_author: $scope.artist,
song_name: $scope.songTitle
}
}).then(function(result) {
return result.data;
});
}
}
});
app.controller('lyricsController', function($scope, lyricService, $interval) {
$interval(function(){
lyricService.getLyrics().then(function(lyrics) {
$scope.lyrics = lyrics; <-- **TypeError: Cannot read property 'then' of undefined**
console.log($scope.lyrics);
});
}, 10000);
});
index.html (just a part)
<div class="col-md-4" ng-controller="lyricsController">{{lyrics}}</div>
<div class="col-md-4"><h3><span id="currentSong" ng-model="currentSong"></span></h3><div>
You need to be careful with your return statement when used in conjunction with newlines, in these lines:
return
$http.get('/lyricsRequester.php',
If you don't, JS will automatically add a semicolon after your return, and the function will return undefined.
Move the $http.get statement to the same line as your return statement.
return $http.get('/lyricsRequester.php', ...
Refer to the following docs:
MDN return statement
Automatic Semicolon Insertion
As for your second issue, you $scope is not really something you inject into your services (like $http). Scopes are available for use in controllers.
You need to refactor your code a bit to make things work.
eg. Your getLyrics function can take a song as a parameter. Then in your controller, you call lyricsService.getLyrics(someSong). Scope access and manipulation are only done in your controller.
app.factory('lyricService', function($http) {
return {
getLyrics: function(song) {
var songArr = song.split('-');
var artist = songArr[0];
var songTitle = songArr[1];
return $http.get('/lyricsRequester.php', {
params: {
song_author: artist,
song_name: songTitle
}
}).then(function(result) {
return result.data;
});
}
}
});
app.controller('lyricsController', function($scope, lyricService) {
$scope.currentSong = 'Judas Priest - A Touch of Evil';
$interval(function(){
lyricService.getLyrics($scope.currentSong).then(function(lyrics) {
$scope.lyrics = lyrics;
console.log($scope.lyrics);
});
}, 10000);
});
You also have some other issues, like using ng-model on your span. ng-model is an angular directive that is used in conjunction with form elements (input, select etc.), not a span as you have. So you might want to change that into an input field.
$http does not use .then, it uses .success and .error. the line that you have where it says then is undefined, should be replaced with a success and error handler instead. Below is a sample from the docs:
// Simple GET request example :
$http.get('/someUrl').
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
See Link:
https://docs.angularjs.org/api/ng/service/$http

AngularJS : Shared Service property not bound to controllers

(please try not to get hung up on any typo's or semantics that may have occurred while transferring it to this post. I know that the code successfully executes so my issue isn't typo's. Also while I am interested in other ways of performing this task - using a single controller for example - I am more interested in why THIS scenario is not working. It may be something that comes up again and it would be nice to already understand the issue)
I am trying to do something that i thought would be fairly simple and after following several tutorials and Stack Overflow posts (as well as other places) I cannot see what I am missing. I am hoping that a pair of fresh eyes can help!
The HTML contains a form where new products can be added (for brevity I have reduced the number of elements) and a list of P tags where products are displayed ... The goal is to add the new products to the list as soon as they are created, without, obviously, refreshing the page.
<div style="width: 300px; float: left; display: inline-block;" data-ng-controller="ProductFormCtrl" data-ng-model="svc">
<p>
Name:
<input type="url" id="txProductName" data-ng-model="svc.form.productName"/>
</p>
<button id="btnSubmit" data-ng-click="svc.addNewProduct()">submit</button>
{{ svc.Title }}
</div>
<div id="dvProductList" style="position:relative;float:left;" data-ng-controller="ProductListCtrl">
<h2>{{ svc.Title }} </h2>
<P data-ng-repeat="product in svc.products">{{ product.ProductName }}</P>
</div>
The form and the list are managed by separate controllers ... each of which references a ProductService with their $scope variable ...
var app = angular.module('productApp', []);
app.controller('ProductFormCtrl', ['$scope', '$http', 'ProductService', function ($scope, $http, $productSvc) {
$scope.svc = $productSvc;
$scope.svc.Title = "Tea";
}]);
app.controller('ProductListCtrl', ['$scope', '$http', 'ProductService', function ($scope, $http, $productSvc) {
$scope.svc = $productSvc;
}]);
In order to referesh the list, the thought was to bind the P element in the ProdcutListCtrl to the products property of the ProductService, and when a new product was added simply update the contents of the products property and voila! ... or not ...
The service defines the property "products" whose value is initialized by a call to web service. It's an array of lightweight product objects.
app.service('ProductService', ['$http', function ($http) {
var self = this;
self.Title = "Coffee";
//
// initialize the property to be referenced by both controllers
(function () {
$http.get("/API/ProductAPI/GetUserProducts/36d43a01-22e5-494d-9e46-2d4ea5df7001")
.success(function (data) {
self.products = data;
});
})();
//
// object to hold the form values
self.form = { productName: '' };
//
// calls web service to add a new product
self.addNewProduct = function () {
var formData = new FormData();
formData.append('ProductName', self.form.productName);
$.ajax({
type: "POST",
url: "/API/ProductAPI/AddUserProduct/36d43a01-22e5-494d-9e46-2d4ea5df7001",
data: formData,
processData: false,
contentType: false
})
.done(function (data) {
if (data != null) {
//
// These changes are not expressed in the User Interface
self.products.push(data); // Update the products property with the new product
self.Title = "Completed"; // Update the title property
}
});
};
}]);
So my expectation is that by "pushing" the new object into the existing array, the product list which references the "products" property would automagically update. I even update the Title property when the request is completed and that change is also not being displayed in the form.
I KNOW that the new product is being created in the databse and even
that it's being returned ... in fact I have confirmed that the
"self.products" property is even being updated.
I also considered that since a SERVICE is actually an instantiation that
perhaps a different instance of the ProductService is being passed
to each controller. I have eliminated this as a possibility since I can change the property, svc.Title, in one controller and see that it is
propogated to the other controller ("Coffee" changes to "Tea").
Anyway ... it appears as though I am somehow losing the reference to the "self." properties when the AJAX request to add a new product is completed and I am not sure why that is. I would welcome any thoughts or guidance.
Thanks,
-G
!! SOLUTION !!
Thanks to shaunhusain for the solution ... pretty simple resolution actually. I added a dependency on $rootScope to the service and in the success handler of the jQuery AJAX request I added a call to $apply to the $rootScope. That's it. :)
app.service('ProductService', ['$http', '$rootScope', function ($http, $rootScope) {
// ...
// all this stuff stayed the same
// ...
//
// calls web service to add a new product
self.addNewProduct = function () {
var formData = new FormData();
formData.append('ProductName', self.form.productName);
$.ajax({
type: "POST",
url: "/API/ProductAPI/AddUserProduct/36d43a01-22e5-494d-9e46-2d4ea5df7001",
data: formData,
processData: false,
contentType: false
})
.done(function (data) {
if (data != null) {
self.products.push(data);
self.Title = "Completed";
$rootScope.$apply(); // <-- Here's the fix ...
}
});
};
}]);
Since you're using jQuery and not $http you need to trigger a $digest after you make the changes for the watches to be triggered to update, in your .done function call $scope.$apply();
Anytime you do something that updates the data but is being done async and/or is outside the context of an angular call you need to call $apply to trigger the watches to update (anything not in a function called by ng-click or something using $http or $timeout because these all call $apply for you).

Pass results from one factory/service ajax method to another via the controller in AngularJS

I have two ajax calls in a service; the first one, AjaxOne gets the data I want from fields (user entered), I then want to alter the data by passing it to another ajax call, AjaxTwo to get the results I need. Both ajax calls are completely different services and can be interacted with by multiple controllers so I've placed then in their own unique Angular factory methods (could be service).
Issue is I'm thinking traditional sequential code running akin to PHP in my little semi-sudo code below (which I know will not work but just for example of how I would solve it in PHP), but I know I need to be thinking in parallel but can't quite get my head around what I need to do for the controller to be able to pass the results from AjaxOne to AjaxTwo. Keep in mind that both factory methods don't need to know of each other existence (to create no coupling and make then highly reusable).
How would I go about doing what I need to with Angular?
app.controller('app', function( $http, $scope, AjaxOne, AjaxTwo ) {
$scope.fields = '';
$scope.ajaxOne = AjaxOne;
$scope.ajaxTwo = AjaxTwo;
$scope.results = [];
$scope.process = function () {
AjaxOne.getResults($scope.fields);
$scope.results = AjaxTwo.getResults(AjaxOne.results);
};
});
Thanks.
Seems like you need to adjust your AjaxOne service to accept a callback, which would asynchronously call AjaxTwo only when AjaxOne is done doing whatever it does:
// Inside AjaxOne:
$scope.getResults = function(things, cb) {
// do something with `things`. Let's assume you're using $http:
$http({
url: "http://example.appspot.com/rest/app",
method: "POST",
data: {
"foo": "bar"
}
}).success(function(data, status, headers, config) {
cb(data);
});
};
// In your original example:
app.controller('app', function($http, $scope, AjaxOne, AjaxTwo) {
$scope.fields = '';
$scope.ajaxOne = AjaxOne;
$scope.ajaxTwo = AjaxTwo;
$scope.results = [];
$scope.process = function() {
AjaxOne.getResults($scope.fields, function(resultsFromAjaxOne) {
$scope.results = AjaxTwo.getResults(resultsFromAjaxOne);
});
};
});
You should use the promises that you get with the $http service it will give something like this
app.controller('app', function( $http, $scope, AjaxOne, AjaxTwo ) {
$scope.fields = '';
$scope.results = [];
$scope.process = function () {
AjaxOne.getResults($scope.fields).success(function(results){
AjaxTwo.getResults(results).success(function(results2){
$scope.results = results2;
});
});
};
});
for more information you can check this url http://docs.angularjs.org/api/ng/service/$http

making ajax request in meteor helpers

How can i wait until the ajax request finishes when returning data to a meteor helpers method.
For example,
Template.item.helpers({
itemName:function () {
var user = Meteor.user();
$.when(reallyLongAjaxRequest()).done(function (a1) {
//tried using jquery when
return "Item Name should have this because it waited";
});
return " Doesnt wait at all";
}
});
I have a reallyLongAjaxRequest() running and i would like it to finish before continuing on with my itemName helper. The log statement to console always shows undefined but that's because the ajax request hasn't finished. I tried using the jquery when with no luck. Any ideas
Edit:
I should mention that i am inside the helper function for a reason. I need the item 'id' being rendered so that i can run the ajax request with that paramater. Using reactive sessions would be perfect but i don't know of a way to get currently rendering items outside of the helpers method definition?
An unnamed collection is one where null is passed for the name. It is an in-memory data structure, not saved to the database. (http://docs.meteor.com/#meteor_collection)
OK, given a Meteor collection called "items" and wanting to do an ajax request for each item based on the item _id, and then being able to reference the ajax result in a template, this is what I'd do:
(roughly)
var Items = new Meteor.Collection('items');
var Results = new Meteor.Collection(null);
Items.find().observeChanges({
added: function (id) {
$.get(url, {id: id}, function (data) {
if (Results.findOne(id))
Results.update(id, {$set: {result: data}});
else
Results.insert({_id: id, result: data});
});
}
});
Template.item.itemName = function (id) {
var doc = Results.findOne(id);
if (doc)
return doc.result;
else
return "";
};
inside your html you'll need to pass in the id to the helper:
{{itemName _id}}
Is there no way to just timeout for a few seconds when defining the helper so that my ajax request finishes without immediately returning.
No, with reactive programming things happen immediately, but you update when you have new stuff.
Make your ajax request separately, and when it completes, have it store the result in a Session variable. Then have your template helper return the value of the Session variable. Roughly...
$.get(url, function (data) {
Session.set('result', data);
});
Template.item.itemName = function () {
return Session.get('result');
};
Session is a reactive data source, so your template will automatically updated when the result of the ajax call comes in. (Naturally you can choose to call the Session variable anything you like, I just used "result" as an example).
This works and tested in MeteorJS > 1.3.x
Add the http package from the console meteor add http
Example POST call with data elements being sent to server and with custom headers.
HTTP.call('POST', tokenUri, {
data: {
"type": 'authorization_code',
//"client_id": clientId,
"code": code,
"redirect_uri" : redirectUri,
},
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : "true",
"Access-Control-Allow-Methods" : "GET,HEAD,OPTIONS,POST,PUT",
"Access-Control-Allow-Headers" : "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers",
}
},function(error, response) {
if ( error ) {
console.log( error );
} else {
console.log( response );
}
});

Categories