I have a controller that needs to access a url parameter. However, I can't figure out how to access the parameter. Here is what I have so far:
Controller:
function CustomerCtrl($scope, $http, $routeParams, $route) {
// var customer_id = $routeParams.id; // this doesn't work
// var customer_id = $route.current.params.id; // this doesn't work
var customer_id = '58'; // this clearly works
$http({
url: 'customers/'+customer_id+'/info',
method: "POST"
})
.success(function (data, status, headers, config) { $scope.name = data; })
.error(function (data, status, headers, config) { $scope.status = status; });
}
App:
var customer = {
name: 'customer',
url: '/customer',
abstract: true,
templateUrl: 'views/customer/customer.html',
controller: 'CustomerCtrl'
};
var customer_info = {
name: 'customer.info',
parent: customer,
url: '/:id/info'
views: {
view1: { templateUrl: "views/customer/view1.html" },
view2: { templateUrl: "views/customer/view2.html" }
}
};
$stateProvider
.state(customer)
.state(customer_info);
What am I missing?
It's actually even easier than you thought. You're using the ui-router (https://github.com/angular-ui/ui-router) which uses states instead of the default router.
function CustomerCtrl($scope, $http, $routeParams, $route) {
should be:
function CustomerCtrl($scope, $http, $stateParams, $state) {
then:
var customer_id = $stateParams.id;
I spent all day confusing myself by trying to find an angular solution to this seemingly simple, common problem. Most of you probably already figured this out, but the solution is to just use plain old javascript:
var pathArray = window.location.pathname.split( '/' );
var customer_id = pathArray[3];
$scope.customer_id = customer_id
So simple, yet I feel like an idiot for not thinking about this from the beginning.
Related
In this project, I am executing a query on click list item of ionic. I am getting the data from php json_encode. The data is getting displayed in the networks tab under response. Also, I have added $scope.doctorList = {}; and after that wrote this line $scope.doctorList = response which comes from success function. The data is getting displayed in console.log($scope.doctorList) as well.
Now when I try to display this data in angular, it does not show anything.
I have included it in ng-repeat as : ng-repeat = "doctors in doctorList"
The syntax seems to be correct as the same thing is working for another controller but here, I can't retrieve the data. The page goes blank and there is no error in console / netowrks tab.
I am using one controller for two html files. Please help
Here is the routes file
angular.module('app.routes', []).config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
$stateProvider.state('homeselect', {
url: '/home-select',
templateUrl: 'templates/homeselect.html',
controller: 'homeCtrl'
});
$stateProvider.state('home', {
url: '/home',
templateUrl: 'templates/home.html',
controller: 'homeCtrl'
});
});
Here is the controller
angular.module('app.controllers', []).controller('homeCtrl', function ($scope, $http, $ionicSideMenuDelegate, myServices, $window) {
$ionicSideMenuDelegate.toggleLeft();
$scope.loadDoc = function (type) {
$http({
url: "http://localhost/drmedic/retrieve_details_type.php",
method: "POST",
data: {
data: type
}
}).success(function (response) {
$scope.doctorList = {};
$scope.doctorList = response;
$window.location.href = '#/home-select';
});
};
$http({method: 'GET', url: 'http://localhost/drmedic/retrieve_details.php'}).success(function (data) {
$scope.contents = {};
$scope.contents = data;
});
});
Here is the html file code for ng-repeat
<ion-list ng-repeat="doctors in doctorList">
<ion-item>
<center>
{{doctors.name}}<br>
{{doctors.fees}}
</center>
</ion-item>
</ion-list>
You can use service.Open a file called service.js.After that this inject to app.js. I revised the code as follows:
Service.js:
angular.module('app.services', [])
.factory("AppService", function ($http) {
var AppService= {};
AppService.GetDetails = function (data) {
return $http({
url: "http://localhost/drmedic/retrieve_details_type.php",
method: "POST",
data: {
data: data
}
});
return AppService;
}
controller.js:
.controller('homeCtrl',function($scope,$http,$ionicSideMenuDelegate,myServices,$window,AppService) {
$ionicSideMenuDelegate.toggleLeft();
$scope.loadDoc = function(type){
AppService.GetDetails({type:type}).success(function (response) {
$scope.doctorList = {};
$scope.doctorList = response;
$window.location.href = '#/home-select';
})
.error(function (err) {
console.log(err);
});
}
});
ng-repeat iterates through a collection of items, create its own scope and renders it on UI. When I say collections, it should be an array.
https://docs.angularjs.org/api/ng/directive/ngRepeat
Please check the data-type for doctorList, which I believe is an array.
$scope.doctorList = [];
I hope this should solve the problem, if not please share the code I'll take a deep look into it.
function storyData($http, $q) {
var URL = 'stories.json';
var storyCache = [];
this.getStories = function() {
var deferred = $q.defer();
alert(URL);
$http({method: 'GET', url: URL})
.success(function (data, status, headers, config) {
storyCache = data;
alert(storyCache); //correct data appears in the alert window, but this doesn't set the instance storyCache variable for some reason
deferred.resolve(data);
})
.error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
};
this.stories = function() {
return storyCache;
}
}
My app -
'use strict';
var angularApp = angular.module('ccsApp', ['ngRoute', 'ngAnimate', 'ui.bootstrap']);
angularApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'stories.html',
controller: 'StoryController as StoryCtrl',
resolve: {
stories: function(storyData) {
return storyData.getStories();
}
}
})
.otherwise({
redirectTo: '/'
});
}
]);
Within my controller, I'm not injecting the "stories" value from the routeProvider so that I can use my service.
Why am I unable to change storyCache from within my $http method? I'm confident this is something terribly simple, but my research hasn't led me to an answer. Thank you in advance for your help.
The async. aspect of this works fine and is not the problem. I'm ensuring that I have the data by using the resolve object on my routeProvider. Also, I'm ensuring that I have the data before the deferred.resolve(data) method executes by issuing an alert on it. I don't have the solution, but an error in my use of async. is not the solution either.
I would like to change the route of an angularjs application build with ionic framework, but the route didn't change
this is my code of app.js
angular.module('starter', ['ionic', 'starter.controllers'])
.state('app.annuaire.menuitempage', {
url: "/menuitempage/:ID",
views: {
'menuContent' :{
templateUrl: "templates/menuItemPage.html",
controller: function($stateParams){
$stateParams.ID ;
}
}
}
})
.state('app.annuaire', {
url: "/annuaire",
views: {
'menuContent' :{
templateUrl: "templates/annuaire.html",
controller: 'MenuItemCtrl'
}
}
})
And this is the code of my controller
angular.module('starter.controllers', [])
.controller('MenuItemCtrl', function($scope, $http, $location) {
$scope.itemsMenu = {};
var responsePromise = $http.get("http://monguidepratique.com/mobile/getCategories.php?parent_id=0");
responsePromise.success(function(data, status, headers, config) {
//alert(data);
$scope.itemsMenu = data;
});
responsePromise.error(function(data, status, headers, config) {
alert("AJAX failed!");
});
$scope.itemClick = function(path){
alert(1);
$location.path(path);
};
})
And this is my html code in annuaire.html
<div class="col" ng-click="itemClick('/menuitempage/1628')"><img class="img_menu" src="img/home.png"><p class="titre_center">Accueil</p></div>
Try
$location.path(path)
instead of
$state.go(path)
You need to inject $location service into your controller.
Edit
If you are using $state.go - you should to use it next way:
$scope.itemClick = function(id){
$state.go('app.annuaire.menuitempage', {'ID': id})
};
And HTML:
<div class="col" ng-click="itemClick(1628)"><img class="img_menu" src="img/home.png"><p class="titre_center">Accueil</p></div>
The first param is state name, not URL, the second is an Object with your params.
I solved my problem
in annuaire.html i changed
itemClick('/menuitempage/1628')
by
itemClick('/app/menuitempage/1628')
and i changed the route name app.annuaire.menuitempage by
app.menuitempage
.state('app.menuitempage', {
url: "/menuitempage/:ID",
views: {
'menuContent' :{
templateUrl: "templates/menuitempage.html",
controller: 'SubMenuCtrl'
}
}
})
I am writing an angularJs app:
html :
<div ng-controller=NavCtrl>
<h1 ng-bind-html="currentTitle"></h1>
</div>
I am searching for a way to update the currentTitle variable in my html which is in global scope.
.service('WorkService', [function(){
return {
currentTitle : 'dada'
};
}])
.controller('NavCtrl', function($scope, $location, $http, WorkService) {
$scope.works = [];
$http({method: 'GET', url: '/api/v1/work'}). //collects all works
success(function(data, status, headers, config) {
$scope.currentTitle = WorkService.currentTitle;
})
})
.controller('DetailCtrl', function($scope, $routeParams, $http, WorkService) {
$http({method: 'GET', url: '/api/v1/work/' + $routeParams.workId + '/'}).
success(function(data, status, headers, config) {
$scope.activateButton($routeParams.workId);
WorkService.currentTitle = data.title;
})
})
But currentTitle variable is not updated in the template. What am i doing wrong?
When you do WorkService.currentTitle = data.title current scope is unaware of this change. That is why you wont see the change in the template.
It is not ideal but for this requirement you may keep the currentTitle in $rootScope and keep update $scope.currentTitle in each controllers and that will do.
.run(function($rootScope){
$rootScope.globalData = {currentTitle : 'dada'}
})
.controller('NavCtrl', function($scope, $location, $http, WorkService) {
$scope.works = [];
$http({method: 'GET', url: '/api/v1/work'}). //collects all works
success(function(data, status, headers, config) {
$scope.globalData.currentTitle = 'New title';
})
})
.controller('DetailCtrl', function($scope, $routeParams, $http, WorkService) {
$http({method: 'GET', url: '/api/v1/work/' + $routeParams.workId + '/'}).
success(function(data, status, headers, config) {
$scope.activateButton($routeParams.workId);
$scope.globalData.currentTitle = data.title;
})
})
And in html
<h1 ng-bind-html="globalData.currentTitle"></h1>
You can't two-way bind to a variable in a service, but you can bind to an accessor function. Change your service to return getter and setter functions:
.service('WorkService', ['$sce', function($sce){
var currentTitle= $sce.trustAsHtml('dada');
return {
getCurrentTitle: function(){ return currentTitle; },
setCurrentTitle: function(value){ currentTitle = $sce.trustAsHtml(value);}
};
Then in your controller you can get the currentTitle like this:
$scope.currentTitle = WorkService.getCurrentTitle;
Note that you are setting it equal to the getCurrentTitle function itself (not the result of the function).
Now your html looks like this:
<h1 ng-bind-html="currentTitle()"></h1>
No need to set up $watches or hang stuff of $rootScope. See Demo here.
I want to call a particular function: GetSession() at the beginning of my application load. This function makes a $http call and get a session token: GlobalSessionToken from the server. This session token is then used in other controllers logic and fetch data from the server. I have call this GetSession()in main controller: MasterController in $routeChangeStart event but as its an asynchronous call, my code moves ahead to CustomerController before the $http response.
Here is my code:
var GlobalSessionToken = ''; //will get from server later
//Define an angular module for our app
var myApp = angular.module('myApp', ['ngRoute']);
//Define Routing for app
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/customer', {
templateUrl: 'partials/customer.html',
controller: 'CustomerController',
resolve: {
loadData: function($q){
return LoadData2($q,'home');
}
}
}).
otherwise({
redirectTo: '/home'
});
}]);
//controllers start here and are defined in their each JS file
var controllers = {};
//only master controller is defined in app.js, rest are in separate js files
controllers.MasterController = function($rootScope, $http){
$rootScope.$on('$routeChangeStart', function(){
if(GlobalSessionToken == ''){
GetSession();
}
console.log('START');
$rootScope.loadingView = true;
});
$rootScope.$on('$routeChangeError', function(){
console.log('ERROR');
$rootScope.loadingView = false;
});
};
controllers.CustomerController = function ($scope) {
if(GlobalSessionToken != ''){
//do something
}
}
//adding the controllers to myApp angularjs app
myApp.controller(controllers);
//controllers end here
function GetSession(){
$http({
url: GetSessionTokenWebMethod,
method: "POST",
data: "{}",
headers: { 'Content-Type': 'application/json' }
}).success(function (data, status, headers, config) {
GlobalSessionToken = data;
}).error(function (data, status, headers, config) {
console.log(data);
});
}
And my HTML has following sections:
<body ng-app="myApp" ng-controller="MasterController">
<!--Placeholder for views-->
<div ng-view="">
</div>
</body>
How can I make sure this GetSession() is always called at the very beginning of my application start and before any other controller calls and also called only once.
EDIT: This is how I added run method as per Maxim's answer. Still need to figure out a way to wait till $http call returns before going ahead with controllers.
//Some initializing code before Angular invokes controllers
myApp.run(['$rootScope','$http', '$q', function($rootScope, $http, $q) {
return GetSession($http, $q);
}]);
function GetSession($http, $q){
var defer = $q.defer();
$http({
url: GetSessionTokenWebMethod,
method: "POST",
data: "{}",
headers: { 'Content-Type': 'application/json' }
}).success(function (data, status, headers, config) {
GlobalSessionToken = data;
defer.resolve('done');
}).error(function (data, status, headers, config) {
console.log(data);
defer.reject();
});
return defer.promise;
}
Even though some of the solutions here are perfectly valid, resolve property of the routes definition is the way to go, in my opinion. Writing your app logic inside session.then in every controller is a bit too much , we're used such approach too in one of the projects and I didn't work so well.
The most effective way is to delay controller's instantiation with resolve, as it's a built-in solution. The only problem is that you have to add resolve property with similar code for every route definition, which leads to code duplication.
To solve this problem, you can modify your route definition objects in a helper function like this:
function withSession(routeConfig) {
routeConfig.resolve = routeConfig.resolve || {};
routeConfig.resolve.session = ['getSessionPromise', function(getSessionPromise) {
return getSessionPromise();
}]
return routeConfig;
}
And then, where define your routes like this:
$routeProvider.when('/example', withSession({
templateUrl: 'views/example.html',
controller: 'ExampleCtrl'
}));
This is one of the many solutions I've tried and liked the most since it's clean and DRY.
You can't postpone the initialisation of controllers.
You may put your controller code inside a Session promise callback:
myApp.factory( 'session', function GetSession($http, $q){
var defer = $q.defer();
$http({
url: GetSessionTokenWebMethod,
method: "POST",
data: "{}",
headers: { 'Content-Type': 'application/json' }
}).success(function (data, status, headers, config) {
GlobalSessionToken = data;
defer.resolve('done');
}).error(function (data, status, headers, config) {
console.log(data);
defer.reject();
});
return defer.promise;
} );
myApp.controller( 'ctrl', function($scope,session) {
session.then( function() {
//$scope.whatever ...
} );
} );
Alternative: If you don't want to use such callbacks, you could have your session request synchronous, but that would be a terrible thing to do.
You have not provided any details related to GetSession. For scenarios like this you should use the resolve property while defining your routes in $routeProvider. I see you are using resolve already.
What you can do now is to wrap the GlobalSessionToken into a Angular service like GlobalSessionTokenServiceand call it in the resolve to get the token before the route loads. Like
resolve: {
loadData: function($q){
return LoadData2($q,'home');
},
GlobalSessionToken: function(GlobalSessionTokenService) {
return GlobalSessionTokenService.getToken() //This should return promise
}
}
This can then be injected in your controller with
controllers.MasterController = function($rootScope, $http,GlobalSessionToken){