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