2

When clicking on a link, I can pass data to another page:

<div ng-repeat="app in apps | filter:{Name: searchText}" class="slide">
    <a href="#/app/{{app.Name}}">{{app.Name}} {{app.Version}}</a>
</div>

When the new page comes up, I see the app's name:

enter image description here

This is the markup to display the name:

<p>{{appName}}</p>

However, if I want to pass the ID, like this:

<div ng-repeat="app in apps | filter:{Name: searchText}" class="slide">
    <a href="#/app/{{app.Id}}">{{app.Name}} {{app.Version}}</a>
</div>

That doesn't work. When I click on the ID, nothing happens in the browser. There is no error in the F12 tools console window. And Fiddler shows no activity. I think it's because the ID has a slash in it (this is a RavenDB convention). This is what I see when I hover over the link:

enter image description here

Notice the last slash. I think that's messing things up.

So I tried a stackoverflow solution to escape the slash. Now when I hover, I see this:

enter image description here

I thought that would have done it, but I'm back to the same behavior: nothing happens when I click on it. Nothing in Fiddler either. What am I missing? (If I change the markup to pass the Name property again, things work. So the wiring is good.)

Edit

I just realized that it's not that nothing is happening. My route provider is kicking in and taking me back to the same page that I'm already on:

$routeProvider.otherwise({ redirectTo: '/apps' });

And this is the entire routing config:

app.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/apps', { templateUrl: 'partials/apps.html', controller: 'appsController' });
    $routeProvider.when('/servers', { templateUrl: 'partials/servers.html', controller: 'serversController' });
    $routeProvider.when('/app/:appId?', { templateUrl: 'partials/app.html', controller: 'appController' });
    $routeProvider.otherwise({ redirectTo: '/apps' });
}]);

Workaround

Setting a route like this allows me to hit the right page. The only issue is that I need to prefix the number part of the ID (on the receiving page) with the literal "applications/". I guess I can do that.

$routeProvider.when('/app/applications/:appId?', { templateUrl: 'partials/app.html', controller: 'appController' });

For completeness, this is what I had to do in the receiving controller:

.controller('appController', function ($scope, $routeParams) {

      $scope.appId = "applications/" + $routeParams.appId;
})
Community
  • 1
  • 1
Bob Horn
  • 33,387
  • 34
  • 113
  • 219
  • Maybe you just need to define another route that matches the URL w/the app ID... It's hard to say unless you show us the "$routeProvider.when()" statements that you call/declare in your app ;) – Sunil D. Aug 19 '14 at 02:18
  • I just added that to my post. I also used your workaround. If no one has an actual way to pass the entire string with the slash in it, I'd be happy to accept your answer. Thanks! – Bob Horn Aug 19 '14 at 12:23

1 Answers1

3

This fiddle reproduces you problem. It is a small application which has 2 routes: /apps and /app/:appId. If the /app/:appId route is taken, the page displays Hello, {{appId}}, otherwise it displays Hello, apps. In the startup method (run), I've added a hard-coded redirect to '/app/applications%2F1121' using $location.path. As you can see, changing the route using $location.path('/app/applications%2F1121') works well: the application starts and gives us the right ID: Hello, applications/1121. However, changing the route using a href doesn't work: if you click the link, the app displays Hello, apps, meaning the /apps route was taken after the /app/applications%2F1122 url found in the link was not recognized.

Therefore, another workaround is to always use $location.path to change routes. Put this function in your $routeScope and use ng-click to call it (fiddle).

.run(function ($rootScope, $location) {
    $rootScope.go = $location.path.bind($location);
})

<a ng-click="go('/app/applications%2F1122')" href="">

Escaping the slash is still required, but this workaround does not require you to change your route configuration, so it can handle any ID.

Hugo Wood
  • 2,140
  • 15
  • 19
  • I'm trying to understand how this is wired together. Why would the `run` function have a hard-coded path? And when I clicked on the `App 1122` link, I see this: `Hello, apps`. I was hoping I'd see `Hello, applications/1122`. No? – Bob Horn Aug 19 '14 at 17:33
  • There are two fiddles in my answer. [The first one](http://jsfiddle.net/t9hdjbp9/1/) has your issue so when you click on the link, the `$routeProvider` doesn't recognize the route and redirects you to `/apps` and you `Hello, apps`. The [second one](http://jsfiddle.net/t9hdjbp9/2/) works fine so when you click the link, you will see `Hello, applications/1122`. – Hugo Wood Aug 19 '14 at 17:51
  • The hard-coded path in `run` is there just to test if changing the route with `$location.path` works or not. The fact that the page displays `Hello, applications/1121` proves that it works. – Hugo Wood Aug 19 '14 at 17:52
  • I've updated my answer to explain a little bit more how the fiddle's app works. – Hugo Wood Aug 19 '14 at 18:03
  • I think I'm close. The problem is that I see `{{app.Id | escape}}` on the receiving page. I'm assuming that's because it's treated as a literal due to this HTML: `ng-click="go('/app/{{app.Id | escape}}')"`. In your example, you're using the literal ID, but I have to use a variable. Do you know how I get past this part? – Bob Horn Aug 19 '14 at 18:13
  • That's because you pass `'/app/{{app.Id | escape}}'` as a string (see the quotes?). Try `ng-click="gotoApp(app.Id)"` and write a function `gotoApp` that takes care of the escaping and concatenating. New fiddle [here](http://jsfiddle.net/t9hdjbp9/3/). – Hugo Wood Aug 19 '14 at 18:26
  • I got it working. I had to put this in app.run: `$rootScope.gotoApp = function (appId) { $rootScope.go('/app/' + encodeURIComponent(appId)); };` Thanks for the help! – Bob Horn Aug 19 '14 at 20:09