Calling factory from directives controller in Angular.js - javascript

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;
}
}
}
});

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;}]);
}

color of the knob cannot be updated after server data request

After returning data from server request, the color of the knob cannot be updated as like as given image link screencast . My code is given below:
JavaScript Code
$scope.options = { /* knob option */ };
$http
.get(url)
.then(function(res) {
$scope.details = res.data.rating // need to show $scope.details in knob
}, function(err) {});
html code
<ui-knob value="details" options="options "></ui-knob>
NB: I'm using ng-knob
I solve this problem by using the following code :
angular.module('', [])
.controller('DemoCtrl', function($scope, $timeout) {
$scope.options = { /* knob option */ };
$scope.details = 0; // value initialize
$http
.get(url)
.then(function(res) {
$timeout(function() {
$scope.details = res.data.rating // load data from server
}, 1000);
}, function(err) {});
});
//1. your code is async
//2. you need use 1. promise or 2. resolve in your router or 3. $scope.apply() after get response in your controller
//Prime 1 (Promise):
//code in Controller
var vm = this;
vm.asyncGreet = function () {
var deferred = $q.defer();
$http({
method: 'post',
data: $httpParamSerializerJQLike({
//***your-send-data***
}),
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: ''//***your-url***
}).
success(function (data, status) {
deferred.resolve('true');
});
return deferred.promise;
};
var promise = vm.asyncGreet();
promise.then(function (greeting) {
//alert('Success: ' + greeting);
//YOUR CODE AFTER SERVER REQUEST
$scope.details = res.data.rating;
}, function (reason) {
//alert('Failed: ' + reason);
}, function (update) {
//alert('Got notification: ' + update);
});
//Prime 2 (Resolve in your Route)
(function (angular) {
'use strict';
// route-config.js
angular
.module('app')
.config(config);
config.$inject = ['$routeProvider'];
function config($routeProvider) {
console.log('routeConfig');
$routeProvider
.when('/requests', {
templateUrl: '/tpl.html',
controller: 'requestController',
controllerAs: 'vm',
//(Promise) IS REQUEST TO SERVER, AFTER START requestController
resolve: {
requestPrepService: requestPrepService
}
});
}
requestPrepService.$inject = ['requestService'];
function requestPrepService(requestService) {
//This $http response
return requestService.getRequests();
}
})(window.angular);
//in Controller
.$inject = ['requestPrepService'];
vm.request = {
data: requestPrepService.data,
}
//Addition
1. If you use promise do not forget $inject = ['$q']
2. Please, read https://docs.angularjs.org/api/ng/directive/ngCloak
(
how use:
<div ng-controller="yourController" ng-cloak></div>
)

How to set directive dynamically by data from $scope in angular-ui-grid

Sorry my english is poor ... Don't laugh, please...
In compile, I can't use $scope.
When I set directive (For example, 'ui-grid-selection') by hard code, It works perfectlly like enter image description here
In link, when I set attribute 'ui-grid-selection' only, it doesn't work.
When I set attr and write $compile($element.find('.mygrid'))($scope), it works but only the function is correct, it's layout became like this and the console log shows:
Error: [ngTransclude:orphan] http://errors.angularjs.org/1.3.20/ngTransclude/orphan?p0=%3Cdiv%20ng-transclude%3D%22%22%3E
at Error (native)
at http://localhost:8000/bower_components/angular/angular.min.js:6:417
at Ia.link (http://localhost:8000/bower_components/angular/angular.min.js:239:272)
at Z (http://localhost:8000/bower_components/angular/angular.min.js:70:149)
at I (http://localhost:8000/bower_components/angular/angular.min.js:59:255)
at g (http://localhost:8000/bower_components/angular/angular.min.js:51:335)
at g (http://localhost:8000/bower_components/angular/angular.min.js:51:352)
at http://localhost:8000/bower_components/angular/angular.min.js:50:444
at http://localhost:8000/bower_components/angular/angular.min.js:52:322
at h (http://localhost:8000/bower_components/angular/angular.min.js:56:322) <div ng-transclude="">
Error: [$compile:ctreq] http://errors.angularjs.org/1.3.20/$compile/ctreq?p0=uiGrid&p1=uiGridHeaderCell
at Error (native)
at http://localhost:8000/bower_components/angular/angular.min.js:6:417
at M (http://localhost:8000/bower_components/angular/angular.min.js:56:127)
at http://localhost:8000/bower_components/angular/angular.min.js:56:193
at r (http://localhost:8000/bower_components/angular/angular.min.js:7:322)
at M (http://localhost:8000/bower_components/angular/angular.min.js:56:170)
at I (http://localhost:8000/bower_components/angular/angular.min.js:59:104)
at g (http://localhost:8000/bower_components/angular/angular.min.js:51:335)
at http://localhost:8000/bower_components/angular/angular.min.js:50:444
at http://localhost:8000/bower_components/angular/angular.min.js:52:322
Error: [$compile:ctreq] http://errors.angularjs.org/1.3.20/$compile/ctreq?p0=uiGrid&p1=uiGridRow
at Error (native)
at http://localhost:8000/bower_components/angular/angular.min.js:6:417
at M (http://localhost:8000/bower_components/angular/angular.min.js:56:127)
at http://localhost:8000/bower_components/angular/angular.min.js:56:193
at r (http://localhost:8000/bower_components/angular/angular.min.js:7:322)
at M (http://localhost:8000/bower_components/angular/angular.min.js:56:170)
at I (http://localhost:8000/bower_components/angular/angular.min.js:59:104)
at g (http://localhost:8000/bower_components/angular/angular.min.js:51:335)
at I (http://localhost:8000/bower_components/angular/angular.min.js:59:199)
at g (http://localhost:8000/bower_components/angular/angular.min.js:51:335)
Error: [$compile:ctreq] http://errors.angularjs.org/1.3.20/$compile/ctreq?p0=uiGrid&p1=uiGridRow
at Error (native)
at http://localhost:8000/bower_components/angular/angular.min.js:6:417
at M (http://localhost:8000/bower_components/angular/angular.min.js:56:127)
at http://localhost:8000/bower_components/angular/angular.min.js:56:193
at r (http://localhost:8000/bower_components/angular/angular.min.js:7:322)
at M (http://localhost:8000/bower_components/angular/angular.min.js:56:170)
at I (http://localhost:8000/bower_components/angular/angular.min.js:59:104)
at g (http://localhost:8000/bower_components/angular/angular.min.js:51:335)
at I (http://localhost:8000/bower_components/angular/angular.min.js:59:199)
at g (http://localhost:8000/bower_components/angular/angular.min.js:51:335)
I don't know how to fix it.Sad me, Help please ...
Here my controller's code:
'use strict';
app.controller('mainCtrl',
['$scope', '$q', '$http', 'uiGridTreeViewConstants', function ($scope, $q, $http, uiGridTreeViewConstants) {
$scope.gridOptions1 = {
onRegisterApi: function( gridApi ) {
$scope.grid1Api = gridApi;
}
};
$http.get('demo/data/uigrid_100.json').success(function(data) {
$scope.gridOptions1 = data.gridOptions;
$scope.gridEnable1 = data.gridEnable;
$scope.gridOptions1.data = data.gridData;
});
}]);
app.directive('jsonUiGrid', ['$compile', function($compile) {
return {
restrict: 'E',
template:
'<div>' +
'<div ui-grid="options" class="mygrid"></div>' +
'</div>'
,
replace: true,
transclude: true,
scope: {
options: '=?',
enablesData: '=enables'
},
link: function($scope, $element, attrs){
$scope.$watch('enablesData', function(newValue) {
if (typeof(newValue) != 'undefined'){
if(newValue && newValue.length){
angular.forEach(newValue, function(attr){
$element.find('.mygrid').attr(attr, '');
});
$compile($element.find('.mygrid'))($scope);
}
}
});
}
}
}])
Tried get data by using $http before run mainCtrl, And Inject into mainCtrl. It works!!
The detail is. I'm using a template named "Clip-Two_130", it contains a function in "config.router.js" which is named "loadSequence".
function loadSequence() {
var _args = arguments;
return {
deps: ['$ocLazyLoad', '$q',
function ($ocLL, $q) {
var promise = $q.when(1);
for (var i = 0, len = _args.length; i < len; i++) {
promise = promiseThen(_args[i]);
}
return promise;
function promiseThen(_arg) {
if (typeof _arg == 'function')
return promise.then(_arg);
else
return promise.then(function () {
var nowLoad = requiredData(_arg);
if (!nowLoad)
return $.error('Route resolve: Bad resource name [' + _arg + ']');
return $ocLL.load(nowLoad);
});
}
function requiredData(name) {
if (jsRequires.modules)
for (var m in jsRequires.modules)
if (jsRequires.modules[m].name && jsRequires.modules[m].name === name)
return jsRequires.modules[m];
return jsRequires.scripts && jsRequires.scripts[name];
}
}]
};
}
And I set router like:
.state('app.demo_ui-grid2', {
url: "/demo_ui-grid2",
templateUrl: "demo/views/demo_ui-grid2.html",
//resolve: loadSequence('ui.grid', 'ui.grid.selection', 'demoUiGridCtrl2'),
resolve: {
deps: loadSequence('ui.grid', 'ui.grid.selection', 'demoUiGridCtrl2').deps,
options: function($q, $http){
var deferred = $q.defer();
$http.get('demo/data/uigrid_options.json').then(function(data) {
deferred.resolve(data.data);
});
return deferred.promise;
}
},
controller: 'mainCtrl',
title: 'demo_ui-grid2',
ncyBreadcrumb: {
label: 'demo ui-grid2'
}
})
The controller file has been modified to :
'use strict';
app.controller('mainCtrl',
['$scope', '$q', '$http', 'options', 'uiGridConstants', 'uiGridData',
function ($scope, $q, $http, options, uiGridConstants, uiGridData) {
// Bind grid enable
$scope.gridEnable1 = options.gridEnable;
// Bind grid options
$scope.gridOptions1 = options.gridOptions;
$scope.gridOptions1.onRegisterApi = function(gridApi){
$scope.grid1Api = gridApi;
};
// Bind grid data [NO NECESSARY]
//$scope.gridOptions1.data = data;
$scope.url = [
'demo/data/100.json',
'demo/data/500_complex.json'
];
$scope.changeData = function(url){
var promise = uiGridData.get(url);
promise.then(function(data) {
$scope.gridOptions1.data = data;
}, function(data) {
console.log('changeData ERROR');
});
}
}]);
app.factory('uiGridData', ['$http', '$q', function ($http, $q) {
return {
get: function(url) {
var deferred = $q.defer();
$http({method: 'GET', url: url}).
success(function(data, status, headers, config) {
deferred.resolve(data);
}).
error(function(data, status, headers, config) {
deferred.reject(data);
});
return deferred.promise;
} // end get
};
}]);
app.directive('jsonUiGrid', ['$compile', function($compile) {
return {
restrict: 'E',
template:
'<div>' +
'<div ui-grid="options" class="mygrid"></div>' +
'</div>'
,
replace: true,
transclude: true,
scope: {
options: '=?',
enablesData: '=enables'
},
link: function($scope, $element, attrs){
angular.forEach($scope.enablesData, function(attr){
$element.find('.mygrid').attr(attr, '');
})
$element.html($element.html());
$compile($element.contents())($scope);
}
}
}])
Maybe I can only modify the controller file without modifying in router file?
Wish there's a better solution. Still need help.
The data file you can use:
100.json
500_complex.json

using resolve in angularjs routes

I am working on angularjs app and my config looks like this:
.config(function($stateProvider,$urlRouterProvider, $localStorage){
$stateProvider
.state('Login',{
url:'/login',
templateUrl:'templates/login.html',
controller:'LoginCtrl',
resolve: {
/* if($localStorage.userInfo === null || $localStorage.userInfo === undefined){
}else{
$scope.signInUser();
}*/
}
})
My login.html looks like this:
<form name="loginform"></form>
I want that if $localstorage.userInfo exists, do not show login.html but call $scope.signInUser function else show the form.
How do I do this using resolve of the route? Can I please get some directions?
I have tried easier ways but I ended up with 10 digest cycles reached error so I was adviced to use resolve for the purpose.
My complete route looks like this:
.config(function($stateProvider,$urlRouterProvider, $localStorage){
$stateProvider
.state('Login',{
url:'/login',
templateUrl:'templates/login.html',
controller:'LoginCtrl',
resolve: {
if($localStorage.userInfo === null || $localStorage.userInfo === undefined){
}else{
$scope.signInUser();
}
}
})
.state('Deployment',{
url:'/deployment',
templateUrl:'templates/deployment.html'
})
.state('Bill',{
url:'/bills',
templateUrl:'templates/bills.html'
})
//$urlRouterProvider.otherwise('/login');
$urlRouterProvider.otherwise(function ($injector) {
var $state = $injector.get('$state');
$state.go('Login');
});
How I achieved this
routes.js
app.config(["$routeProvider", "$locationProvider", function($routeProvider, $location) {
$routeProvider.when("/home", angularAMD.route({
templateUrl: "templates/pages/home.html",
controller: "HomeController",
controllerUrl: "app/controllers/home_controller",
resolve: {
weekendTypes: function(WeekendTypes) {
return WeekendTypes.getAll()
}
}
}));
}]);
factory.js
app.factory("WeekendTypes", ["$http", function($http) {
return {
getAll: function() {
var _apiurl = config_data.GENERAL_CONFIG.AJAX_URL + "weekend/getAll",
promise = $http({
method: "GET",
url: _apiurl
}).success(function(data, status, headers, config) {
return data
});
return promise
}
}
}])
You should use something like this
getData: function(){
var deferred = $q.defer();
$timeout(function(){
var data=localStorageService.get('description'),
deferred.resolve(data);
},3000);
return deferred.promise;
}
Had to try it by myself before sharing code.
Remove the resolve function from set local storage value as data like below
state('Login',{
url:'/login',
templateUrl:'templates/login.html',
controller:'LoginCtrl',
data : {userIfno : $localStorage.userInfo}
})
Then make use of .run function like
.run($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function(toState) {
if (toState.data.userIfno === '') {
$state.go('Login', {}); //here set proper state
}
});
}
Hope this helps you.

How do I obtain $stateParams in Angular service

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

Categories