How do I obtain $stateParams in Angular service - javascript

Here is my state definition:
.state('sub-topic',{
url:"/topics/:topicId",
templateUrl: "templates/sub-topics.html",
controller: "SubTopicsController"
})
Here is my service
myApp.service('subTopicsService',function($http, $stateParams){
this.getSubTopics = function(){
$http.get('topics/' + $stateParams.topicId + '.json').success(function(data, status, header, config) {
return data;
});
}
})
A part of my controller, that has 'subTopicService' injected
$scope.topicList = subTopicsService.getSubTopics();
The problem is, the $stateParams is undefined in the service.
Specifically I get this error message: Cannot access property :topicId of undefined.
How do I use $stateParams in my service?

This scenario should work. There is a working plunker. Changes I made:
I just restructred the service definition:
myApp.service('subTopicsService', function($http, $stateParams) {
var getSubTopics = function() {
$http.get('topics/' + $stateParams.topicId + '.json ')
.success(function(data, status, header, config) {
return data;
});
};
// to prove, that this service can work with $stateParams
var getStateParams = function() {
return $stateParams;
};
return {
getSubTopics: getSubTopics,
getStateParams: getStateParams,
};
});
Here we get the service injected into controller:
myApp.controller('SubTopicsController', function($scope, $state, subTopicsService) {
$scope.stateParams = subTopicsService.getStateParams();
});
And here is our view, consuming that all:
$stateProvider
.state('sub-topic', {
url: "/topics/:topicId",
//templateUrl: "templates/sub-topics.html",
template: '<div><pre>{{stateParams}}</pre></div>',
controller: "SubTopicsController",
});
See the working plunker for more detauls

Related

How to correctly pass data from Service to Controller

I am trying to send data from my http service to my controller. The service correctly gets the data but it doesn't get sent to the controller.
Now, I am aware that the query is done asynchronously which is why I am trying to use $q.defer.
I tried following the example provided by a similar question : AngularJS $http call in a Service, return resolved data, not promises , however it still doesn't work.
Here is my Service :
.service("builds", ['$http', '$q', function($http, $q) {
var deferred = $q.defer();
$http({
method:'GET',
url: '/builds',
cache : true
}).success(function(data) {
deferred.resolve(data);
}).error(function(msg){
deferred.reject(msg);
});
console.log(deferred.promise);
return deferred.promise;}]);
And here is my routeProvider
$routeProvider.
when('/builds', {
controller: ['$scope', 'buildsData', function ($scope, buildsData) {
console.log("In routeprovider:" + buildsData);
$scope.allBuilds = buildsData;
}],
template: '<build-list></build-list>',
resolve: {
buildsData: ['builds', function(builds){
return builds;
}]
}
})
And finally here is a snippet of my Controller :
var app = angular.
module('buildList').
component('buildList', {
templateUrl: 'build-list/build-list.template.html',
controller: function BuildListController($scope, $window,$location,$cookies, builds) {
console.log($scope.allBuilds);
$scope.league = $scope.allBuilds;
As #vishal says
You should create a method in service because generally a service may have many get and set methods ( I mean best practice).
create a function say getData
function getData()
{
$http({
method:'GET',
url: '/builds',
cache : true
})
}
then you should be calling this method in controller
In the controller you should inject this service and then
builds.getData().then(function(s){
//result
},function(e){
//error
}
);
you shouldntt have
controller: ['$scope', 'buildsData', function ($scope, buildsData) {
console.log("In routeprovider:" + buildsData);
$scope.allBuilds = buildsData;
}],
and a controller in an other file:
You can directly do
when('/builds', {
controller: 'BuildListController'
template: '<build-list></build-list>',
resolve: {
buildsData: ['builds', function(builds){
return builds;
}]
}
})
and then in your controller
$scope.allBuilds = buildsData;
Beside, if you want add some functions to it , your service should look,like this:
.service("builds", ['$http', '$q', function($http, $q) {
var deferred = $q.defer();
getbuilds: function(){
$http({
method:'GET',
url: '/builds',
cache : true
}).success(function(data) {
deferred.resolve(data);
}).error(function(msg){
deferred.reject(msg);
});
console.log(deferred.promise);
return deferred.promise;}]);
}

Angular ui-route with JSON Data Request

I want to build a Single Page Website, where my data is stored in a CMS. This CMS accepts Ajax Requests to serve me JSON. This JSON I want to output in my ng-app using the ui-router (I also tried the ngRoute before, with same results).
The Problem is: I need no template. Cause all my data I need comes from the JSON Request. But using no template or templateUrl doesn't affects the controller.
The question is how to output my received data in the HTML? I cant use ng-controller because it binds on only this specific controller. Console.log shows that my data is successfully received, but I found no way to get an output.
app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$urlRouterProvider.otherwise("/");
$stateProvider
.state('state1', {
url: '/state1',
template: '<h1>This Is A State</h1>',
controller: function($scope, $http) {
$scope.pageObj = '';
$scope.pageObj.url = '/angular/demo/';
$scope.pageObj.class = 'page-my';
$scope.pageObj.data = 'Empty';
$http
.get('/angular/demo/')
.then(function(result) {
console.log("Data Received");
console.log(result.data);
$scope.pageObj.data = result.data;
});
//console.log(result.data);
console.log("Hello state");
}
});
});
I found a small solution with using factory. The question is still, how do I access my data? Data now is stored by an own controller i guess. I post my updated code below:
var app = angular.module('myApp', ['ngSanitize', 'ngRoute', 'ui.router']).factory("dataService", function($http) {
var data = "";
var getData = function() {
return data;
}
var setData = function(newData) {
data = newData;
}
return {
getData: getData,
setData: setData
};
});
app.controller('FactoryCtrl', ['$scope', '$http', 'dataService', function($scope, $http, dataService) {
$scope.mydata = dataService.getData();
console.log($scope.mydata);
}]);
app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$urlRouterProvider.otherwise("/");
$stateProvider
.state('state1', {
url: '/state1',
template: '<h1>{{pageObj.data}}</h1>',
controller: function($scope, $http, dataService) {
$scope.pageObj = '';
$scope.pageObj.url = '/angular/demo/';
$scope.pageObj.class = 'page-my';
$scope.pageObj.data = 'Empty';
$http
.get('/angular/demo/')
.then(function(result) {
console.log("Data Received");
$scope.pageObj.data = result.data;
//$scope.model.data = dataService.getData();
dataService.setData("a string");
//console.log(dataService.getData());
});
console.log("Hello state");
}
});
});

$routeParams undefined when passing to new view & controller

Fairly new to AngularJS and WebAPI here, and figure the best way to learn is by doing. Apologies in advance if this question seems simple - I've spent a day flipping through StackOverflow and tried them all.
I currently have a separate Master & Detail view, both with their own controller. I am trying to pass the selected ID through to the Details controller so I can query my database using the ID, though am getting "undefined" on my $routeParams. I'm unsure if I am missing something simple, or whether I'm even approaching this correctly.
The controller doesn't seem to like it when I inject '$routeParams' either.
My app.js module:
var app = angular.module("ProjectDashboardModule", ["ngRoute"]);
app.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider
.when("/", { templateUrl: "/Home/Index" })
.when("/Project", { templateUrl: '/Project/Index', controller: 'ProjectCrudController' })
.when("/Project/project/:id", {templateUrl:'/Project/project', controller: 'ProjectTaskController' });
$routeProvider.otherwise({redirectTo: '/home' });
$locationProvider.html5Mode(true);
}]);
my Factory.js:
app.factory('projectFactory', ['$http', function ($http) {
var urlBase = '/api/Projects/';
var projectFactory = {};
projectFactory.getProjects = function () {
return $http.get(urlBase);
};
projectFactory.getSingleProject = function (id) {
return $http.get(urlBase + '/' + id);
};
return projectFactory;
}]);
my ProjectTaskController.js:
app.controller('ProjectTaskController', ['$scope', "$routeParams", 'projectFactory', function ($scope, $routeParams, projectFactory) {
alert($routeParams.id)
$scope.project;
$scope.message;
getProjectById($routeParams.id);
function getProjectById(id) {
projectFactory.getSingleProject(id)
.success(function (data) {
$scope.project = data;
})
.error(function (error) {
$scope.message = 'error retrieving project ' + error.message;
});
}
}]);
I found that my problem was that all my angular script references were scattered. I moved all my custom script references (controller, factory, module) to index.cshtml and fixed the issue.

Router resolve will not inject into controller

I have tried everything to get ui-router's resolve to pass it's value to the given controller–AppCtrl. I am using dependency injection with $inject, and that seems to cause the issues. What am I missing?
Routing
$stateProvider.state('app.index', {
url: '/me',
templateUrl: '/includes/app/me.jade',
controller: 'AppCtrl',
controllerAs: 'vm',
resolve: {
auser: ['User', function(User) {
return User.getUser().then(function(user) {
return user;
});
}],
}
});
Controller
appControllers.controller('AppCtrl', AppCtrl);
AppCtrl.$inject = ['$scope', '$rootScope'];
function AppCtrl($scope, $rootScope, auser) {
var vm = this;
console.log(auser); // undefined
...
}
Edit
Here's a plunk http://plnkr.co/edit/PoCiEnh64hR4XM24aH33?p=preview
When you use route resolve argument as dependency injection in the controller bound to the route, you cannot use that controller with ng-controller directive because the service provider with the name aname does not exist. It is a dynamic dependency that is injected by the router when it instantiates the controller to be bound in its respective partial view.
Also remember to return $timeout in your example, because it returns a promise otherwise your argument will get resolved with no value, same is the case if you are using $http or another service that returns a promise.
i.e
resolve: {
auser: ['$timeout', function($timeout) {
return $timeout(function() {
return {name:'me'}
}, 1000);
}],
In the controller inject the resolve dependency.
appControllers.controller('AppCtrl', AppCtrl);
AppCtrl.$inject = ['$scope', '$rootScope','auser']; //Inject auser here
function AppCtrl($scope, $rootScope, auser) {
var vm = this;
vm.user = auser;
}
in the view instead of ng-controller, use ui-view directive:
<div ui-view></div>
Demo
Here is how I work with resolve. It should receive promise. So I create service accordingly.
app.factory('User', function($http){
var user = {};
return {
resolve: function() {
return $http.get('api/user/1').success(function(data){
user = data;
});
},
get: function() {
return user;
}
}
});
This is main idea. You can also do something like this with $q
app.factory('User', function($q, $http){
var user = {};
var defer = $q.defer();
$http.get('api/user/1').success(function(data){
user = data;
defer.resolve();
}).error(function(){
defer.reject();
});
return {
resolve: function() {
return defer.promise;
},
get: function() {
return user;
}
}
});
These are almost identical in action. The difference is that in first case, service will start fetching date when you call resolve() method of service and in second example it will start fetch when factory object is created.
Now in your state.
$stateProvider.state('app.index', {
url: '/me',
templateUrl: '/includes/app/me.jade',
controller: function ($scope, $rootScope, User) {
$scope.user = User.get();
console.log($scope.user);
},
controllerAs: 'vm',
resolve: {
auser: function(User) {
return User.resolve()
}
}
});

Calling factory from directives controller in Angular.js

I am trying to learn Angular.js, I am using ng-boiler-plate to manage my test application.
However I have ran into a ptoblem and can't see the reason for it not working. Basically I am trying to inject a Factory and then call it from a directives controller.
However when I try to call it I get an error reporting the factory name (in this case dashboardFac) is undefined.
I will include the directive and factory below:
Directive:
angular.module( 'locationSelector', [
'ngBoilerplate.locationFactory'
] )
.directive( 'locationSelector', function() {
return {
restrict: 'A',
//template: '<h3>asdfasdfasd</h3>',
templateUrl : 'components/locationSelector/locationSelector.tpl.html',
link: function( scope, element, attrs ) {
console.log("link working ");
var $input = angular.element( document.querySelector( '#location' ) );
$input.bind('focus', function() {
console.log("stay focused son");
});
},
controller: function($scope, dashboardFac, $element){
$scope.locyTexy = "";
$scope.api = dashboardFac;
console.log($scope.api);
$scope.change = function() {
console.log("asdfasd");
dashboardFac.assets.getLocations().then(function(result){
});
};
}
};
})
;
Factory:
angular.module( 'ngBoilerplate.locationFactory', [
]).factory('dashboardFac', function($http, $q){
this.assets = {
getLocations: function(args) {
var deferred = $q.defer();
var parmUrl = "will be some url eventually";
$http.jsonp({
method: 'GET',
url: parmUrl
}).
success(function(data, status) {
deferred.resolve(data);
}).
error(function(data, status) {
deferred.reject(data);
});
return deferred.promise;
}
};
});
Any help would be greatly apprieacted, I have a feeling I am missing something fundamental but hopefully someone can help point me in the right direction.
Thanks in advance.
You must inject dashboardFac factory to directive:
.directive( 'locationSelector', function(dashboardFac) {
[…]
})
You will have to first inject the factory into your directive, as pointed out by Krzysztof Safjanowski
.directive( 'locationSelector', function(dashboardFac) {
[…]
})
Then your factory will have to return an Object, like every other factory:
angular.module( 'ngBoilerplate.locationFactory', [])
.factory('dashboardFac', function($http, $q){
return {
assets: {
getLocations: function (args) {
var deferred = $q.defer();
var parmUrl = "will be some url eventually";
$http.jsonp({
method: 'GET',
url: parmUrl
}).
success(function (data, status) {
deferred.resolve(data);
}).
error(function (data, status) {
deferred.reject(data);
});
return deferred.promise;
}
}
}
});

Categories