AngularJS Store $routeParam in var in factory service - javascript

I'm new to Angular and i'm currently trying to get the id of a project from the url and pass it as a var inside a service.
My current code is as follows:
app.config(
['$routeProvider',
function($routeProvider) {
...
$routeProvider.when('/project/:ProjectId', {
templateUrl: 'project.html',
controller: 'ProjectController',
activePage: 'Portfolio'
});
...
}
])
...
.controller('ProjectController', function($scope, ProjectFactory) {
$scope.content = ProjectFactory.async();
})
...
.factory('ProjectFactory', function($http) {
var factoryProject = {
async: function(page) {
var projectID = 'XXXXXX';
var apiKey = 'XXXXXX';
var url = 'http://behance.net/v2/projects/' + projectId + '?api_key=' +
apiKey + '&callback=JSON_CALLBACK';
var promise = $http.jsonp(url).error(function(response, status) {
alert(status);
}).success(function(response, status) {
console.log(response.project);
}).then(function(response, status) {
return response.data;
});
return promise;
}
};
return factoryProject;
});
I know i'm missing something, how can i store :ProjectId, from $routeProvider, in the variable projectID?
Thanks!

A couple things missing here to get this to work. The first is in your 'ProjectController', you need to inject the $routeParams variable making the controller definition
.controller('ProjectController', function($scope, ProjectFactory, $routeParams) {
$scope.content = ProjectFactory.async();
})
Now you can access ProjectId in the $routeParams object
var pid = $routeParams.ProjectId
Now you can pass the pid as a param into the factory
ProjectFactory.async(pid)
I haven't tested this yet, but I think that's all you're missing.

You need to inject the $routParams service into your factory and access it like so:
var projectId = $routeParams.ProjectId;

Inject $routeParams object to the controller, and use $routeParams.ProjectId
More info here: https://docs.angularjs.org/api/ngRoute/service/$route

Related

Call function from one controller in another in angularjs

I currently have 2 javascript controllers: selectAll and listAllDomains.
I'm trying to call the method getBeanName (defined in listAllDomains) in the controller selectAll under:
response = $http.post('/invoke/selectAll/', INSERT_CALL_HERE);
As a note, the object returned by the method getBeanName will be passed as an argument to the $http.post() method and handled by a Java controller.
app.controller('listAllDomains', ['$http', '$scope', '$rootScope', function ($http, $scope, $rootScope) {
$scope.showSpinner = true;
$scope.showBtn = false;
let dataObj;
$http.get('domains/').then(function (response) {
$scope.showSpinner = false;
$scope.domains = response.data;
});
$scope.showButton = function(eleStatus) {
let eleSize = Object.keys(eleStatus).length;
return !eleSize;
};
$scope.getBeanName = function (objectType, objectName) {
dataObj = {
type : objectType,
name : objectName,
methodName : "select",
methodParameters : ["true"]
};
localStorage.setItem("dataObj", dataObj);
console.log(dataObj);
$rootScope.$emit("invokeSelectAll", dataObj);
return dataObj;
}
}]);
app.controller('selectAll', ['$http', '$scope' , '$rootScope',
function ($http, $scope, $rootScope) {
var response;
$rootScope.$on("invokeSelectAll", function(){
$scope.invokeSelectAll();
});
$scope.invokeSelectAll = function(){
console.log(localStorage.getItem("dataObj"));
response = $http.post('/invoke/selectAll/', INSERT_CALL_HERE);
response.success(function(data, status, headers, config) {
$scope.responses = data ? data : "Select Operation not supported on this bean";
});
}
}]);
Any help would be much appreciated! Thank you!
You can either create a service and inject it in both controllers or just define your function in $rootScope and then use it in any controller.
Check this issue for reference: How to use $rootScope in AngularJS
first create a service/factory with required function. And inject into the controller.

How to pass form data to another page?

im using angularJS v 1.5.6 and want to know how to pass my form data correctly with $location.path.
Here is my code Page A:
<form>
...
<button type="submit" ng-click="submit(formData)">submit</button>
</form>
JS:
app.config(['$routeProvider', function ($routeProvider) {$routeProvider
// Home
.when("/", {
templateUrl: "A.html",
controller: "ACtrl"
})
.when("/B/", {
templateUrl: "B.html",
controller: "BCtrl"
})
//fallback url if nothing matches
.otherwise({
redirectTo: '/'
});
}]);
app.controller('ACtrl', function ( $scope, $location, $http) {
$scope.formData = {};
$scope.submit = function() {
$location.path("/B/" + $scope.formData );
};
});
//controller for B page
app.controller('BCtrl', ['$scope', '$routeParams',
function($scope,$routeParams) {
$scope.formData = $routeParams.formData;
}]);
it is a pretty simple example, but i cant figure out how to solve it :(
By clicking the submit nothing happens. If i remove the $scope from $scope.formData i get a error like: Error: formData is not defined.
The terms in formdata are available, i tested it with console.log($scope.formData) and everything is ok.
here is the link plunker: https://plnkr.co/edit/K5zwcmRRyom5HR4a5Q9o
EDIT
the only issue is now, how to handle the select object correctly in the foreach loop. Need help please
You can do it by creating a service and using setter/getter in order to transfer a variable.
For example like this: https://plnkr.co/edit/IuTXsVLU7dq3TylfnSYP?p=preview
app.service('TransferService', [function(){
var savedData,
service = {
getData: getData,
setData: setData
}
function getData(){
return savedData
}
function setData(data){
savedData = data
}
return service
}])
Don't use location.path...
You could either use a service or use localstorage (or some other browser storage mechanism [sessionStorage, indexdb].
Service Method Below
app.service("SomeService", function () {
var value = null;
this.set = function (val) {
value = val;
return this;
}
this.get = function () {
return value;
}
})
app.controller("ACtrl", function ($scope, SomeService) {
$scope.formData = {};
$scope.submit = function() {
//Assuming you've populated it with some data...
SomeService.set($scope.formData);
$location.path("/B/");
};
})
app.controller("BCtrl", function ($scope, SomeService) {
$scope.formData;
(function () {
//Check that the data is present in the SomeService service.
var dataFromACtrl = SomeService.get();
if (dataFromACtrl) {
$scope.formData = dataFromACtrl;
}
})();
})
Using localStrorage below, could be sessionStorage.
app.controller("ACtrl", function ($scope, SomeService) {
$scope.formData = {};
$scope.submit = function() {
//Assuming you've populated it with some data...
window.localStorage.setItem("form_data", JSON.stringify($scope.form_data));
$location.path("/B/");
};
})
app.controller("BCtrl", function ($scope, SomeService) {
$scope.formData;
(function () {
var dataFromACtrl = window.localStorage.getItem("form_data");
if (dataFromACtrl) {
$scope.formData = JSON.parse(dataFromACtrl);
}
})();
})
Note
Using the localStorage example you would need to do some clean-up, after doing whatever you want to do with that data in Bctrl you'd want to clear the entry in localstorage using either of the below lines of code:
window.localStorage.removeItem("form_data");
delete window.localStorage["form_data"];

AngularJS app loading and processing JSON data once for multiple controllers

I'm working on an Angular app, where I'm running into mostly the same problem as in this post:
AngularJS App: Load data from JSON once and use it in several controllers
I've got a factory that reads a JSON file, and returns the whole data object. Each controller, then, uses this factory (as a service?) to obtain the data, but then each controller has to pick it apart on its own. The JSON has to be searched and processed to get the relevant payload like, $scope.currentArray = data.someThing.allItems[i]; etc, and I obviously don't want to repeat this code in all the controllers.
Seems to me I can either find some way to share the data, after, say, MainController (the "first one") has finished working it, or I can add some new module "between" the controllers and the factory. This new module -- let's call it myProcessService? -- would then be the one getting the data object from the factory, and do all the processing there... once and for all. Then, each controller would only deal with myProcessService to (somehow) get the ready-formatted variables and arrays etc onto their respective scopes (yes, this is Angular 1).
If I try to give an example of how I'm doing this so far, maybe someone can help me with the necessary improvements? And, I am aware that it is a good idea to begin using the Angular 2 patterns already today, but please understand that I am first trying to get some grasp of how A1 works, before delving into A2 :)
var app = angular.module('myApp', ['ngRoute']);
app.factory('getDataFile', ['$http', function($http) {
function getStream(pid) {
return $http.get("data/" + pid + ".json")
.success(function(data) {
console.info("Found data for pid " + pid);
return data;
})
.error(function(err) {
console.error("Cant find data for pid " + pid);
return err;
});
}
return {getStream: getStream};
}]);
app.controller('MainController', ['$scope', 'getDataFile',
function($scope, getDataFile) {
getDataFile.getStream('10101011').success(function(data) {
// process "data" into what's relevant:
var i = getRelevantIndexForToday(new Date());
$scope.myVar = data.someField;
$scope.currentArray = data.someThing.allItems[i];
// etc... you get the drift
}
}]);
app.controller('SecondController', ['$scope', 'getDataFile',
function($scope, getDataFile) {
getDataFile.getStream('10101011').success(function(data) {
// process "data" into what's relevant:
var i = getRelevantIndexForToday(new Date());
$scope.myVar = data.someField;
$scope.currentArray = data.someThing.allItems[i];
// etc... you get the drift
}
}]);
Edit:
My ngRouter is set up something like this. They fill the ng-view div in my index.html. However -- and maybe this is frowned upon? -- I've also got a "MainController" which sits directly in the index.html body tag, such that I can show some data (from the back end) in the header part of the single page application.
app.config(function($routeProvider) {
$routeProvider
.when('/:id/work/:page_id', {
controller: 'AssetController',
templateUrl: 'app/views/work.html'
})
.when('/:id/work/', {
redirectTo: '/:id/work/1'
})
.when('/:id/', {
controller: 'DashController',
templateUrl: 'app/views/dashboard.html'
})
.otherwise({
redirectTo: '/'
});
});
and index.html is a lot like this:
<body ng-app="myApp">
<div class="container" ng-controller="MainController">
<h1>Welcome, {{username}}</h1>
<div ng-view></div>
</div>
</body>
You can add another helper function in your factory, that returns the required object that you want to share between controllers.
app.factory('getDataFile', ['$http', function($http) {
function getStream(pid) {
return $http.get("data/" + pid + ".json")
.success(function(data) {
console.info("Found data for pid " + pid);
return data;
})
.error(function(err) {
console.error("Cant find data for pid " + pid);
return err;
});
}
function getCurrent(pid) {
return getStream(pid).then(function() {
var i = getRelevantIndexForToday(new Date());
return {
myVar: data.someField,
currentArray: data.someThing.allItems[i];
};
});
}
return {
getStream: getStream,
getCurrent: getCurrent
};
}]);
app.controller('MainController', ['$scope', 'getDataFile',
function($scope, getDataFile) {
getDataFile.getCurrent('10101011').success(function(data) {
$scope.myVar = data.myVar;
$scope.currentArray = data.currentArray;
// etc... you get the drift
}
}]);
app.controller('SecondController', ['$scope', 'current',
function($scope, current) {
.success(function(data) {
$scope.myVar = data.myVar;
$scope.currentArray = data.currentArray;
}
}]);
Suggestion:
Also I suggest you to use resolve which allows you to pass data to your controller from your route.
Route:
.when('/:id/work', {
controller: 'AssetController',
templateUrl: 'app/views/work.html',
resolve: {
// you are injecting current variable in the controller with the data. You can inject this to each of your controller. you dont need to add the whole function in your next route. Just use current
current: function(getDataFile){
return getDataFile.getCurrent('10101011');
}
})
Controller:
app.controller('MainController', ['$scope', 'current',
function($scope, current) {
$scope.myVar = current.myVar;
$scope.currentArray = current.currentArray;
}]);
app.controller('SecondController', ['$scope', 'current',
function($scope, current) {
$scope.myVar = current.myVar;
$scope.currentArray = current.currentArray;
}]);
Now that you have
Thanks for giving an answer in line with my use of deprecated methods success and error, Subash. However, I had some problems with the code in your answer, and I got some help on #angularjs, so I thought I should post the updated code here.
var myApp = angular.module('myApp',[]);
myApp.factory('getDataFile', ['$http', function($http) {
function getStream(pid) {
// here, using placeholder data URL, just to get some data:
return $http.get('http://jsonplaceholder.typicode.com/users')
.then(function(result) {
console.info("Found data for pid " + pid);
return result.data;
})
.catch(function(err) {
console.error("Cant find data for pid " + pid);
return err;
});
}
function getCurrent(pid) {
return getStream(pid).then(function(data) {
var i = 1; // test
console.log("myVar = ", data[i].name);
return {
myVar: data[i].name
};
});
}
return {
getStream: getStream,
getCurrent: getCurrent
};
}]);
myApp.controller('MainController', ['$scope', 'getDataFile',
function($scope, getDataFile) {
$scope.name = "j";
getDataFile.getCurrent('10101011').then(function(user) {
$scope.myVar = user.myVar;
console.log("controller. myVar = ", user);
// etc... you get the drift
});
}]);

Passing params to an angular service from a controller?

I'm an angular newby. I'm hoping to pass params to a service that fetches data form a server depending on those params.
for example, if I want to pass a book name string and then use it in the service to concatenate with the request url. The documentation does not show clearly in this subject and I could not find helpful examples in other resources.
Let say, this is the controller:
app.controller('BookController', ['$scope', '$routeParams', 'books', function($scope, $routeParams, books) {
// sending params to books service before a successful return
books.success(function(data) {
$scope.book = data[$routeParams.bookId];
});
and this is the service
app.factory('books', ['$http', function($http) {
// var url = 'http://...' + ParamFromController + '.json'
return $http.get(url)
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
So, how can I send params to 'books' service and then use it in the service?
Thanks a lot in advance.
You can declare your service as:
app.factory('books', ['$http', function($http) {
// var url = 'http://...' + ParamFromController + '.json'
return {
getVal: function(url,options){
return $http.get(url,options)
}
}
}]);
and use it in your controller and provide appropriate params to pass into 'books' service:
app.controller('BookController', ['$scope', '$routeParams', 'books', function($scope, $routeParams, books) {
// sending params to books service before a successful return
books.getVal('api/activity.json',{'name':'abc'}).success(function(data) {
$scope.book = data[$routeParams.bookId];
});
Also, dont use the .success() callback both in your service and controller function. The books service is returning a promise($http returns a promise implicitly) and you can handle that in controller.
Right now you are returning the promise / result of the $http as the service instance.
Services are not meant to work this way. You should return an object that holds several properties / methods that define your service:
app.factory('books', ['$http', function($http) {
var instance = {
getBook: function(bookId) {
return $http.get(...);
}
}
return instance;
}
In the controller you can then use the books service as follows:
books
.getBook($routeParams.bookId)
.then(function (result) { ... });
app.factory('books', ['$http', function($http) {
var booksService = {};
booksService.getBook = function(bookId){
{
return $http.get(url, bookId);
};
return booksService;
}]);
and in your controller
app.controller('BookController', ['$scope', '$routeParams', 'books', function($scope, $routeParams, books) {
books.getBook($routeParams.bookId).success(function(data) {
$scope.book = data;
});

AngularJS: Getting back data with specific id

I'm trying to get a specific product by its id from a JSON file with products. I have some kind of problem as this question
AngularJS : get back data from a json array with an id
the code is similar. I read through that question and the accepted answer there, still can't figured this out. From what I understand the $scope.search() returns a promise which after success triggers the .then() to set get the correct person.
This line of code prints out the products array and also getting the product id from the url.
However it prints out twice in the console.
console.log($scope.products + $routeParams.productId);
app.js
var app = angular.module('gtbApp', [
'ngRoute',
'productControllers'
]);
// Setting up the routes with right controllers and partials
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/main', {
templateUrl: 'partials/product-grid.html',
controller: 'ProductController'
})
.when('/product/:productId', {
templateUrl: 'partials/product-detail.html',
controller: 'ProductDetailCtrl'
})
.otherwise({
redirectTo: '/main'
});
}]);
controllers.js
var app = angular.module('productControllers', []);
// For product-grid.html
app.controller('ProductController', ['$http', function($http){
var store = this;
store.products = [];
$http.get('products.json').success(function(data){
store.products = data;
});
}]);
// For product-detail.html
app.controller('ProductDetailCtrl', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http){
$scope.search = function() {
var url = 'products.json';
// Return a promise object
return $http.get(url).success(httpSuccess).error(function(){
console.log('Unable to retrieve info form JSON file.');
});
}
httpSuccess = function(response) {
$scope.products = response;
}
function getById(arr, id) {
for (var i = 0, len = arr.length; i < len; i++) {
if (arr[i].id === id) {
return arr[i];
}
}
}
$scope.search().then(function(){
// Prints out the products array and id twice
console.log($scope.products + $routeParams.productId);
$scope.product = getById($scope.products, $routeParams.productId);
// Prints out twice "undefined"
console.log($scope.product);
});
}]);
The main question is how to get specific product based on id why in "ProductDetailCtrl"
$scope.product = getById($scope.products, $routeParams.productId);
doesn't work.
Thanks in advance!
Update:
Found out why $scope.product is undefined, it is just because the $routeParams.productId is a string, and in getById() need a integer in second args.
However I don't know why console.log($scope.product); prints out twice.
I don't really understand what your main question is here. But anyways. When you use the $http service it will return a promise, which you eventually will have to unwrap. What you are doing in your code is that you are unwrapping it twice. Which is fine.
With $http response you can either use 'success'/'error' or just 'then' which can take a success and an error callback. Which means you could either unwrap in the search function or after you call the search function.
$scope.search = function() {
var url = 'products.json';
$http.get(url)
.success(function(data){
$scope.product = getById($scope.products, $routeParams.productId);
})
.error(function() {
console.log('Unable to retrieve info form JSON file.');
});
}
You could also do something like:
$scope.search = function() {
var url = 'products.json';
return $http.get(url);
}
$scope.search().then(function(data) {
$scope.product = getById(data, $routeParams.productId);
}, errorCallback);
And the below would achieve the same result
$scope.search = function() {
var url = 'products.json';
return $http.get(url);
}
$scope.search()
.success(function(data) {
$scope.product = getById(data, $routeParams.productId);
})
.error(errorCallback);
or reference the promise:
$scope.search = function() {
var url = 'products.json';
return $http.get(url);
}
var dataPromise = $scope.search();
dataPromise.then(function(data) {
$scope.product = getById(data, $routeParams.productId);
}, errorCallback);
What you need to know is that as long as you're returning something within a success/error/then function it will return a promise which you will have to unwrap in order to get the data.
You should be either using the .success() and .error() on the $http-promise or only then .then()
Do it like this:
app.controller('ProductController', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http){
$scope.search = function() {
var url = 'products.json';
// Return a promise object
return $http.get(url);
}
.....
$scope.search()
.success(function(data){ // --> data is the products.json
... // handle the successfull call
} );
.error(function(...) {
... // handle the error
} );
// or:
$scope.search().then(
function(data){ // --> data is the products.json
... // handle the successfull call
},
function(...) {
... // handle the error
});
}]);

Categories

Resources