Right now I have a post method that works fine in a controller but what's the best way to refactor this into a service? Most importantly, I need to be able to pass $scope.tag from ng-model in the post. Then the post makes a call to the server for an external API request using the post params in the url.
// controller
app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.submit = function () {
var recipe = $scope.tag;
$http.post('/api', {tag: recipe})
.then(function(response) {
$scope.recipeData = JSON.parse(response.data);
console.log(response.data);
});
};
// server.js
app.post('/api', function (req, res) {
var recipe = req.body.tag;
request("http://externalapi.com/api/search?key=xxx=" + recipe, function (error, response, body) {
res.json(body);
});
});
// index.html
<form class="form-inline" ng-submit="submit()">
<div class="form-group">
<input type="text" ng-model="tag" class="form-control">
<button type="submit" value="Search" class="btn btn-default search-button"> Search</button>
</div>
</form>
---------refactored code----------
app.factory('searchFactory', ['$http', function ($http) {
var obj = {};
obj.fetchRecipes = function () {
return $http.post("/api", { tag: "chicken" });
};
return obj;
}]);
app.controller('MainController', ['$scope', 'searchFactory', function ($scope, searchFactory) {
$scope.submit = function () {
searchFactory.fetchRecipes()
.success(function(response) {
$scope.recipeResults = response;
});
};
}]);
Refactor request method to a factory service and put request logic in there. ie. SearchService
So, inject SearchService in MainController and access the service request method that returns a promise.
Example:
app.controller('MainCtrl', ['$scope', 'SearchService',
function ($scope, SearchService) {
$scope.submit = function () {
var promise = SearchService.getRecipe( $scope.tag );
..
}
}
]);
Have a look at some of the style guides and best practices by the community, recommended JohnPapa's Styleguide.
Related
I have a problem here, whenever I am clicking the button which is inside the component, I see that I am making the $http call and I don't get the response in the console, but in browser I see the call is made.
It consoles the data only when I uncomment the $timeout function.
JS
var app = angular.module('myApp', []);
app.controller('mainCtrl', [$scope, $http, $timeout, function($scope, $http, $timeout) {
$scope.navigate = function () {
$scope.getStats();
}
$scope.getStats = function () {
//$timeout(function () {
$http
.get('/scripts/controllers/fda/appSvc.json')
.then(function (response) {
console.log(response.data);
}, function (error) {
console.log(error);
})
//}, 0)
};
$scope.detailedTableCtrl = {
navigate: $scope.navigate
}
}]);
app.component("myBox", {
bindings: {
'detailedTableCtrl': '='
},
controller: function($element) {
},
controllerAs: 'myBox',
templateUrl: "/template",
transclude: true
})
HTML
<div ng-app="myApp" ng-controller="mainCtrl">
<my-box detailed-table-ctrl="detailedTableCtrl"></my-box>
</div><!--end app-->
<!--mybox component-->
<button class="btn btn-default btn-sm" ng-click="myBox.detailedTableCtrl.navigate()">
<span class="glyphicon glyphicon-chevron-left"></span>
<span>Back</span>
</button>
As #Amy pointed out i don't see $http service injected. Also please do use service to consume data and inject the service in controller. Your controller shouldn't worry about calling/consuming data.
<!-- Controller to get data from the Service or Factory ( pay attention to service injection here ) -->
app.controller('mainCtrl', ['$scope', 'dataService', function($scope,dataService) {
dataService.getData().then(function(response) {
$scope.response = response.data;
}, function(error) {
$scope.error = error;
$scope.response = [];
});
});
<!-- Factory to handle your data from REST or JSON -->
(function () {
"use strict";
app.factory("dataService",['$http', function($http){
function getData (){
return $http.get('/scripts/controllers/fda/appSvc.json');
}
return {
getData : getData
};
}]);
})();
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
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;
});
}
}
I'm newer in AngularJS. So I have a simple question, but I can't find answer. I have code:
angular.module('app', ['app.controllers', 'ngRoute']).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/users', {templateUrl: '../pages/list.html', controller: 'UserListCtrl'}).
when('/user-details/:login', {templateUrl: '../pages/form.html', controller: 'UserCtrl' /* and here I need to call userDetails(login) from UserCtrl */}).
otherwise({redirectTo: '/users'});;
}
]);
app.controller('UserCtrl', function ($scope, $http, $location) {
$scope.userDetails = function (login) {
$http.get(url + login).success(function (data) {
$scope.user = data[0];
console.log('tst');
}).error(errorCallback);
};
$scope.createUser = function (user) {
$http.post(url, user).success(function (data) {
$location.path('/users');
}).error(errorCallback);
};
});
My problem is: I don't know how to call specific method of controller when routing matches. I need to call method and give to it parameter :login from routing. How to solve this?
Thanks for your answers
If I understand correctly, you are re-using the same controller for two parts of the view (or for two views), one for creating a user and one for fetching the details of the current user.
Since these two aspects are totally different, it is not advisable to use the same controller for both. The controllers should be different and any common or re-usable functionality should be shared through a service.
In any case, code that makes calls to the backend should not be placed inside controllers, but into services. E.g.:
app.service('UserSrv', function ($http) {
var url = '...';
this.userDetails = function (login) {
return $http.get(url + login);
};
this.createUser = function (user) {
return $http.post(url, user);
};
});
app.controller('UserCtrl', function ($scope, UserSrv) {
var login = '...';
var errorCallback = ...;
// Fetch user details upon initialiation
UserSrv.userDetails(login).success(function (data) {
$scope.user = data[0];
}).error(errorCallback);
});
app.controller('NewUserCtrl', function ($location, $scope, UserSrv) {
var errorCallback = ...;
$scope.createUser = function (user) {
UserSrv.createUser(user).success(function (data) {
$location.path('/users');
}).error(errorCallback);
};
});
You could, also, use $routeProvider's resolve property to "preload" the user's details and pass it to the UserCtrl as an argument.
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 :)