AngularJS - Using $resource and interact with a RESTful data source - javascript

I've had a problem in my previous topic, that I couldn't consume my service.
After doing some research I could finally figure out a way to consume my service after all. Still I was wondering why my other approach with the javascript object as method container didn't work out. I have some guesses but can't find an appropriate solution.
Hopefully you guys can lead me on the right path.
controller.js (Working solution)
angular.module('TodoApp.controllers', []).
controller('listCtrl', function ($scope, $location, todoApiService) {
$scope.todos = todoApiService.query();
});
services.js (Working solution)
angular.module('TodoApp.services', []).
factory('todoApiService', function ($resource) {
return $resource('/api/todo/:id', { id: '#id' }, { update: { method: 'PUT' } });
});
controllers.js (Not working solution)
angular.module('TodoApp.controllers', []).
controller('listCtrl', function ($scope, $location, todoApiService) {
$scope.todos = todoApiService.getMyTodos.query();
});
services.js (Not working solution)
angular.module('TodoApp.services', []).
factory('todoApiService', function () {
var todoApi = {};
todoApi.getMyTodos = function ($resource) {
return $resource('/api/todo/:id', { id: '#id' }, { update: { method: 'PUT' } });
};
return todoApi;
});

You should either:
Inject $resource to your factory function, just like you did in the working version. And then you can remove the $resource as a parameter for getMyTodos.
angular.module('TodoApp.services', []).
factory('todoApiService', function ($resource) {
var todoApi = {};
todoApi.getMyTodos = function () {
return $resource('/api/todo/:id', { id: '#id' }, { update: { method: 'PUT' } });
};
return todoApi;
});
And then from the controller:
angular.module('TodoApp.controllers', []).
controller('listCtrl', function ($scope, $location, todoApiService) {
$scope.todos = todoApiService.getMyTodos().query();
});
Or, you can pass the $resource from the controller to getMyTodos (after injecting it to the controller) - so your controller would look like:
angular.module('TodoApp.controllers', []).
controller('listCtrl', function ($scope, $location, todoApiService, $resource) {
$scope.todos = todoApiService.getMyTodos($resource).query();
});
I didn't check to see that this is working, but it should :)

Related

Need help on Angular Factory

Hi SO angular community !
I'm very confused, I think I have understand the factory purpose and concept, but seems not ...
Here is my problem (surely simple for you) :
I want to use my REST API (working perfectly) using Angular and .factory ...
rest.js
var app = angular.module('urlShortener', ['ngRoute', 'ngResource']);
app.factory('API', ['$resource',
function($resource){
return $resource('/link'});
}],{
get: {method:GET},
post: {method:POST},
put: {method:PUT},
delete: {method:DELETE},
}
);
app.controller('GetAll', function ($scope) {
$scope.links = API.get();
});
index.ejs
<div ng-controller="GetAll">
<ul>
<li ng-repeat="link in links">
<p>{{link.itemId}} --> {{link.url}}</p>
</li>
</ul>
</div>
Not working ... 2 hours I'm consulting the Angular API, and no solutions :/
Please help me I'm wasting time :'(
\\\\ SOLUTION ////
rest.js
app.factory('API', ['$resource', function($resource) { return $resource('/link'); }]);
app.controller('GetAll', ['$scope', 'API', function ($scope, API) {
API.query().$promise.then(function(links) {
$scope.links = links;
});
}]);
Thanks to #dfsq help :)
You can't just assign $resource instance to $scope.links, you need to do it when underlying promise resolves:
app.controller('GetAll', ['$scope', 'API', function ($scope, API) {
API.get().$promise.then(function(links) {
$scope.links = links;
});
}]);
You have to inject "API" in your controller.
app.controller('GetAll', function ($scope, API) {
$scope.links = API.get();
});
If your rest service returns an array of objects you need to use query function.
$scope.links = API.query(); // instead of API.get()
If you need to do anything else when the promise returns use something like this:
API.query().$promise.then(function(result){
$scope.links = result;
// any other operation related to the request here
});
if you want to do api requests, use $http
this is a piece of code I use in my app:
angular
.module('myApp')
.factory('apiFactory', apiFactory);
function apiFactory($http) {
return {
getDataFromApi: getDataFromApi,
};
function getDataFromApi(url) {
return $http({
method: 'GET', // or post or whatever
url: url,
headers: {
...
}
})
.then(success)
.catch(fail);
function success(response) {
return response.data;
}
function fail(response) {
// handle error
}
}
}
Is this what you are looking for?
API For Resources
services.factory('Api', ['$resource',
function($resource) {
return {
Recipe: $resource('/recipes/:id', {id: '#id'}),
Users: $resource('/users/:id', {id: '#id'}),
Group: $resource('/groups/:id', {id: '#id'})
};
}]);
function myCtrl($scope, Api){
$scope.recipe = Api.Recipe.get({id: 1});
$scope.users = Api.Users.query();
...
}

myfunction() function call from one controller to another in angularjs

i have used Angularjs and i wanna call getcustomer function from one controller to another controller i have so many doing gooogling but i don't have an idea that how to call that
i have write below code which i used
var app = angular.module('Napp', []);
app.controller('GetAlphabetical', function ($scope, $http) {
function getCutomers() {
$scope.loading = true;
$http.get('#Url.Content("~/Home/GetPesrons")').then(function (response) {
//var _data = angular.fromJson(response);
$scope.loading = false;
$scope.Customer = response.data; // please check the request response if list id in data object
}, function (error) {
throw error;
})
}
});
and second controller :
app.controller('MainCtrl', function ($scope, $http) {
getCutomers()
});
Mate, you will have to follow the following steps to resolve your problem. Firstly you have you create a factory
angular
.module('Napp')
.factory('CustomerFactory', ['$http', function ($http) {
var _factory = {};
_factory.getCustomers = function () {
return $http.get('#Url.Content("~/Home/GetPesrons")');
};
return _factory;
}]);
Then you can share data and functions between multiple controllers or services
GetAlphabetical Controller :
angular
.module('Napp')
.controller('GetAlphabetical', ['$scope', 'CustomerFactory', function ($scope, CustomerFactory) {
loadCustomers();
function loadCustomers() {
CustomerFactory.getCustomers().then(function (successResponse) {
$scope.Customer = successResponse.data; // please check the request response if list id in data object
}, function (errorResponse) {
throw error;
})
}
}]);
MainCtrl Controller :
angular
.module('Napp')
.controller('MainCtrl', ['$scope', 'CustomerFactory', function ($scope, CustomerFactory) {
loadCustomers();
function loadCustomers() {
CustomerFactory.getCustomers().then(function (successResponse) {
$scope.Customer = successResponse.data; // please check the request response if list id in data object
}, function (errorResponse) {
throw error;
})
}
}]);
This can be easily done by defining it as a service and injecting it as a dependency.
var app = angular.module('myApp', []);
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!"
};
});
app.controller('MainCtrl', function ($scope, $http, helloWorldFromService) {
app.controller('GetAlphabetical', function ($scope, $http, helloWorldFromService) {
Angular Service
What you want to do is to somehow communicate between two controllers. This can be easily be achieved using $broadcast & $on.
Incase there is a parent child relation between your controllers, use the following.
function firstCtrl($scope){
$scope.$broadcast('someEvent', [1,2,3]);
}
function secondCtrl($scope){
$scope.$on('someEvent', function(event, mass) {console.log(mass)});
}
If there is no parent child relationship between your controller, then inject $rootScope and broadcast using that.
related question - https://stackoverflow.com/a/14502755/1182982

Angular watch factory value

Say i have the following factory:
app.factory("categoryFactory", function (api, $http, $q) {
var selected = null;
var categoryList = [];
return {
getList: function () {
var d = $q.defer();
if(categoryList.length <= 0){
$http.get(api.getUrl('categoryStructure', null))
.success(function (response) {
categoryList = response;
d.resolve(categoryList);
});
}
else
{
d.resolve(categoryList)
}
return d.promise;
},
setSelected: function (category) {
selected = category;
},
getSelected: function () {
return selected;
}
}
});
now i have two controllers using this factory at the same time. Because of this both controllers has to be notified when updated for this i attempted the following:
app.controller('DashboardController', ['$http', '$scope', '$sessionStorage', '$log', 'Session', 'api','categoryFactory', function ($http, $scope, $sessionStorage, $log, Session, api, categoryFactory) {
$scope.selectedCategory = categoryFactory.getSelected();
}]);
While my other controller looks like this:
app.controller('NavController', ['$http', '$scope', '$sessionStorage', '$log', 'Session', 'api', 'FileUploader', 'categoryFactory', function ($http, $scope, $sessionStorage, $log, Session, api, FileUploader, categoryFactory) {
$scope.categories = [];
categoryFactory.getList().then(function (response) {
$scope.categories = response;
});
$scope.selectCategory = function (category) {
categoryFactory.setSelected(category);
}
}]);
how ever when the NavController changed the value it was not changed in the DashboardController
My question is how can i either watch or in another way get notified when the value changes?
You can use an observer pattern, like so:
app.factory("categoryFactory", function (api, $http, $q) {
// the list of callbacks to call when something changes
var observerCallbacks = [];
// ...
function notifyObservers() {
angular.forEach(observerCallbacks, function(callback) {
callback();
});
}
return {
setSelected: function (category) {
selected = category;
// notify the observers after you change the value
notifyObservers();
},
registerObserver: function(callback) {
observerCallbacks.push(callback);
}
}
});
And then in your controllers:
app.controller('NavController', ['$http', '$scope', '$sessionStorage', '$log', 'Session', 'api', 'FileUploader', 'categoryFactory', function ($http, $scope, $sessionStorage, $log, Session, api, FileUploader, categoryFactory) {
// ...
// init
(function() {
categoryFactory.registerObserver(function() {
categoryFactory.getList().then(function (response) {
$scope.categories = response;
});
});
})();
}]);
This way, any time setSelected is called, it calls each callback that you've registered in observerCallbacks. You can register these from any controller since factories are singletons and they will always be in the know.
Edit: just want to add that I may have put the notifyObservers() call in the wrong area (currently in setSelected) and that I may be putting the wrong update call in the controller (currently getList) but the architecture remains the same. In the registerObserver, put whatever you want to do when the values are updated and wherever you make changes that you want observers to know about call notifyObservers()
You could follow dot rule here so that prototypal inheritance will get followed.
Basically you need to have one object inside your service that will have selected variable, And will get rid of getSelected method.
Factory
app.factory("categoryFactory", function(api, $http, $q) {
var categoryFactory = {};
categoryFactory.getList = function() {
var d = $q.defer();
if (categoryList.length <= 0) {
$http.get(api.getUrl('categoryStructure', null))
.success(function(response) {
categoryList = response;
d.resolve(categoryList);
});
} else {
d.resolve(categoryList)
}
return d.promise;
}
categoryFactory.setSelected = function(category) {
categoryFactory.data.selected = category;
}
categoryFactory.data = {
selected: null
}
return categoryFactory;
});
Controller
app.controller('DashboardController', ['$http', '$scope', '$sessionStorage', '$log', 'Session', 'api', 'categoryFactory',
function($http, $scope, $sessionStorage, $log, Session, api, categoryFactory) {
//this will provide you binding without watcher
$scope.selection = categoryFactory.data;
}
]);
And then use {{selection.selected}} on html part will update a value when changes will occur in selection.

How to Redirect with MVC when calling $post in angular

So upfront, I am new to angular so I am a little lost with how I want to accomplish a redirect after I post data back to a server:
I have the following in a update:
$http.post("#Url.Action("SaveBranding", "AirlineConfig")", brandModel.model);
Then on the server I have this in my controller:
[HttpPost]
public ActionResult SaveBranding(BrandingViewModel viewModel)
{
if (IsModelStateValid())
{
var airline = GetAirlineFromAirlinePlatformId(viewModel.AirlinePlatformId);
switch (viewModel.PostAction)
{
case "Save":
BrandingViewModel.SaveEntity(viewModel, _db);
var airlineBranding = BrandingViewModel.FromEntity(_db.AirlinePlatforms.Single(x => x.AirlinePlatformId == viewModel.AirlinePlatformId).BrandingViews, viewModel.AirlinePlatformId);
return View("Branding", airlineBranding);
case "Save & Close":
BrandingViewModel.SaveEntity(viewModel, _db);
return RedirectToAction("Edit", "AirlineConfig", new { id = airline.AirlineId });
case "Cancel":
return RedirectToAction("Edit", "AirlineConfig", new { id = airline.AirlineId });
default:
return HttpNotFound();
}
}
return View("Branding"); //Replace this later
}
My routing isnt working and I am lost how to do this so I can navigate to the correct location.
Use window.location to manually redirect in the browser rather than use a server redirect.
The angular way to redirect is using $location service.
angular.module('someModule', [])
.controller('SomeController', ['$scope', '$http', '$location', someController])
function someController($http, $location) {
$scope.brandModel = {};
$scope.submit = function () {
$http.post("#Url.Action("SaveBranding", "AirlineConfig")", brandModel.model).then(function (data) {
$location.path('/url/to/path');
});
}
}
I put this answer here for completeness. I think also $location is more geared up for handling either hash urls or html5mode urls. If you use raw JavaScript, then you either use window.location.hash = "someUrl" or window.location.href = "someUrl". That could be a little caveat for not doing it the "angular" way.
I noticed also that you include that #Url.Action("", ""), when I did my Angular app with MVC in the index page I did this:
angular.module('someModule', [])
.factory('urlService', urlService)
function urlService() {
var service = {
getSaveBrandingUrl: getSaveBrandingUrl
};
return service;
function getSaveBrandingUrl() {
return '#Url.Action("", "")';
}
}
That way I can have all my other scripts separate, and they only rely on a function name so if you change the URL you don't have to go around the app changing all the links. When you inject this into the controller you would do something like:
angular.module('someModule', [])
.controller('SomeController', ['$scope', '$http', '$location', 'urlService', someController])
function someController($scope, $http, $location, urlService) {
$scope.brandModel = {};
$scope.submit = function () {
$http.post(urlService.getSaveBrandingUrl(), brandModel.model).then(function (data) {
$location.path('/url/to/path');
});
}
}
Obviously then you can tie all that up into it's own service to reduce the injection into the controller:
angular.module('someModule', [])
.factory('someControllerService', ['$http', 'urlService', someControllerService])
.controller('SomeController', ['$scope', '$location', 'someControllerService', someController])
function someController($scope, $location, someControllerService) {
$scope.brandModel = {};
$scope.submit = function () {
someControllerService.saveBranding($scope.brandModel.model).then(function (data) {
$location.path('some/url');
});
}
}
function someControllerService($http, urlService) {
var service = {
saveBranding: saveBranding
};
return service;
function saveBranding(branding) {
return $http.post(urlService.getSaveBrandingUrl(), brandModel.model).then(function (data) {
return data.data;
});
}
}

AngularJS: how to execute a method in another controller?

I've searched on Google but can't find information on how to do this properly. Seems like all the answers on Google are now outdated (using older versions of AngularJS).
I'm trying to setup two controllers on my AngularJS module. For example, the first controller is handling $http GET requests. And the second controller is displaying either a 'success' or 'error' message. I want to be able to call a method from the second controller with the success/error message that is to be displayed.
Or am I supposed to use a service/factory for this? I've read about services but can't figure out how to make something like this work.
var module = angular.module('app', []);
module.controller('ApiController', ['$scope', '$http', function ($scope, $http) {
$http.get('/api').
success(function(data){
// call AlertController('success')
}).
error(function(data){
// call AlertController('failed')
});
}]);
module.controller('AlertController', ['$scope', function ($scope) {
$scope.message = {
show_message: true,
type: 'info',
message: "Display message!"
};
}]);
Either doing it that way, or perhaps I would like to push the incoming alert onto a global object variable, and then remove it after it has been displayed.
Anyone know the proper way to set this up?
Ok let's try this - you should also check out Injecting $scope into an angular service function()
The Message service:
module.service('MessageService', function ($timeout) {
var messageQueue = [];
var DISPLAY_TIME = 5000; // each message will be displayed for 5 seconds
function startTimer() {
$timeout(function() {
// Remove the first message in the queue
messageQueue.shift();
// Start timer for next message (if there is one)
if (messageQueue.length > 0) startTimer();
}, DISPLAY_TIME);
}
function add(message) {
messageQueue.push(message);
// If this is the only message in the queue you need to start the timer
if (messageQueue.length==0) startTimer();
}
function get() {
if (messageQueue.length==0) return "";
else return messageQueue[0];
}
return { add: add, get: get };
});
You can still use this ApiService as well:
module.service('ApiService', ['$http', function ($http) {
return {
get: function(url) {
return $http.get(url);
}
};
}]);
Your Search controller:
module.controller('SearchController', ['$scope', 'ApiService', 'MessageService', function ($scope, api, messages) {
api.get('/yelp').
success(function(data){
messages.add('success');
}).
error(function(data){
messages.add('failed');
});
}]);
Your Alert controller:
module.controller('AlertController', ['$scope', 'MessageService', function ($scope, messages) {
$scope.getMessage = function() { messages.get(); }
}]);
So in your html you can have:
<div ng-controller="AlertController">
<div>{{ getMessage() }}</div>
</div>
here is how you make factory
module.factory('appService', ['$window', '$http', '$q', function(win, $http, $q) {
return{
backendcall: function(){
var deferred = $q.defer();
$http.get('/yelp').
success(function(data){
deferred.resolve(data);
}).
error(function(data){
deferred.resolve(status);
});
return deferred.promise;
}
}
}]);
and your controller will be like this
module.controller('AlertController', ['$scope', 'appService', function ($scope, appService) {
appService.backendcall().then(function(response){
$scope.message = {
show_message: true,
type: 'info',
message: "Display message!"
};
})
}]);

Categories