angularjs nested detail view doesn't get displayed - angularjs

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>"
}
});

Related

var vm = this, making $http request twice

Here is my controller code:
.controller('TransitCtrl', function ($ionicPlatform, $scope, $state, $q, $ionicSideMenuDelegate, $timeout, $http, design, config) {
$ionicSideMenuDelegate.canDragContent(false);
var vm = this;
vm.userImg = design.user_img;
vm.isGetStarted = false;
vm.getPV = true;
vm.getPL = false;
vm.showWelcome = false;
var counter = 1;
$ionicPlatform.ready(function(){
$timeout( function(){
var userDataStageFirst = {
url: config.baseURL + 'userDataStageFirst',
dataServer: {
serverTaskRequest: counter
}
}
var url = userDataStageFirst.url;
var dataServer = userDataStageFirst.dataServer;
$http.post(url, dataServer).success(function (data, status, headers, config) {
alert(data)
})
.error(function () {
alert("error");
});
}, 1000 );
});
})
And here is this app.js
.state('app.transit', {
url: '/transit',
views: {
'menuContent': {
templateUrl: 'templates/transit.html',
controller: 'TransitCtrl'
}
}
})
and My html page
<ion-view hide-nav-bar="true" ng-controller="TransitCtrl as vm">
<ion-content>
hello world
</ion-content>
</ion-view>
When I use $scope in place of vm its working perfectly good, but when I use vm, it sends 2 $http request to the server. Not being able to understand this concept here.
Try remove ng-controller="TransitCtrl as vm" from template.
and change to this
state('app.transit', {
url: '/transit',
views: {
'menuContent': {
templateUrl: 'templates/transit.html',
controller: 'TransitCtrl as vm'
}
}
})

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

$urlRouterProvider.otherwise doesn't recognize $cordovaSQLite.execute(db, query, []) in a function of a controller

I have a state in my app.js :
.state('app.kamus', {
url: '/kamus',
views: {
'menuContent': {
templateUrl: 'templates/kamus.html',
controller: 'Kamus1Ctrl'
}
}
})
...
and :
$urlRouterProvider.otherwise('/app/kamus');
controller :
.controller('Kamus1Ctrl', function($scope, $cordovaSQLite, $ionicLoading, $stateParams, $timeout) {
$ionicLoading.show({
content: 'Loading',
animation: 'fade-in',
showBackdrop: true,
maxWidth: 200,
showDelay: 0
});
$scope.selectAll = function() {
$scope.datas = [];
var query = "SELECT * FROM data";
$cordovaSQLite.execute(db, query, []).then(function(res) {
$scope.datas = [];
if (res.rows.length > 0) {
for (var i = 0; i < res.rows.length; i++) {
$scope.datas.push(res.rows.item(i));
}
} else {
console.log("No results found");
}
}).finally(function() {
$ionicLoading.hide();
});
}
$scope.selectAll();
})
I direct the $urlRouterProvider.otherwise to /app/kamus to show kamus page in first launch of my application. But it seems $urlRouterProvider.otherwise is failed to execute $cordovaSQLite.execute(db, query, []) in my selectAll() function on Kamus1Ctrl.
But when I use other pages as my $urlRouterProvider.otherwise, i.e : $urlRouterProvider.otherwise('app/other'), then I go to /app/kamus via my side menu(button ui-sref="app.kamus"), it just works.
How to fix this problem?
Do like this
Index.html
<body>
<div>
<h3>Index page</h3>
<div ui-view="main"></div>
</div>
</body>
kamus.html
<div ui-view="view1"></div>
Controller
var routerApp = angular.module('routerApp', ['ui.router']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('app');
$stateProvider
.state('app', {
abstract: true,
url: '/app',
views: {
'main': {
templateUrl: 'kamus.html',
controller : 'Kamus1Ctrl'
}
}
})
.state('app.kamus', {
url: '',
views: {
'view1#app': {
template: "Im View1"
}
}
});
});
routerApp.controller('Kamus1Ctrl', function($scope, $cordovaSQLite, $ionicLoading, $stateParams, $timeout) {
alert("Inside controller");
$scope.selectAll = function() {
alert("Inside selectAll");
//rest of the code
}
$scope.selectAll();
})
NOTE: In ui-router dot operator is used for inner states.

Separate nav from ng-view

I'm brand new to Angularjs and am trying to set up a new site but I'm confused as to the set up. I have a module and am using $route to successfully navigate but I'm lost as to what to do with my nav. When I load the module I want to read my database for a list of links that the user is allowed to access then spit them out in the nav. I don't want to repeat this in every view because I don't need to. So I'm trying to figure out how to run the ajax call once and then keep changing the view (I'd also like to add a class .selected to whatever view they're on). How would I go about doing that, with a directive?
(function () {
var app = angular.module('manage', ['ngRoute', 'manageControllers']);
/*
I've tried this but obviously $http isn't injected. Can I even do that?
var thisApp = this;
$http.get('/test/angular/php/angular.php', {params: {'function': 'nav'}}).then(function successCallback(response) {
});
*/
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'templates/dash.html',
controller: 'DashCtrl'
}).
when('/inventory/', {
templateUrl: 'templates/inventory.html',
controller: 'InventoryCtrl'
}).
when('/inventory/:mvKey', {
templateUrl: 'templates/inventory.html',
controller: 'InventoryCtrl'
}).
when('/inventory/:mvKey/:tab', {
templateUrl: 'templates/inventory.html',
controller: 'InventoryCtrl'
}).
/* etc...*/
}
]);
})();
EDIT:
My attempt at getting the nav to run once
controllers.js
var manageControllers = angular.module('manageControllers', []);
var thisApp = this;
nav = null;
navSelected = '/';
manageControllers.controller('NavCtrl', ['$scope', '$http', function($scope, $http) {
if (thisApp.nav === null) {
$http.get('php/angular.php', {params: {'function': 'nav'}}).then(function successCallback(response) {
console.log(response.data);
thisApp.nav = response.data;
$scope.nav = thisApp.nav;
$scope.select = thisApp.navSelected;
});
} else {
$scope.nav = thisApp.nav;
$scope.select = thisApp.navSelected;
}
}]);
manageControllers.controller('DashCtrl', ['$scope', function($scope) {
thisApp.navSelected = '/';
}]);
I would swith to UI Router (https://github.com/angular-ui/ui-router) instead of $route. It allows you being much more flexible with your routing.
A Small example:
app.config(['$stateProvider',
function($stateProvider) {
$stateProvider.
state('/', {
url: '/',
views: {
'': {
templateUrl: 'templates/dash.html',
controller: 'DashCtrl'
},
'nav#': {
templateUrl: 'path/to/nav.html',
controller: 'NavCtrl'
},
}
}).
state('/inventory/', {
url: '/',
views: {
'': {
templateUrl: 'templates/dash.html',
controller: 'DashCtrl'
},
'nav#': {
templateUrl: 'path/to/nav.html',
controller: 'NavCtrl'
},
}
}).
// ...
and in your index.html
<div ui-view="nav"></div>
<div ui-view ></div>
Take a closer look at UI Router's doc, there's much more you can do with it!

Nested template routes in ui.router

(AngularJS v1.2.28 - angular-ui-router v0.2.13
In my index.html I have the following:
<div class="wrapper" ui-view></div>
In my app.js I have my stateProvider set up as:
$urlRouterProvider.otherwise('/app/search');
$stateProvider.state("app", {
url: '/home',
controller: 'MainCtrl',
templateUrl: 'views/main.html'
}).state('app.search', {
resolve: {
categories: function ($q, $stateParams, LiveOak) {
var deferred = $q.defer();
LiveOak.readMembers('/liveoak/storage/categories', {
success: function (categories) {
deferred.resolve(categories);
},
error: function (error) {
console.error(error);
}
});
return deferred.promise;
}
},
url: '/search',
templateUrl: 'views/search.html',
controller: 'SearchCtrl'
}
).state('app.subjects', {
url: '/subjects/:id',
abstract:true,
templateUrl: '<ui-view/>'
}
).state('app.subjects.default', {
resolve: {
subjects: function ($q, $stateParams, LiveOak) {
var deferred = $q.defer();
var categoryId = $stateParams.id;
var query = {
categoryId : categoryId
};
LiveOak.readMembers('/liveoak/storage/subjects', {
query: query,
success: function (subjects) {
console.log("subjects resolved")
deferred.resolve(subjects);
},
error: function (error) {
console.error(error);
}
});
return deferred.promise;
},
instructors: function ($q, $stateParams, LiveOak) {
}
},
url: '',
templateUrl: 'views/subject.html',
controller: 'SubjectCtrl'
}).state('app.subjects.authors', { //THIS IS NOT RECOGNIZED
resolve: {
authors: function ($q, $stateParams, LiveOak) {
var deferred = $q.defer();
var subjectId = $stateParams.id;
var query = {
query.subjectId : subjectId
};
LiveOak.readMembers('/liveoak/storage/authors', {
query: query,
success: function (authors) {
deferred.resolve(authors);
},
error: function (error) {
console.error(error);
}
}
);
return deferred.promise;
}
},
url: '/subjects/:id/authors/',
templateUrl: '../views/subjects.authors.html',
controller: 'AuthorsCtrl'
}
);
}]);
I am wrestling with the state: app.subjects.authors. Right now app.search and app.subjects work. However, when I try to go the the state: app.subjects.authors it is not even recognized. I set up up a state app.subject as abstract, so hopefully app.subjects.authors wouldn't be overridden by app.subjects. Anyone see anything out of the ordinary?
Thanks for the help!!
My subject.html looks like this:
<div ng-repeat="subject in subjects" class="mdl-cell mdl-cell--4-col">
<a href="#/app/subjects/{{subject.categoryId}}/authors">
<span>{{subject.name}}</span>
</a>
</div>
Just change templateUrl: to template:. You don't need abstract:.
.state('app.subjects', {
url: '/subjects/:id',
template: '<ui-view/>'
})
You shall have:
url: '/authors',
Instead of:
url: '/subjects/:id/authors/',
Because url is relative. So the url of child state is continuation of parent state's url. So authors state will match following url:
/home/subjects/:id/authors

Resources