Passing Service data from module config to Controller from $routeProvider? - angularjs

I am really new to angular and have been reading a number of tutorials etc and have the following problem:
search-module.js
var Search = angular.module('SearchApp',["ngCookies","ngRoute"]);
Search.run(function ($http, $cookies) {
$http.defaults.headers.common['X-CSRFToken'] = $cookies['csrftoken'];
});
Search.config(function($routeProvider){
$routeProvider
.when('/', {
controller:'searchCtrl',
resolve: {
inv_items: function (InventoryService){
return InventoryService.get('red');
}
}
})
.otherwise({
redirectTo: '/'
})
});
data-service.js
Search.factory('InventoryService', function ($http, $q) {
var api_url = "api/inventory/";
return {
get: function (inventory) {
var url = api_url + inventory;
var defer = $q.defer();
$http({method: 'GET', url: url}).
success(function (data, status, headers, config){
defer.resolver(data);
})
.error(function (data,status, headers, config){
defer.reject(status);
});
return defer.promise;
}
}
});
search-controller.js
Search.controller('searchCtrl', function($scope){
$scope.selected = 'have';
$scope.setSection = function(section){
$scope.selected = section;
};
$scope.isSelected = function(section){
return $scope.selected == section;
};
});
Like I mentioned previously I am really new to angular just picked it up yesterday. Basically from what I have written I understand that when the URL is '/' then the service will be initiated and the controller will be called? What I want to know is why cant I use inv_items in my controller? I get the following error.
Do I need to pass some sort of global to the controller which will contain inv_items or am I missing some important piece of knowledge?
Thanks!

The resolve variable 'inv_items' isn't automatically added to your scope of 'searchCtrl'.
Search.controller('searchCtrl', function($scope, inv_items){ //Add this
$scope.inv_items = inv_items; //And this
$scope.selected = 'have';
$scope.setSection = function(section){
$scope.selected = section;
};
$scope.isSelected = function(section){
return $scope.selected == section;
};
});
Granted that the rest of the code works, your 'inv_items' should now be available in that scope.

Related

Angular rootScope works then goes undefined on refresh - AngularFire

Scenario: I assign some values for the user at login to my rootScope. Now I want to able to use those values so that every time the user post a meeting, it should be added under his information in Firebase db.
Issue: I do this well, when I login, and i post the meeting from the user. But then as soon as the page refreshes, rootScope.currentUser becomes undefined. How can I keep rootScope.currentUser from going undefined? My Controller and my factory are below:
my controller:
myApp.controller('MeetingsController', function($scope, $firebaseObject, $firebaseArray, $rootScope, FIREBASE_URL, SomeURL){
//rootScope.currentUser.$id works the first time i post then the second it doesn't
var ref = new Firebase(FIREBASE_URL + $rootScope.currentUser.$id + SomeURL);
var meetings = $firebaseObject(ref);
$scope.meetings = meetings;
$scope.addMeeting = function(){
ref.push({
name: $scope.meetingname,
date: Firebase.ServerValue.TIMESTAMP
});
};
});//controller for around me
My Factory:
myApp.factory('Authentification', function($firebase, $rootScope, $firebaseObject, $firebaseAuth, $routeParams, $location, FIREBASE_URL){
var ref = new Firebase(FIREBASE_URL);
var auth = $firebaseAuth(ref);
auth.$onAuth(function(authUser){
if(authUser){
var firebaseUsers = new Firebase(FIREBASE_URL+'/users/'+authUser.uid);
var user = $firebaseObject(firebaseUsers);
$rootScope.currentUser = user;
} else {
$rootScope.currentUser = '';
}
});
var myObject = {
login: function(user){
return auth.$authWithPassword({
email: user.email,
password: user.pswd
});
},
logout: function(user){
return auth.$unauth();
},
requireAuth: function() {
return auth.$requireAuth();
}
};
return myObject;
});
Route:
myApp.config( ['$routeProvider', function($routeProvider){
$routeProvider.
when('/login', {
templateUrl: 'views/login.html',
controller: 'RegistrationController'
}).
when('/register',{
templateUrl: 'views/register.html',
controller: 'RegistrationController'
}).
when('/aroundme', {
templateUrl: 'views/aroundme.html' ,
controller: 'MeetingsController',
resolve: {
currentAuth: function(Authentification){
return Authentification.requireAuth();
}
}
}).
otherwise({
redirectTo: '/'
});
}]);
The issue might be that you're assigning the $firebaseObject to the $rootScope before it has finished loading. To make sure that it has loaded before binding it to the $rootScope use $loaded():
auth.$onAuth(function(authUser){
if(authUser){
var firebaseUsers = new Firebase(FIREBASE_URL+'/users/'+authUser.uid);
var user = $firebaseObject(firebaseUsers);
user.$loaded()
.then(function(data) {
$rootScope.currentUser = data;
})
.catch(function(err) {
// Handle error
});
} else {
$rootScope.currentUser = '';
}
});
From the docs:
Note that the data will not be available immediately since retrieving it is an asynchronous operation. You can use the $loaded() promise to get notified when the data has loaded.

AngularJS pass param from view to controller

I'm a beginner in angularjs. What I’m trying to do is from view to pass params to the controller, which to return at its side, different results from factory. The problem is that when it goes to call metod with params from some view the result is an infinity loop.
I've the following config:
app.config(function($locationProvider, $stateProvider, $urlRouterProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
}).hashPrefix('!');
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'templates/home.html',
controller: 'StoreController as store'
})
})
My Factory is:
app.factory('BookFactory', function($http, $q){
var service = {};
var baseUrl = 'http://someAPI/ ';
var _query = '';
var _finalUrl = '';
var makeUrl = function() {
_finalUrl = baseUrl + _query;
}
service.setQuery = function(query) {
_query = query;
}
service.getQuery = function() {
return _query;
}
service.callBooks = function() {
makeUrl();
var deffered = $q.defer();
$http({
url: _finalUrl,
method: "GET"
}).success(function(data, status, headers, config) {
deffered.resolve(data);
}).error(function(data, status, headers, config) {
deffered.reject
})
return deffered.promise;
}
return service;
});
And the controller is:
app.controller('StoreController', ['BookFactory',function(BookFactory) {
var store = this;
store.products = [];
this.submitQuery = function(param) {
BookFactory.setQuery(param);
BookFactory.callBooks()
.then(function(data){
store.products = data;
}, function (data) {
alert(data);
});
}
}]);
Home.html when I call the method as follows:
ng-repeat="product in store.submitQuery('php')"
This causes an infinite loop and I can’t understand why, but if I change a bit the controller in the following way:
app.controller('StoreController', ['BookFactory',function(BookFactory) {
var store = this;
store.products = [];
this.submitQuery = function(param) {
BookFactory.setQuery(param);
BookFactory.callBooks()
.then(function(data){
store.products = data;
}, function (data) {
alert(data);
});
}
this.submitQuery('php');
}]);
The difference is that in the controller submitQuery is called
Than in home.html:
ng-repeat="product in store"
Things are going well but I wish thought the през view to pass different parameters.
Thanks in advance.
ng-repeat="product in store.submitQuery('php')"
of course this will make infinite loop ,cause when you make request,ng-repeat is redrawing and invoke same query over and over,
in order to pass diffrent param for query you can bind any variable to view
html
<input ng-model="queryParam" />
controller
app.controller('StoreController', ['BookFactory','$scope',function(BookFactory,$scope) {
var store = this;
$scope.store.products = [];
$scope.queryParam="php";
this.submitQuery = function() {
var param=$scope.queryParam;
BookFactory.setQuery(param);
BookFactory.callBooks()
.then(function(data){
store.products = data;
}, function (data) {
alert(data);
});
}
this.submitQuery();
}]);
and you can set up value of input and thus pass query param to contoller
Thanks for your answer
Not only in ng-repeat is happening. I mean, even if store.submitQuery('php') executes without ng-repeat, the result will be the same (infinity loop).
However for me from semantic point of view to use additional html element for this is not very good.
I changed the view like this:
<div ng-init="store.init('php')" ng-controller="StoreController as store">
{{store}}
</div>
And little bit the controller:
app.controller('StoreController', ['BookFactory',function(BookFactory) {
var store = this;
store.products = [];
this.init = function(param) {
BookFactory.setQuery(param);
this.submitQuery();
}
this.submitQuery = function(param) {
BookFactory.callBooks()
.then(function(data){
store.products = data;
}, function (data) {
alert(data);
});
}
}]);
And now it’s working like I need, but I’m not sure this is the right way.

Why is this factory returning undefined?

I would like assistance in figuring out why this service I have created is returning undefined when I print it to console.
module.js
'use strict';
var Search = angular.module('SearchApp',["ngCookies","ngRoute"]);
Search.run(function ($http, $cookies) {
$http.defaults.headers.common['X-CSRFToken'] = $cookies['csrftoken'];
});
Search.config(function($routeProvider){
$routeProvider
.when('/', {
controller:'searchCtrl',
resolve: {
dota_items: function (InventoryService){
return InventoryService.get('dota');
}
}
})
.otherwise({
redirectTo: '/'
})
});
This is the module file where I have declared a route.
servcie.js
Search.factory('InventoryService', function ($http, $q) {
var api_url = "/api/inventory/";
return {
get: function (inventory) {
var inv_url = api_url + inventory + '/';
var defer = $q.defer();
$http({method: 'GET', url: inv_url}).
success(function (data, status, headers, config){
defer.resolve(data);
})
.error(function (data,status, headers, config){
defer.reject(status);
});
return defer.promise;
}
}
});
As far as I can tell the syntax is correct for my service however I may have missed something.
controller.js
Search.controller('searchCtrl',['$scope', function($scope, dota_items){
console.log(dota_items);
$scope.selected = 'have';
$scope.setSection = function(section){
$scope.selected = section;
};
$scope.isSelected = function(section){
return $scope.selected == section;
};
}]);
Here is the issue, In the console, the variable is always undefined. I have attempted to check if my service is even being called by printing to console however nothing is logged. I'm not sure what the issue could be.
Thanks
When you declare the 'searchCtrl' controller with the inlined array dependency injection syntax
['$scope', function($scope, dota_items) { }]
angular ignores the actual argument names in the function in favor of what you've specified in the array. Consider adding dota_items to the array before the function.
Search.controller('searchCtrl', ['$scope','dota_items',function($scope, dota_items) {
// your code
}]);
You can also remove the array entirely and use angular's implicit dependencies feature like so:
Search.controller('searchCtrl', function($scope, dota_items) {
// your code
});
but it should be noted that this approach only works if you're not minifying or obfuscating your code.

View loads before $scope values are assigned

I've come to this problem were my view loads before $scope params are assigned and this is caused by $http service call taking some time before response is achived.
This leaves me with dropdown boxes being unsync with url params on page reload...
Is there anyway to reload these $scope params or wait til they get values before rendering the view? I would like the easiest solution to this as Im yet farily new to angularjs.
Just give me a hint if more info is needed!
Here's some of the code...
Route
angular.module('app', ['ngRoute', 'app.controller', 'app.service', 'app.filter'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/order/:id', {
templateUrl: '../../App_AngularJs/partials/specificOrder.htm',
controller: 'orderController',
reloadOnSearch: true
})
.when('/orderitem/:id', {
templateUrl: '../../App_AngularJs/partials/orderItem/orderItem.htm',
controller: 'orderItemController',
reloadOnSearch: true
})
.when('/', {
templateUrl: '../../App_AngularJs/partials/searchOrder.htm',
controller: 'ordersController',
reloadOnSearch: false
//Use some resolve here!? How!?
});
}
Controller
var orderContrl = angular.module('app.controller', ['angularTreeview', 'ui.bootstrap'])
.controller('ordersController', [
'$scope', '$routeParams', '$location', '$filter', '$modal', '$log', 'orderService',
function ($scope, $routeParams, $location, $filter, $modal, $log, orderService) {
init();
function init() {
$scope.searchtext = $routeParams.search || '';
$scope.page = $routeParams.page || 1;
$scope.take = $routeParams.take || 10;
$scope.status = $routeParams.status || -1;
$scope.group = $routeParams.group || -1;
$scope.type = $routeParams.type || -1;
$scope.category = $routeParams.category || -1;
$scope.selectedOrganisation = "Knoc LK";
getOrders(true);
getFilters(true);
}
function getFilters(reloadPage) {
orderService.queryOrderAllDropdown()
.then(function (response) {
$scope.orderGroup = response.OrderGroups;
$scope.orderStatus = response.OrderStatus;
$scope.orderType = response.OrderTypes;
$scope.orderPackageCategory = response.ProductPackageCategories;
$scope.orderAllCategory = response.ProductItemCategories;
//Sets type and shows different categories depending on type chosen
getCategory();
//Trying to reassign the values but still nothing...
if (reloadPage) {
angular.forEach($scope.orderStatus, function (value) {
if ($routeParams.status == value.ID)
$scope.status = value.ID;
});
//Trying to reassign the values but still nothing...
$scope.group = $scope.group;
}
},
function (errorMessage) {
$scope.error = errorMessage;
});
}
Service
angular.module('app.service', [])
.service('orderService', ['$http', '$q', function ($http, $q) {
this.queryOrderAllDropdown = function () {
var deferred = $q.defer();
$http({
type: 'GET',
url: 'GenericHandlers/HttpOrderService.ashx',
method: 'GetOrderAllDropdown',
headers: { 'Content-Type': 'text/plain' }
}).success(function (data) {
deferred.resolve(data);
}).error(function () {
deferred.reject("An error occured while fetching data");
});
return deferred.promise;
},
You need to use a Resolver to fetch the data from the backend. Adding a "resolve" to the $routeProvider will fetch the data before the controller takes control. Check out this blog post for a similar example.

AngularJS Service Passing Data Between Controllers

When using an AngularJS service to try and pass data between two controllers, my second controller always receives undefined when trying to access data from the service. I am guessing this is because the first service does a $window.location.href and I'm thinking this is clearing out the data in the service? Is there a way for me to change the URL to a new location and keep the data persisted in the service for the second controller? When I run the code below the alert in the second controller is always undefined.
app.js (Where Service is Defined)
var app = angular.module('SetTrackerApp', ['$strap.directives', 'ngCookies']);
app.config(function ($routeProvider)
{
$routeProvider
.when('/app', {templateUrl: 'partials/addset.html', controller:'SetController'})
.when('/profile', {templateUrl: 'partials/profile.html', controller:'ProfileController'})
.otherwise({templateUrl: '/partials/addset.html', controller:'SetController'});
});
app.factory('userService', function() {
var userData = [
{yearSetCount: 0}
];
return {
user:function() {
return userData;
},
setEmail: function(email) {
userData.email = email;
},
getEmail: function() {
return userData.email;
},
setSetCount: function(setCount) {
userData.yearSetCount = setCount;
},
getSetCount: function() {
return userData.yearSetCount;
}
};
});
logincontroller.js: (Controller 1 which sets value in service)
app.controller('LoginController', function ($scope, $http, $window, userService) {
$scope.login = function() {
$http({
method : 'POST',
url : '/login',
data : $scope.user
}).success(function (data) {
userService.setEmail("foobar");
$window.location.href = '/app'
}).error(function(data) {
$scope.login.error = true;
$scope.error = data;
});
}
});
appcontroller.js (Second controller trying to read value from service)
app.controller('AppController', function($scope, $http, userService) {
$scope.init = function() {
alert("In init userId: " userService.getEmail());
}
});
Define your service like this
app.service('userService', function() {
this.userData = {yearSetCount: 0};
this.user = function() {
return this.userData;
};
this.setEmail = function(email) {
this.userData.email = email;
};
this.getEmail = function() {
return this.userData.email;
};
this.setSetCount = function(setCount) {
this.userData.yearSetCount = setCount;
};
this.getSetCount = function() {
return this.userData.yearSetCount;
};
});
Check out Duncan's answer here:
AngularJS - what are the major differences in the different ways to declare a service in angular?

Resources