angular js force.com Javascript remoting - angularjs

I am new to Angular JS and really struggling to get data into my controller from javascript remoting. Has anyone done this before?
Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.Forecasting.Users}',
new Object(),function(result, event){
return result
}
);
How on earth do i get the data into the controller :
var forecastingCtrl = function($scope, $q){
$scope.lengths = function(){return '5'};
$scope.users = [];
}
EDIT : Following works fine:
fc.service('Users', function($rootScope, $q) {
this.get = function(){
var deferred = $q.defer();
Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.Forecasting.Users}',new Object(),function(result, event){
if(event) {
$rootScope.$apply(function() {
deferred.resolve(result);
});
} else {
deferred.reject(result);
}
});
return deferred.promise;
}
});
function forecastingCtrl($scope, $q, Users){
$scope.lengths = function(){return '5'};
var promise = Users.get();
promise.then(
function(users){
$scope.users = users;
},
function(reason){
alert('Failed: ' + reason);
}
);
};

I haven't used javascript remoting (sounds interesting) but what you will probably want to do is to encapsulate your visualforce code inside a service, having a method (most likely a promise) to return your data and inject the service into your controller. The upside of this is that you can unit test your controller by injecting a mock or spy of your data service. The pattern would be very much like how you would use angular's $http and $resource services. Hopefully this gets you on the right track.

Related

How to use 'Controller as' with $http in Angular

I'm trying to load some data through $http to prefill a profile form. Unfortunately all the examples I find online use the $scope-approach rather than 'Controller as'-approach (which I'm using to make future transition to Angular 2 easier). These examples assign the $http response to the '$scope' variable, which is not possible when using 'this'.
After a lot of fiddling I managed to get it to work by adding a temp variable
var temp = this;
to which I can assign the $http response when it successfully returns.
angular.module('angularUserApp')
.factory('ajax',['$http',function($http){
return {
getProfile: function(){
return $http.get('/ajax/user/profile')
.then(function(response){
return response.data.data.profile;
});
}
}
}])
.controller('userProfileCtrl', ['ajax', function (ajax) {
var temp = this;
ajax.getProfile().then(function(response){
temp.profile = response;
});
}]);
Is there a more elegant approach?
Your approach for using controllerAs is correct. Just a few advices though, better alias the this to a variable vm, which stands for viewModel instead of temp, and name your service semantically: userService instead of ajax:
angular.module('angularUserApp')
.factory('userService', function ($http){
return {
getProfile: function () {
return $http.get('/ajax/user/profile')
.then(function (response){
return response.data.profile;
});
}
}
})
.controller('userProfileCtrl', function (userService) {
var vm = this;
userService.getProfile().then(function (response) {
vm.profile = response;
});
});
One of the design ideas of angular is that you can use $scope. Simply inject $scope into your controller, like you did with your ajax service and set the profile response to the $scope variable ($scope.profile = response;).
As a result you would get something like:
angular.module('angularUserApp')
.factory('ajax',['$http',function($http){
return {
getProfile: function(){
return $http.get('/ajax/user/profile')
.then(function(response){
return response.data.data.profile;
});
}
}
}])
.controller('userProfileCtrl', ['ajax', '$scope', function (ajax, $scope) {
ajax.getProfile().then(function(response){
$scope.profile = response;
});
}]);
// In your template
<div ng-controller="userProfileCtrl">
<div ng-bind="profile.name"></div>
</div>

Making the most of my factory

I am new to Angular, so if you ask the question: "Why don't you...?" The answer is...because I didn't know I could.
Have a factory make an API call, then inject that factory into a parent controller that will have scope over the entire page. Then have child controllers nested and inherit from the parent controller.
Here is what I have so far. I may be WAY off here, and if that is the case, please tell me. I am working on this alone, and have no help, so any help is welcomed.
Thank you.
var app = angular.module('myApp', []);
app.factory('myFactory', function($http){
var MyFactory = function(){};
MyFactory.getParams = function(){
return $http.get('/getparameters');
.success(function(data){
var roomname = data.roomname;
})
MyFactory.getRoom(roomname);
};
MyFactory.getRoom = function(room){
return $http.get('/my/api/' + room);
};
});
app.controller('RoomCtrl', function($scope, myFactory){
$scope.data = myFactory;
});
You don't need to use resource, you need use promise;
EDITED
I tried to make more clear for you
app.factory('apicall', ['$q','$http',function($q, $http){
function getRoom(options){
var promise = $http.get(options.paramUrl)
.success(function(data){
//handle your error
return $http.get(options.roomUrl + data.roomname);
})
.error(function(msg){
return $q.when(msg)
})
return promise;
}
return {getRoom:getRoom};
}])
if you want call your factory in where you want
app.controller('RoomCtrl', ['$scope','apicall',function($scope, apicall){
var options = {
paramUrl:'/getparameters',
roomUrl:'/my/api/'
}
apicall.getRoom.all(function(result){
$scope.data = result;
})
}]);
The $q service helps you to handle combination of two asynchronous calls
app.factory('apicall', function($q, $http) {
var deferred = $q.defer();
$http.get('/getparameters')
.success(
function(data) {
var roomname = data.roomname;
$http.get(baseURL + 'room/' + roomname)
.success(
function(roomData) {
deferred.resolve(roomData);
}
)
.error(
function() {
deferred.reject();
}
)
})
.error(
function() {
deferred.reject();
}
);
return deferred.promise;
});
And here is controller where you can use your service
app.controller('someCtrl', function(apicall) {
apicall.then(
function(roomData) {
//success
},
function() {
//error
}
)
})
I usually separate different API calls in different factories that return a $resource.
For example, let's say we have 2 different API calls that point to different resources:
yourwebsite.com/user/:userId - returns data about the user
yourwebsite.com/photo/:photoId - return data about some photo
In angular, you would split these in 2 different factories:
"use strict";
angular.module("App.services").
factory("User",["$resource", function($resource){
return $resource("yourwebsite.com/user/:userId"),{userId:"#userId"});
}]);
and second
angular.module("App.services").
factory("Photo",["$resource", function($resource){
return $resource("yourwebsite.com/photo/:photoId"),{photoId:"#photoId"});
}]);
In your controller, you would use them like so:
angular.module("App.controllers").controller("TestController",["User","Photo", function(User, Photo){
User.get({
id:10
}).$promise.then(function(data){
console.log(data); //returns the data for user with the id=10
});
Photo.get({
id:123
}).$promise.then(function(data){
console.log(data);
});
}]);
Usually $resource maps a CRUD API(what I posted above is a basic example of a GET call).Check out the documentation on $resource - It already has the basic GET, PUT, POST, DELETE functions.
I would recommend using $http if you have only 1 simple operation on that URL and not all 4 of them. You can then inject $http in your controller and do the request there instead of creating a factory for it.
If you have 2 requests and they are chained(second one depends on the data received from the first one) you have to wait until the first one is resolved. With $resource you can do this in the following way:
angular.module("App.controllers").controller("TestController",["User","Photo", function(User, Photo){
var user_promise = User.get({
id:10
}).$promise.then(function(data){
console.log(data); //returns the data for user with the id=10
return data;
});
var photo_promise = Photo.get({
id:123
}).$promise.then(function(data){
console.log(data);
return data;
});
user_promise.then(photo_promise).
catch(function(error){
console.log(error); //catch all errors from the whole promise chain
});
}]);

update a service variable within an $http callback

I'm using a service to make user data available to various controllers in my Angular app. I'm stuck trying to figure out how to use the $http service to update a variable local to the service (in my case "this.users"). I've tried with and without promises. The server is responding correctly.
I've read several excellent articles for how to use $http within a service to update the scope of a controller. The best being this one: http://sravi-kiran.blogspot.com/2013/03/MovingAjaxCallsToACustomServiceInAngularJS.html. That does not help me though because it negates the benefits of using a service. Mainly, modifying the scope in one controller does not modify throughout the rest of the app.
Here is what I have thus far.
app.service('UserService', ['$http', function($http) {
this.users = [];
this.load = function() {
var promise = $http.get('users.json')
.success(function(data){
// this.users is undefined here
console.log(this.users);
}
};
promise.then(function() {
// this.users is undefined here
console.log('this.users');
});
}]);
Any help is greatly appreciated. Thank you.
Try using
var users = [];
rather than
this.users = [];
and see what
console.log(users);
outputs in each of those cases.
Your service is oddly defined, but if you have a return in it you can access it from any controller:
app.service('UserService', ['$http', function($http) {
var users = [];
this.load = function() {
var promise = $http.get('users.json')
.success(function(data){
// this.users is undefined here
console.log(users);
users = data.data;
}
};
return {
getUsers: function(){
return users;
}
}
}]);
so in your controller, you can use:
var myUsers = UserService.getUsers();
UPDATE to use a service correctly here, your service should return a promise and the promise should be accessed in the controller: Here's an example from another answer I gave
// your service should return a promise
app.service('PickerService', [$http', function($http) {
return {
getFiles: function(){
return $http.get('files.json'); // this returns a promise, the promise is not executed here
}
}
}]);
then in your controller do this:
PickerService.getFiles().then(function(returnValues){ // the promise is executed here as the return values are here
$scope.myDirectiveData = returnValues.data;
});
this does not have scope anymore where you are trying to use it do this instead:
app.service('UserService', [$http', function($http) {
var users = [];
this.load = function() {
var promise = $http.get('users.json')
.success(function(data){
console.log(users);
}
};
promise.then(function() {
console.log(users);
});
}]);
all local variables to a service should just be vars if you assign them to this as a property than they will be included every time the service is injected into a controller which is bad practice.
I think what your asking for is a solution along the lines of defining your service like this:
angular.module('app')
.service('User', function($http, $q) {
var users = null;
var deferred = $q.defer()
return {
getUsers: function() {
if(users) {
deferred.resolve(users);
} else {
$http.get('users.json');
.success(function(result) {
deferred.resolve(result);
})
.error(function(error) {
deferred.reject(error);
});
}
return deferred.promise;
}
};
});
Then in one Each controller you would have to do this:
angular.module('app')
.controller('ACtrl', function($scope, User) {
User.getUsers().then(function(users) {
// Same object that's in BCtrl
$scope.users = users;
});
});
angular.module('app')
.controller('BCtrl', function($scope, User) {
User.getUsers().then(function(users) {
// Same object that's in ACtrl
$scope.users = users;
});
});
NOTE: Because the deferred.promise the same promise passed to all controllers, executing deferred.resolve(users) in the future will cause all then success callbacks in each of your controllers to be called essentially overwriting the old users list.
All operations on the list will be noticed in all controllers because the users array is a shared object at that point. This will only handle updates to the user list/each individual user on the client side of your application. If you want to persist changes to the server, you're going to have to add other $http methods to your service to handle CRUD operations on a user. This can generally be tricky and I highly advise that you check out ngResource, which takes care of basic RESTful operations

How can I get a service to access server data via an $http call?

I make an $http call inside a service that is supposed to get data from my server. For some reason I can't get my service to work - nothing happens. I know the server code works because if I place the $http call inside a function within my controller, then it gets the server data as expected. Here is the code I have so far:
app.service('myService', function($q,$compile,$http) {
this.getData = function() {
var deferred = $q.defer();
var promise = $http.get('myfile.php').success(function (data) {
var response = $compile(data)($scope);
deferred.resolve(response);
});
return deferred.promise;
};
});
Also, I know the code that uses this service works because if I do something like the following,
app.service('myService', function() {
this.getData = function() {
return 'TEST';
};
});
then I will see the word "TEST" show up in the div that utilizes this service. I feel like I'm very close, but there is something I am missing. Any ideas on what I'm doing wrong?
UPDATE:
controller: function($scope, $http, $rootScope, myService){
var scope = $rootScope;
scope.viewMyData = function() {
var element = myService.getData();
$('#myDiv').html(element);
}
}
HTML:
<div ng-click="viewMyData()">Click Here</div>
<div id="myDiv"></div>
If I strip the code in myService and simply return TEST (as above), then I will see "TEST" show up in id="myDiv". But for some reason the $http call isn't being triggered.
#tymeJV is right, but here's my attempt to spell out the example better. $http returns a promise interface that allows you to chain callbacks to be executed when the $http response returns. So, in this case, calling myService.getData() can't return the result immediately (it's off getting the data from the server), so you need to give it a function to execute when the server finally responds. So, with promises, you simply attach your callback using the thePromise.then(myCallbackFunc).
Service
app.service('myService', function($q,$compile,$http) {
this.getData = function() {
var promise = $http.get('myfile.php');
promise = promise.then(function (response) {
return response.data;
});
return promise;
};
});
Controller
controller: function($scope, $rootScope, myService){
var scope = $rootScope;
scope.viewMyData = function() {
myService.getData().then(function(data) {
$('#myDiv').html(element);
});
}
}
Use .then in the controller to continue the promise pattern:
myService.getData().then(function(data) {
$('#myDiv').html(data);
});

Cache Data with $resource promises pattern

Assuming my service is returning a promise from a $resource get, I'm wondering if this is the proper way to cache data. In this example, after hitting the back arrow and returning to the search results, I don't want to query the webserver again since I already have them. Is this the proper pattern to handle this situation? The example below is querying the Flixter (Rotten Tomatoes) Api.
Boilded down code:
Controller:
function SearchCtrl($scope, $route, $routeParams, $location, DataService) {
DataService.search($routeParams.q).then(function(data){
$scope.movies = data.movies;
});
}
Service:
angular.module('myApp.services', []).
factory('DataService', ['$q', '$rootScope', 'JsonService', function ($q, $rootScope, JsonService) {
var movie = {};
var searchResults = {};
var searchq = '';
var service = {
search: function(q) {
var d = $q.defer();
// checking search query, if is the same as the last one,
//resolve the results since we already have them and don't call service
// IS THIS THE CORRECT PATTERN
if (q==searchq) {
d.resolve(searchResults);
} else {
// returns a $resource with defined getdata
JsonService.search.movieSearch(q, 20, 1).getdata(function(data){
searchResults = data;
searchq = q;
d.resolve(searchResults);
});
}
return d.promise;
},
getSearchResults: function() {
return searchResults;
}
};
return service;
}]);
I can't provide a working example as it would expose my API key.
I've faked out the actual ajax request but I think the general idea should apply, you can see the full demo here
Here is the controller, it just executes the search and then sets the results:
myApp.controller('MyCtrl', function($scope, DataService) {
$scope.search = function(){
DataService
.search($scope.q)
.then(function(response){
$scope.fromCache = response.fromCache;
$scope.results = response.results;
});
};
});
In the DataService I am just saving results into an object keyed off the query. It is simplistic but hopefully will get you started. You could save it in html5 storage or something if you want something like that.
You will need to put in your actual ajax call here, but the principle remains.
myApp.factory('DataService', function($q){
var resultsCache = {};
return {
search: function(query){
var deferred = $q.defer();
if (resultsCache[query]) {
resultsCache[query].fromCache = true;
}
else {
resultsCache[query] = {results: [{name: 'result one'}, {name: 'result two'}]};
}
deferred.resolve(resultsCache[query]);
return deferred.promise;
}
};
});
Hope that helps

Resources