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.
Related
I am making an Ionic app and I am utilizing $http service to pull in a page data from a server in JSON format through an API. My factory looks like this:
app.factory('FaqHiveData', function ($http, $q, $timeout, $log, $stateParams, $ionicLoading) {
var faqdata = [];
$ionicLoading.show();
return {
all: function () {
var dfd = $q.defer();
$http.get("http://hive.squaresoftng.com/api/get/faq/")//, {cache: true}
.then(function (response) {
faqdata = response.data;
dfd.resolve(faqdata);
}).finally(function(){
$ionicLoading.hide();
});
return dfd.promise;
}
};
});
in app.js, i am using a resolve function in my app.config for each state
.state('app.faq', {
url: '/faq',
views: {
'menuContent': {
templateUrl: 'templates/faq.html',
controller: 'FaqCtrl',
resolve: {
faqdata: function (FaqHiveData) {
return FaqHiveData.all();
}
}
}
}
})
i also enable cache in my app.config
// enable http caching
$httpProvider.defaults.cache = true;
then i use the return data in my controller from the scope
app.controller('FaqCtrl', function ($scope, $stateParams, $http, $timeout, $log, faqdata, ionicMaterialInk) {
$scope.faqdata = faqdata;
//add ref to other needed value in the scope.faqdata
$scope.faqs = $scope.faqdata.faqs;
});
this works for accessing the data in my views, but i want to set this returned data to local storage in order to have access to it when the app starts or there is no connection.
I want to wait for a service $http result before the controller does the rest.
I tested some hardcoded JSON for myData and it IS visible in the controller, but as soon as I try to populate myData with a $http request, the controller is not waiting for it and just walks thru the rest of the code. The network tab from Chrome webdevelopper is showing the expected result for the request.
I already have the following:
var ListerApp = angular.module('ListerApp',[
'ListerAppFilters',
'sharedFactoryApp',
'sharedServiceApp',
'ListerAppController',
'infinite-scroll',
'angular-inview',
'ngRoute'
]);
ListerApp.config(['$routeProvider', '$httpProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when('/list',
{
templateUrl: '/assets/services/partials/list.html',
controller: 'ListerCtrl',
resolve : {
'sharedServiceAppData': function($sharedServices){
// sharedFactoryAppData will also be injectable in your controller, if you don't want this you could create a new promise with the $q service
return $sharedServices.promise();
}
}
}
);
}]);
angular.module('sharedServiceApp', []).service('$sharedServices', ['$http', '$rootScope', '$q', function($http, $rootScope, $q) {
var myData = null;
return {
promise : function () {
if (!myData) {
$http({method : 'GET', url : '/shop/api/json', params : {
end : $rootScope.endmarkerSyncDataset,
page : 1,
per_page : $rootScope.itemsPerPage
}
}).success(function (data) {
myData = data.data_set;
//deferred.resolve(data.data_set);
});
// I allready tested this and this is OK: myData = {foo : 'bar'};
}
},
getShopData: function () {
return myData;
}
};
}]);
(function(){
var appController = angular.module('ListerAppController', []);
appController.controller('ListerCtrl', ['$scope', '$rootScope', '$http', '$filter', '$timeout', '$sharedFactories', '$sharedServices',
function($scope, $rootScope, $http, $filter, $timeout, $sharedFactories, $sharedServices) {
$scope.items = $sharedServices.getShopData();
console.log($scope.items); // return myData -> null
}
})();
I've done this a bunch of times here's what I usually do in my resolve object for the routeProvider, need to make sure you return all promises appropriately in order for the route change to wait on resolve properties.
$routeProvider
.when('/path',
{
templateUrl: 'some/path/to/template.html',
controller: 'myCtrl',
resolve : {
'myData': ['mySrvc',function(mySrvc){
return mySrvc.someMethod().then(function(response){
return response.data;
},function(){
return {};
});
}]
}
}
);
Then the service:
angular.module('myApp.services').factory('mySrvc',['$http',function($http){
var _url = 'https://someurl.com/path/to/api';
return {
someMethod : function(vars){
if(angular.isDefined(vars)){
return $http.post(_url,$.param(vars),{headers:{'Content-Type':'application/x-www.form-urlencoded'}});
}else{
return $http.get(_url);
}
}
};
}]);
Then in the controller you need to inject the resolve parameters at the end of the parameter list for the controller.
angular.module('myApp.controllers').controller('myCtrl',['$scope','myData',function($scope,myData){
});
In your code, in the resolve object of the routeProvider you have a return from a function that returns nothing, try returning the promise from the $http and then the data.data_set value in the success function of your service.
I have found something like $q.defer, resolve and promise.
It holds up everything until the status "promise" is reached.
Here's a link
angular.module('sharedServiceApp', []).service('$sharedServices', ['$http', '$rootScope', '$q', function($http, $rootScope, $q) {
var myData = null;
return {
promise : function () {
if (!myData) {
var deferred = $q.defer();
$http({method : 'GET', url : '/shop/api/json', params : {
end : $rootScope.endmarkerSyncDataset,
page : 1,
per_page : $rootScope.itemsPerPage
}
}).success(function (data) {
myData = data.data_set;
deferred.resolve(data.data_set);
}).error(function(data, status, headers, config) {
deferred.reject("Error: request returned status " + status);
});
return deferred.promise;
} else {
return myData;
}
},
getShopData: function () {
return myData;
},
setShopData: function (data) {
myData= data;
}
};
}]);
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.
I am trying to call the update / put method in the factory which will in turn save the changes on the form to the database via an API call. But I get a console error below. The update function is getting called from the button click fine, but it doesn't call the factory and API from there. What am I missing? Thank you!
I updated my code with the suggestion below but now have this error:
My console error: "Error: [$injector:unpr] http://errors.angularjs.org/1.2.10/$injector/unpr?p0=%24resourceProvider%20%3C-%20%24resource%20%3C-%20memberUpdate
var securityApp = angular.module('securityApp', ['ngRoute']).
config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'PartialPages/members.html',
controller: 'membersController'
})
.when('/memberDetail/:memberID', {
templateUrl: 'PartialPages/memberDetail.html',
controller: 'memberDetailController'
})
.when('/memberEdit', {
templateUrl: 'PartialPages/memberEdit.html',
controller: 'memberEditController'
});
});
securityApp.factory('memberUpdate', function ($resource) {
return $resource('/api/Members/:id', { id: '#id' }, { update: { method: 'PUT' } });
});
securityApp.controller('memberDetailController', function ($scope, $http, $routeParams, memberUpdate) {
var id = $routeParams.memberID;
$http.get('/api/Members/' + $routeParams.memberID).success(function (data) {
$scope.member = data;
})
.error(function () {
$scope.error = "An Error has occured while loading posts!";
})
$scope.update = function () {
memberUpdate.update({ id: id }, $scope.member);
};
});
You need to inject memberUpdate into the controller dependencies.
securityApp.controller('memberDetailController', function ($scope, $http, $routeParams, memberUpdate) {
var id = $routeParams.memberID;
$http.get('/api/Members/' + $routeParams.memberID).success(function (data) {
$scope.member = data;
})
.error(function () {
$scope.error = "An Error has occured while loading posts!";
})
$scope.update = function () { // you don't need to pass $scope and memberUpdate since they are already available into the scope
memberUpdate.update({ id: id }, $scope.member);
};
});
$resource is in a different module so you need to include it.
var securityApp = angular.module('securityApp', ['ngRoute', 'ngResource']).
her how you install it https://docs.angularjs.org/api/ngResource
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?