Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm following the UI-Router Nested States & Nested Views : Abstract State code example from https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views#abstract-states and adapting it to my ExpressJS (Jade template) app.

When I type in http://localhost:3030/#/contacts and press enter, the contacts portion of the URL gets deleted leaving the URL as http://localhost:3030/#/.

But if I add an extra / to the end of the URL like http://localhost:3030/#/contacts/ that will work and I will see

enter image description here

Also, if I go to http://localhost:3030/#/contacts/list then I will see

  1. the contacts.jade template display properly in the ui-view of the layout.jade template
  2. the contacts-list.jade (Alice & Bob) display properly in ui-view of the contacts.jade template

enter image description here

And then if I click on the Alice link I will see

enter image description here

So I'm not sure why I can't access the /contacts URL. Below are all relevant files.


AngularJS / UI-Router

app.js

'use strict';

var app = angular.module('app', ['ui.router']);

app.config([
  '$stateProvider',
  '$urlRouterProvider',
  function($stateProvider, $urlRouterProvider) {

  $urlRouterProvider.otherwise('/');

    $stateProvider
        .state('contacts', {
            abstract: true,
            url: '/contacts',
            templateUrl: '/partials/contacts',
            controller: function($scope){
                $scope.contacts = [{id: 0, name: "Alice"}, {id: 1, name: "Bob"}];
            }
        })
        .state('contacts.list', {
            url: '/list',
            templateUrl: '/partials/contacts-list'
        })
        .state('contacts.detail', {
            url: '/:id',
            templateUrl: '/partials/contacts-detail',
            controller: function($scope, $stateParams){
                $scope.person = $scope.contacts[$stateParams.id];
            }
        })
}]);

Jade templates

index.jade

extends ../views/includes/layout

layout.jade

doctype html 
html
    include head
    body(ng-app='app')
        <div ui-view></div>
        include scripts

contacts.jade

h1 Contacts
<div ui-view></div>

contacts-list.jade

ul
li(ng-repeat="person in contacts")
    a(ng-href="#/contacts/{{person.id}}") {{person.name}}

contacts-detail.jade

h2 {{person.name}}

ExpressJS

server.js

var express = require('express'),
    mongoose = require('mongoose'),
    morgan = require('morgan'),
    bodyParser = require('body-parser'),
    path = require('path');

var env = process.env.NODE_ENV = process.env.NODE_ENV || 'development';

var app = express();


// configuration
app.set('views', path.join(__dirname, '/app/views'));
app.set('view engine', 'jade');
app.use(morgan('dev')); // logs every request to console
app.use(bodyParser()); // pull information from html in POST
app.use(express.static(__dirname + '/public'));

// connect to mongodb via mongoose
if(env === 'development') {
  mongoose.connect('mongodb://localhost/3lf');
} else {
  mongoose.connect('mongodb://maxmythic:[email protected]:33307/3lf');
}

var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error ...'));
db.once('open', function(callback) {
  console.log('3lf db is open for business ...');
});

// create mongoose schema and retrieve data
var messageSchema = mongoose.Schema({message: String});
var Message = mongoose.model('Message', messageSchema);
var mongoMessage;
Message.findOne().exec(function(err, messageDoc){
  mongoMessage = messageDoc.message;
});

// define routes
// make sure to coordinate client side and server side routes
app.get('/partials/:partialPath', function(req, res) {
  res.render('partials/' + req.params.partialPath); 
});

app.get('*', function(req, res) {
  res.render('index', {
    mongoMessage: mongoMessage
  });
});


var port = process.env.PORT || 3030;
app.listen(port);
console.log('Listening on port ' + port + '...');
share|improve this question

1 Answer 1

up vote 1 down vote accepted

You cannot access /contacts url because the state contacts is abstract with abstract: true. Abstract states cannot be explicitly triggered. They are triggered implicitly when path below them are triggered, e.g. contacts will be triggered when contacts.list is accessed. That's why it goes to / when access /contacts, because you specified $urlRouterProvider.otherwise('/') and / is the default value.

When you access /contacts/, you triggered state contact.details with id set to empty string matching path /:id.

share|improve this answer
    
Ok. Thank you very much Alex :) –  s3z Jul 31 '14 at 12:27

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.