Using $routeParams for custom views? - angularjs

i was making a gallery using angular, i categorized images so when the gallery loads, each category is represented by an image, when user clicked on the image they would see the entire images of that gallery.
for that i made an array so each image representing a category has a block that is an array and consist information of all images in that category. and using that block for loading those images.
so i was trying to use $routeParams so i could make a url for each category to load data in that view, the representative image of categories are loading fine but i can't load the images of that category in the view.
my module code is:
(function () {
var app = angular.module('myApp', ['ngRoute']);
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'contentsCtrl',
templateUrl: 'views/contents.php'
})
.when('/news/', {
controller: 'newsCtrl',
templateUrl: 'views/news.php'
})
.when('/notes/', {
controller: 'notesCtrl',
templateUrl: 'views/notes.php'
})
.when('/records/', {
controller: 'recordsCtrl',
templateUrl: 'views/records.php'
})
.when('/gallery/', {
controller: 'galleryCtrl',
templateUrl: 'views/gallery.php'
})
.when('/gallery/:galleryID', {
controller: 'imagesCtrl',
templateUrl: 'views/images.php'
})
.when('/statute/', {
controller: 'statuteCtrl',
templateUrl: 'views/statute.php'
})
.when('/forms/', {
controller: 'formsCtrl',
templateUrl: 'views/forms.php'
})
.when('/about/', {
controller: 'aboutCtrl',
templateUrl: 'views/about.php'
})
.when('/contact/', {
controller: 'ContactCtrl',
templateUrl: 'views/contact.php'
})
.when('/post/', {
controller: 'PostCtrl',
templateUrl: 'views/post.php'
})
.otherwise({redirectTo: '/'});
});
and the code for the controller is:
(function () {
var imagesCtrl = function ($scope, $http, $routeParams) {
$http.get("includes/gallery.php").success(function (response) {
$scope.gallery = response.gallery;
});
var galleryID = $routeParams.galleryID;
$scope.images = $scope.gallery[0];
function init() {
// Search gallery for the galleryID
for (var i = 0, len = $scope.gallery.length; i < len; i++) {
if ($scope.gallery[i].imageCategory == parseInt(galleryID)) {
$scope.images = $scope.gallery[i].category;
break;
}
}
}
init();
};
imagesCtrl.$inject = ['$scope', '$http', '$routeParams'];
angular.module('myApp').controller('imagesCtrl', imagesCtrl);
}());
and this is the view:
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">{{ galleryID }}</h1>
</div>
Back to Gallery
<div class="col-lg-4 col-md-4 col-sm-6 col-xs-12 thumb" ng-repeat="image in images">
<img class="img-responsive" src="./uploads/images/{{ image.imageName}}" alt="" style="width:400px; height:160px;">
</div>
so anyone knows what is the problem? i would appreciate the help!

You're calling your init() function just after sending the $http request. It thus tries finding the gallery in $scope.gallery, but $scope.gallery is initialized long after, when the response to the $http request is available.
The code should be:
$http.get("includes/gallery.php").success(function (response) {
$scope.gallery = response.gallery;
init();
});
function init() {
// Search gallery for the galleryID
for (var i = 0, len = $scope.gallery.length; i < len; i++) {
if ($scope.gallery[i].imageCategory == parseInt($routeParams.galleryID)) {
$scope.images = $scope.gallery[i].category;
break;
}
}
}
That said, Why do you get all the galleries from the server for each page, supposed to render a single gallery. You should send the gallery ID to the server, and the server should respond with that category only, instead of always responding with all the galleries.

Another approach is to use $routerresolve, the router will wait for these promises to be resolved or one to be rejected before the controller is instantiated.
Route Setup:
.when('/gallery/', {
controller: 'galleryCtrl',
templateUrl: 'views/gallery.php'
resolve: {
gallery: ['$http', function($http) {
return $http
.get('includes/gallery.php')
.then(
function success(response) {
return response.data;
},
function error(reason) {
return false;
}
);
}
]
}
})
The controller should looks like this:
(function (angular) {
var imagesCtrl = function ($scope, $http, $routeParams, gallery) {
$scope.gallery = gallery;
var galleryID = $routeParams.galleryID;
$scope.images = $scope.gallery[0];
function init() {
// Search gallery for the galleryID
for (var i = 0, len = $scope.gallery.length; i < len; i++) {
if ($scope.gallery[i].imageCategory == parseInt(galleryID)) {
$scope.images = $scope.gallery[i].category;
break;
}
}
}
init();
};
imagesCtrl.$inject = ['$scope', '$http', '$routeParams', 'gallery'];
angular.module('myApp').controller('imagesCtrl', imagesCtrl);
}(angular));

Related

Getting one item out of ng-repeat

I have a homepage with different products and I want to display one choosen product in anouther view. (the detail view). To show the products I use ng-repeat, which iterate over an product-Array.
Now I get a single product out of the ng-repeat when cklicking an button. Then the view changes into the detail view with the choosen product. The switch of the views should go over the id, because this one is needed to make an request to my API.
At this state I tried it with $routeParams, but it'doesn't workted. Then I searched here on stackoverflow. I read that it could be scope-Problem, because I try to pass the id into an controller. (and I need that Id in another controller).
When I click the Button on the homepage, nothing happents.
I hope, that somebody has an idea, how to solve this problem.
Here is a stample json file of the API:
{
"_id": "582ae2beda0fd7f858c109e7",
"title": "Lorem ipsum",
"smalldescription": "Lorem ipsum dolor sit amet,",
"longdescription": "Lorem ipsum dolor sit ametLorem ipsum ",
"price": "2500",
"img": "Imagetxt"
}
Here is my Code:
app.js
angular.module('Productportfolio', ['ngRoute'])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/home', {
templateUrl: '/components/home/home.html',
controller: 'ProductCtrl'
})
.when('/detail/:productId', {
templateUrl: '/components/detail/detail.html',
controller: 'DetailCtrl'
.otherwise({redirectTo: '/home'});
}]);
home.html
<div ng-controller="ProductCtrl as ProductCtrl">
<div ng-repeat="product in ProductCtrl.products ">
<h3>{{product.title}}</h3>
<button ng-click="loadDetail(product)">Detailansicht</button>
</div>
</div>
ProductCtrl.js
angular.module('Productportfolio')
.controller('ProductCtrl', ['APIService','$location', function (APIService,$location) {
var vm = this;
vm.products = null;
init();
function init() {
APIService.getProducts()
.then(function (response) {
vm.products = response.data;
})
.catch(function (error) {
console.log("error at GET");
});
}
vm.loadDetail = function(product){
$location.path('/detail'+product.id);
}
}]);
APISvc.js
angular.module('Productportfolio')
.service('APIService', ['$http', function ($http) {
var svc = this;
svc.root = 'http://localhost:3000/api';
svc.API = {
'getProducts': getProducts,
'getProduct' : getProduct
};
return svc.API;
function getProducts() {
return $http({
method: 'GET',
url: svc.root + '/products'
})
}
function getProduct(id){
return $http({
method: 'GET',
url : svc.root +'/product/'+id
})
}
}]);
DetailCtrl.js
angular.module('Productportfolio')
.controller('DetailCtrl', ['APIService', '$routeParams', function (APIService, $routeParams) {
var vm = this;
vm.product = null;
vm.productId = $routeParams.productId;
init();
function init() {
APIService.getProduct(vm.productId)
.then(function (response) {
console.log(response);
vm.product = response.data;
})
.catch(function (error) {
console.log("error at GET");
});
}
}]);
Remove ng-controller from div and update like below.
<div >
<div ng-repeat="product in vm.products ">
<h3>{{product.title}}</h3>
<button ng-click="vm.loadDetail(product)">Detailansicht</button>
</div>
</div>
Also in route configuration add controllerAs: 'vm'
.when('/home', {
templateUrl: '/components/home/home.html',
controller: 'ProductCtrl',
controllerAs: 'vm'
})
Update the function like
vm.loadDetail = function(product){
$location.path('/detail'+product['_id']);
}
Replace your module file with this this
angular.module('Productportfolio', ['ngRoute'])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/home', {
templateUrl: '/components/home/home.html',
controller: 'ProductCtrl',
controllerAs: 'ProductCtrl' //modified as your using controller as syntax
})
.when('/detail/:productId', {
templateUrl: '/components/detail/detail.html',
controller: 'DetailCtrl',
controllerAs : 'DetailCtrl' //modify this also
//add these lines
param:{
productId:null
}
}
.otherwise({redirectTo: '/home'});
}]);
Replace your ProductCtrl.js with this
angular.module('Productportfolio')
.controller('ProductCtrl', ['APIService','$location', function (APIService,$location) {
var vm = this;
vm.products = null;
init();
function init() {
APIService.getProducts()
.then(function (response) {
vm.products = response.data;
})
.catch(function (error) {
console.log("error at GET");
});
}
vm.loadDetail = function(product){
$location.path('/detail/'+product._id); // you missed a slash and the property was wrong
}
}]);
this is the correct one
$location.path('/detail/'+product._id);
Edit
As #Paulson Peter said:
Remove ng-controller from div and update like below.
<div >
<div ng-repeat="product in vm.products ">
<h3>{{product.title}}</h3>
<button ng-click="vm.loadDetail(product)">Detailansicht</button>
</div>
Also in route configuration add controllerAs: 'vm'
.when('/home', {
templateUrl: '/components/home/home.html',
controller: 'ProductCtrl',
controllerAs: 'vm'
})
Like # Aravind said:
vm.loadDetail = function(product){
$location.path('/detail/'+product._id); //here is the change
}
Now I can get the product an the view changes

Angular check parameter

My code:
/**
* Created by maki1234 on 14.03.16.
*/
angular.module('admin', ['ngRoute'])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/all.html',
controller: 'mainController'
})
.when('/details/:id', {
templateUrl: 'views/details.html',
controller: 'detailsController',
resolve: {
id: function ($route, $q) {
var q = $q.defer();
var id = parseInt($route.current.params.id, 10);
if (!isNaN(id)) {
q.resolve(id);
} else {
q.reject('Param Id must be a number!');
}
return q.promise;
}
}
})
.otherwise({
redirectTo: '/'
});
})
.controller('mainController', function () {
})
.controller('detailsController', function ($scope, $location, id, $log) {
$scope.$on('$routeChangeError', function (event, current, previous, rejection) {
$scope.error = rejection;
});
$log.info($scope.error);
});
My problem is: This code works but when ID is numeric, but when it's a string controller doesn't log anything in console. Any suggestion? (when id is numeric in console i see undefined - it's good i think)
Updated:
app.js
angular.module('admin', ['ngRoute'])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/all.html',
})
.when('/details/:id', {
templateUrl: 'views/details.html',
controller: 'detailsController',
resolve: {
'id': function ($route, $q) {
var q = $q.defer();
var id = parseInt($route.current.params.id, 10);
if (!isNaN(id)) {
q.resolve(id);
} else {
q.reject('Param id must be a number!');
}
return q.promise;
}
}
})
.otherwise({
redirectTo: '/'
});
})
.controller('mainController', function ($rootScope, $location) {
$rootScope.$on('$routeChangeError', function (event, current, previous, rejection) {
$rootScope.error = rejection;
});
})
.controller('detailsController', function ($scope, id) {
$scope.id = id;
});
index.html
<div class="container-fluid">
<div class="row">
<div class="col xs-10 col-xs-offset-1" ng-controller="mainController" ng-view>
</div>
</div>
</div>
details.html
<h3>{{id}}</h3>
<h3>{{error}}</h3>
The problem is when I have valid url id is printed on the screen, but when I change id to bad value on the screen I see printed id and the error (it seems that $scope.id is saved and it's all time in memory). Second problem is when I have for example bad url I see error on the screen but when I press F5 and the page "reload" route doesn't change so i see white screen without any error (because route is the same and routeChangeError event isn't fired...).

could not modify view after calling ajax from controller using a factory

I have a demo app through which I want to display all countries data in a page(view) using angularjs.
Here is my code:
MyApp.js
var app = angular.module("MyApp", [ 'ui.bootstrap',
'ngRoute',
'MyControllers',
'MyFactory' ]);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/home', {
controller: 'MyController',
templateUrl: 'resources/modules/homeView/homeView.jsp'
})
.when('/view1', {
controller: 'MyController',
templateUrl: 'resources/modules/view1/view1.jsp'
})
.when('/view2', {
controller: 'MyController',
templateUrl: 'resources/modules/view2/view2.jsp'
})
.otherwise({redirectTo: '/home'});
}]);
MyControllers.js
var controllers = angular.module('MyControllers', []);
controllers.controller('MyController', ['$scope', 'Factory',
function($scope, Factory) {
$scope.countries = [];
$scope.showme = false;
$scope.CountryDetailsClick = function() {
var responsePromise = Factory
.getResponse("http://localhost:12345/DemoNew/getCountryList");
responsePromise.success(function(data, status, headers,
config) {
$scope.countries = data;
console.log("countryList size = " + $scope.countries.length);
$scope.showme = true;
});
responsePromise.error(function(data, status, headers,
config) {
alert("AJAX failed");
});
}
}]);
MyFactory.js
var myFactory = angular.module('MyFactory', []);
myFactory.factory('Factory', function($http) {
return {
getResponse : function(url) {
return $http.get(url);
}
}
});
View1.jsp
<body ng-view>
<h1 class="page-header">View1</h1>
{{countries.length}}
</body>
View2.jsp
<body ng-view>
<h1 class="page-header">View2</h1>
{{showme}}
</body>
homeView.jsp
<body ng-view>
<h1 class="page-header">Home</h1>
index.jsp
<body ng-app="MyApp" ng-controller="MyController">
<nav class="navbar navbar-default navbar-static-top" role="navigation"
style="margin-bottom: 0">
Country Details
Country Rate Plans
</nav>
<div id="page-wrapper" ng-view>
</div>
</body>
Now I am getting on console as :-
countryList size = 268
which is correct, I am using spring for backend. I am able to fetch data from the database.
But in View1 I get:
0
Also in View2 I get:
false
That means I am not able to reflect the fetched data to the view. Please help :(
===============================================================
After suggestions given by rob, i changed the following:
I changed my MyFactory.js to:
var myFactory = angular.module('MyFactory', []);
myFactory.factory('Factory', function($http) {
var current = {};
var factory = {
getResponse: function(urlReq){
var data = $http({method: 'GET', url: urlReq}).then(function (result){
current = result.data;
}, function (result){
alert("ERROR: No data returned");
});
},
getList: function(){
return current;
}
}
return factory;
});
And MyControllers.js to:
var controllers = angular.module('MyControllers', []);
controllers.controller('MyController',
function($scope, Factory) {
$scope.CountryDetailsClick = function() {
Factory.getResponse("http://localhost:12345/DemoNew/getCountryList");
}
});
controllers.controller('MyController3',
function($scope, Factory) {
console.log("in controller3");
});
controllers.controller('MyController2',
function($scope, Factory) {
console.log("in controller2");
$scope.countries = Factory.getList();
$scope.showme = true;
});
MyApp.js
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/home', {
controller: 'MyController',
templateUrl: 'resources/modules/homeView/homeView.jsp'
})
.when('/view1', {
controller: 'MyController3',
templateUrl: 'resources/modules/view1/view1.jsp'
})
.when('/view2', {
controller: 'MyController2',
templateUrl: 'resources/modules/view2/view2.jsp'
})
.otherwise({redirectTo: '/home'});
}]);
View2.jsp
<body ng-view>
<h1 class="page-header">View2</h1>
{{showme}}
{{countries}}
</body>
When I click on Country Details, I get "true" and an empty array, but when I click Country Details after clicking Country Rate Plans, it works perfectly fine.
Please find the flaw.!!
You are using the same controller from index.jsp and from your views. So Angular is creating two instances of your controller each with it's own scope. You are calling CountryDetailsClick() from the ng-controller in index.jsp's scope but you are trying to show the value of countries.length from the view's scope.
If you want to share some functionality or state between different controllers (e.g. your CountryDetailsClick() function) then put it in a service.

How to display single alert from multiple controllers with UI Bootstrap Alert

I am using UI Router and UI Bootstrap in my Angular app. I'd like to use a service so that I can display alert messages from various controllers. I want the alert to display at the top of the screen. Any suggestions on how to modify the code below so that the alert will display at the top of the page and display messages from different controllers?
I'm using this Stack Overflow post as a model.
HTML:
<alert ng-repeat="alert in allInfos()" type="{{alert.type}}" close="closeAlert($index)"
ng-cloak>{{alert.msg}}</alert>
Service:
.factory('Informer', function(){
var messages = [];
var Informer = {};
Informer.inform = function(msg, type) {
messages.push({
msg: msg,
type: type
});
};
Informer.allInfos = function() {
return messages;
};
Informer.remove = function(info) {
messages.splice(messages.indexOf(info), 1);
};
return Informer;
})
Controller:
.controller('PaymentFormCtrl',
function ($scope, $http, Informer) {
$scope.handleStripe = function () {
Informer.inform("There was a problem authorizing your card.", "danger");
$scope.messages = 'problem';
$scope.allInfos = Informer.allInfos;
$scope.remove = Informer.remove;
}
};
});
.controller('ContactFormCtrl',
function ($scope, $http, Informer) {
//. . .
Informer.inform("There is already an account with that email address", "danger");
$scope.messages = 'problem';
$scope.allInfos = Informer.allInfos;
$scope.remove = Informer.remove;
}
};
});
Routers:
.state('home', {
url: '/',
views: {
'top': {
templateUrl: 'views/bigHero.html'
},
'bottom': {
templateUrl: 'views/home.html',
controller: 'HomeCtrl'
}
}
})
.state('payment', {
url: '/payment',
views: {
'top': {
templateUrl: 'views/customerinfo.html',
controller: 'ContactFormCtrl'
},
'bottom': {
templateUrl: 'views/creditcard.html',
controller: 'PaymentFormCtrl'
},
}
});
});
You really have three good options that I can think of off the top of my head.
Create a global or what i like to call a "RootController" of your application bound higher up in your DOM so that the other controllers scope naturally extends it. i.e.:
<div ng-controller="RootController">
<div ui-view></div>
</div>
You can create a parent state with UI Router that both your child states inherit, giving a similar effect to the case above:
$stateProvider.state('parent', {controller: 'ParentController'});
$stateProvider.state('parent.child1', {controller: 'Child1Controller'});
$stateProvider.state('parent.child2', {controller: 'Child2Controller'});
You can pass all shared functionality through a service, which acts as an error message to your necessary controllers.
myService.service('errorService', function() {
this.errorMessage = 'Everything is happy!';
});
myService.controller('PaymentFormCtrl', function($scope, errorService) {
$scope.errorService = errorService;
$scope.setError = function() {
errorService.errorMessage = 'An error happened!';
};
});

angularjs nested detail view doesn't get displayed

the stateProvider of my app have a nested view (base.gallery -> base.gallery.detail) and if i click on a link inside my gallery it should show the detailview, but it doesn't...
the link looks good for me, but it only changes the url in the browser and it logs "get displayed" from the onEnter-function, but it doesn't display the template("modules/album/detail/view/detail.html") in my ui-view...
e.g.: for my link <a ui-sref="base.photos.detail(params(item.id))" class="list-item-link" href="/gallery/21/detail/457">
.state("base", {
abstract: true,
templateUrl: 'modules/base/views/base.html',
controller: function($scope, navigationData){
$scope.navigation.data = navigationData;
},
resolve:{
navigationData:function(navigationSvc){
var response = navigationSvc;
return response;
}
}
})
.state("base.categories", {
url: "/categories",
templateUrl: "modules/album/list/view/list.html",
controller: function($scope, data){
$scope.settings.data = data;
$scope.settings.type = "categories";
},
resolve:{
data:function(listSvc){
var response = listSvc.load("categories");
return response;
}
}
})
.state("base.category", {
url: "/category/:id",
templateUrl: "modules/album/list/view/list.html",
controller: function($scope, data){
$scope.settings.data = data;
$scope.settings.type = "galleries";
},
resolve:{
data:function($stateParams, listSvc){
var response = listSvc.load("category/"+$stateParams.id);
return response;
}
},
})
.state("base.gallery", {
url: "/gallery/:id",
templateUrl: "modules/album/list/view/list.html",
controller: function($scope, data, $stateParams){
$scope.settings.data = data;
$scope.settings.type = "photos";
},
resolve:{
data:function($stateParams, listSvc){
var response = listSvc.load("gallery/"+$stateParams.id);
return response;
}
}
})
.state("base.gallery.detail", {
url: "/detail/:photo_id",
templateUrl: "modules/album/detail/view/detail.html",
controller: function($scope, $stateParams){
console.log("doesn't get displayed ");
$scope.settings.type = "photo";
},
onEnter: function(){
console.log("get displayed");
}
})
html of my index where i load all my lists and i als want to display my detail view inside that ui-view...
...
<div class="content" ui-view></div>
...
html of my list view
<li class="list-item" ng-repeat="item in list.data">
<a ui-sref="{{state}}(params(item.id))" class="list-item-link">item.title</a>
</li>
UPDATE
k i got it ;) i need views and then use the # to target it in the same ui-view from my index.html
.state("base.gallery.detail", {
url: "/detail/:photo_id",
views:{
"#" : {
controller: function($scope, $stateParams, listSvc){
$scope.settings = {};
$scope.settings.type = "photos";
$scope.photo = listSvc.data[$stateParams.id_photo-1];
console.log($stateParams);
},
template: "<h2>detail</2><div>{{photo.title}}</div>"
}
});

Resources