KevInSol
KevInSol

Reputation: 2610

Ionic / Angular ui-router -a href's returning wrong URL/content

I have an Ionic tab menu which shows 4 items (the code below and codepen just have 2 items for clarity) and a "more" item which leads to further menu choices displayed as a list in an ion-content. It uses the Angular ui-router. I have two possibly connected issues.

Issue 1: at first the app appears to be working correctly but as you start to navigate around a few links (generally after visiting "more", the tabs will start to return incorrect URLS. For example:

Stating at News > Contact > More > Sports > Contacts > News > More - breaks here, I see Contacts content instead of More content.

I've add a console.log into each controller and in Chrome dev tools console, I can see that each tab click seems to lunch an extra event, e.g. clicking news tab means 'news' appears twice in the console. In addition, in the nav example above, the console shows that the contacts controller was launched when I clicked More.

So to summarise, after some clicks around the app, the href targets seem to be sending me to the wrong place, like as if one had edited the code while it is running.

Issue 2: Up until the point where the nav breaks as described above, the back button works correctly for pages launched from the tabs, but for the pages launched from the "more" page (ie from the list) there is no back button.

Sorry for all these beginner questions!

Codepen : http://codepen.io/anon/pen/hBpfa

Index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">


    <script src="lib/ionic/js/ionic.bundle.js"></script>
    <script src="js/app.js"></script>
    </head>
  <body ng-app="schoolApp"  animation="slide-left-right-ios7">

    <ion-nav-bar class="bar-stable nav-title-slide-ios7 bar-positive">
      <ion-nav-back-button class="button-icon icon  ion-ios7-arrow-back">
        Back
      </ion-nav-back-button>
    </ion-nav-bar>

    <ion-nav-view></ion-nav-view>

  <script id="tabs.html" type="text/ng-template">
  <ion-tabs class="tabs-icon-top">

    <ion-tab title="News" icon="icon ion-ios7-paper-outline SS-tab-icon" href="#/tab/news">
      <ion-nav-view></ion-nav-view>
    </ion-tab>

    <ion-tab title="Contact" icon="icon ion-ios7-telephone SS-tab-icon" href="#/tab/contact">
      <ion-nav-view></ion-nav-view>
    </ion-tab>

    <ion-tab title="More" icon="icon ion-navicon-round SS-tab-icon" href="#/tab/more">
      <ion-nav-view></ion-nav-view>
    </ion-tab>

  </ion-tabs>
  </script>

  <script id="more_tab_contents.html" type="text/ng-template">
  <ion-view title="{{title}}">
    <ion-content class="has-header padding">

      <div class="list">
        <a nav-clear class="item item-icon-left" href="#tab/info">
          <i class="icon ion-ios7-information SS-tab-icon"></i>
          Information
        </a>
        <a nav-clear class="item item-icon-left" href="#tab/pictures">
          <i class="icon ion-camera SS-tab-icon"></i>
          Pictures
        </a>
        <a nav-clear class="item item-icon-left" href="#tab/sport">
          <i class="icon ion-ios7-football-outline SS-tab-icon"></i>
          Sports
        </a>
      </div>
    </ion-content>

  </ion-view>
  </script>

  <script id="inside.html" type="text/ng-template">
    <ion-view title="{{title}}">
      <ion-content class="has-header padding">
           <div class="SS_inside_content">
              <h1>{{title}}</h1>

              <ol>
              <li>In faucibus condimentum libero, vel iaculis nibh tristique ac. Nunc vitae urna felis. Praesent lectus ligula, vulputate id dolor at, porttitor pretium nulla. </li>
             <li>In faucibus condimentum libero, vel iaculis nibh tristique ac. Nunc vitae urna felis. Praesent lectus ligula, vulputate id dolor at, porttitor pretium nulla. </li>
             <li>In faucibus condimentum libero, vel iaculis nibh tristique ac. Nunc vitae urna felis. Praesent lectus ligula, vulputate id dolor at, porttitor pretium nulla. </li>
              <li>In faucibus condimentum libero, vel iaculis nibh tristique ac. Nunc vitae urna felis. Praesent lectus ligula, vulputate id dolor at, porttitor pretium nulla. </li>
             <li>In faucibus condimentum libero, vel iaculis nibh tristique ac. Nunc vitae urna felis. Praesent lectus ligula, vulputate id dolor at, porttitor pretium nulla. </li>
             <li>In faucibus condimentum libero, vel iaculis nibh tristique ac. Nunc vitae urna felis. Praesent lectus ligula, vulputate id dolor at, porttitor pretium nulla. </li>
              <li>In faucibus condimentum libero, vel iaculis nibh tristique ac. Nunc vitae urna felis. Praesent lectus ligula, vulputate id dolor at, porttitor pretium nulla. </li>
               </ol>
         </div>
     </ion-content>
    </ion-view>
  </script>

  <script id="" type="text/ng-template">
  </script>

  </body>
</html>

App.js:

var schoolApp = angular.module('schoolApp', ['ionic'])



schoolApp.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider


   // setup an abstract state for the tabs directive
    .state('tab', {
      url: "/tab",
      abstract: true,
      templateUrl: "tabs.html"
    })

   .state('tab.news', {
      url: '/news',
      templateUrl: 'inside.html',
      controller: 'newsCtrl'
    })


   .state('tab.contact', {
      url: '/contact',
      templateUrl: 'inside.html',
      controller: 'contactCtrl'
    })



 .state('tab.info', {
      url: '/info',
      templateUrl: 'inside.html',
      controller: 'infoCtrl'
    })


.state('tab.pictures', {
      url: '/pictures',
      templateUrl: 'inside.html',
      controller: 'picturesCtrl'
    })

.state('tab.sport', {
      url: '/sport',
      templateUrl: 'inside.html',
      controller: 'sportCtrl'
    })


.state('tab.more', {
      url: '/more',
      templateUrl: 'more_tab_contents.html',
      controller: 'moreCtrl'
    })

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/news');

});



schoolApp.controller('infoCtrl', function($scope) {
  $scope.title="Information";
  console.log ( 'info' );
})



schoolApp.controller('newsCtrl', function($scope) {
  $scope.title="Latest News";
  console.log ( 'news' );
})



schoolApp.controller('contactCtrl', function($scope) {
  $scope.title="Contacts";
  console.log ( 'contact' );
})



schoolApp.controller('picturesCtrl', function($scope) {
  $scope.title="Pictures";
  console.log ( 'pics' );
})
schoolApp.controller('sportCtrl', function($scope) {
  $scope.title="Sports";
  console.log ( 'sport' );
})

schoolApp.controller('moreCtrl', function($scope) {
  $scope.title="Further content choices";
  console.log ( 'more' );
});

Update

Further to discussions with @SjoerdDeWit and looking at the Ionic codepen examples, I have reverted to using named views, which I had done before. However before I was loading my "more" content into the tab view for News - now I'm loading everything from the more page, and the pages it links to, into the named view for that tab - I think this is the way Ionic intend it to be done. So, as you click/tap "more" you get extra menu choices, the choose them and all the time you are still within the more tab, it is still active. Is this the way it should be?

One thing I notice. if I go to 'more', then 'sport' (within more) - then go to one of the other tabs, then back to more, I get sport, then tap more again and get the more menu options.

A log on each state controller shows (for a different sequence than above but same idea):

news named_views.js:96 (Launch of app)
contact named_views.js:100
more named_views.js:104
more > pics named_views.js:114
news named_views.js:96
more > pics named_views.js:114 FIRST TAP OF MORE - REVISIT IT
more named_views.js:104 TAP IT AGAIN

Revised index.html - just updates shown

  <script id="tabs.html" type="text/ng-template">
  <ion-tabs class="tabs-icon-top">

    <ion-tab title="News" icon="icon ion-ios7-paper-outline SS-tab-icon" ui-sref="tab.news">
        <ion-nav-view name="news-tab"></ion-nav-view>
    </ion-tab>

    <ion-tab title="Contact" icon="icon ion-ios7-telephone SS-tab-icon" ui-sref="tab.contact">
      <ion-nav-view name="contact-tab"></ion-nav-view>
    </ion-tab>

    <ion-tab title="More" icon="icon ion-navicon-round SS-tab-icon" ui-sref="tab.more">
      <ion-nav-view name="more-tab"></ion-nav-view>
    </ion-tab>

  </ion-tabs>
  </script>

  <script id="more_tab_contents.html" type="text/ng-template">
  <ion-view title="{{title}}">
    <ion-content class="has-header padding">

      <div class="list">
        <a nav-clear class="item item-icon-left" ui-sref="tab.info">
          <i class="icon ion-ios7-information SS-tab-icon"></i>
          Information ui-sref
        </a>
        <a nav-clear class="item item-icon-left" ui-sref="tab.pictures">
          <i class="icon ion-camera SS-tab-icon"></i>
          Pictures
        </a>
        <a nav-clear class="item item-icon-left" ui-sref="tab.sport">
          <i class="icon ion-ios7-football-outline SS-tab-icon"></i>
          Sports
        </a>
      </div>
    </ion-content>

  </ion-view>
  </script>

Revised javascript:

var schoolApp = angular.module('schoolApp', ['ionic'])



schoolApp.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider

   // setup an abstract state for the tabs directive
    .state('tab', {
      url: "/tab",
      abstract: true,
      templateUrl: "tabs.html"
    })


   .state('tab.news', {
      url: '/news',
      views: {
        'news-tab': {
          templateUrl: 'inside.html',
          controller: 'newsCtrl'
        }
      }
    })



   .state('tab.contact', {
      url: '/contact',
      views: {
        'contact-tab': {
          templateUrl: 'inside.html',
          controller: 'contactCtrl'
        }
      }
    })



   .state('tab.more', {
      url: '/more',
      views: {
        'more-tab': {
          templateUrl: 'more_tab_contents.html',
          controller: 'moreCtrl'
        }
      }
    })




 .state('tab.info', {
      url: '/info',
      views: {
        'more-tab': {
          templateUrl: 'inside.html',
          controller: 'infoCtrl'
         }
      }
    })



.state('tab.pictures', {
      url: '/pictures',
      views: {
        'more-tab': {
          templateUrl: 'inside.html',
          controller: 'picturesCtrl'
         }
      }
    })

.state('tab.sport', {
      url: '/sport',
      views: {
        'more-tab': {
          templateUrl: 'inside.html',
          controller: 'sportCtrl'
         }
      }
    });


  $urlRouterProvider.otherwise('/tab/news');

}); // end config




schoolApp.controller('newsCtrl', function($scope) {
  $scope.title="Latest news";
  console.log('news');
})
schoolApp.controller('contactCtrl', function($scope) {
  $scope.title="Contact us";
  console.log('contact');
})
schoolApp.controller('moreCtrl', function($scope) {
  $scope.title="More (tabs overflow)";
  console.log('more');
})

schoolApp.controller('infoCtrl', function($scope) {
  $scope.title="Information";
  console.log('more > info');
})

schoolApp.controller('picturesCtrl', function($scope) {
  $scope.title="pictures";
  console.log('more > pics');
})
schoolApp.controller('sportCtrl', function($scope) {
  $scope.title="Sports";
  console.log('more > sports');
});

Upvotes: 3

Views: 8290

Answers (2)

KevInSol
KevInSol

Reputation: 2610

I have resolved these issues (and in doing so have other questions but that will be for another time)

Issue 1 - click/tap tab and getting incorrect content. Fixed with changes made above below the Update

Issue 2 - back nav not appearing in some places, see this:

<a nav-clear class="item item-icon-left" href="#tab/info">
  <i class="icon ion-ios7-information SS-tab-icon"></i>
  Information
</a>

nav-clear was stopping back button, as it should - I must have copied 'n' pasted it from some sample code

Upvotes: 1

Sjoerd de Wit
Sjoerd de Wit

Reputation: 2413

Angular and Ionic use the UI-Router. Instead of using an href attribute you should use the ui-sref followed by the state u want to go too. i've remade your footer tabs with the correct way of routing in Ionic and Angular

<ion-tabs class="tabs-icon-top">

<ion-tab title="News" icon="icon ion-ios7-paper-outline SS-tab-icon" ui-sref="tab.news">
  <ion-nav-view name="news"></ion-nav-view>
</ion-tab>

<ion-tab title="Contact" icon="icon ion-ios7-telephone SS-tab-icon" ui-sref="tab.contact">
  <ion-nav-view name="contact"></ion-nav-view>
</ion-tab>

<ion-tab title="More" icon="icon ion-navicon-round SS-tab-icon" ui-sref="tab.more">
  <ion-nav-view name="more"></ion-nav-view>
</ion-tab>

You do not specify the views. so when you click on news > contact contact is loaded into the news ionview that is located in the ion-tabs if u set it up like this with the names and change your app.js to this you should be oke, although if i'm not mistaken the back button doesn't show up anymore cause the link is present in the tabs

 .state('tab.news', {
      url: '/news',
      views: {
                'news': 
            { 
                    templateUrl: 'inside.html',
                    controller: 'newsCtrl', 
            }
        }
    })


   .state('tab.contact', {
      url: '/contact',
      views: {
                'contact': 
            { 
                    templateUrl: 'inside.html',
                    controller: 'contactCtrl',  
            }
      }
    })



 .state('tab.more', {
      url: '/more',
      views: {
                'more': 
            { 
                    templateUrl: 'inside.html',
                    controller: 'infoCtrl', 
            }
      }   

})

Upvotes: 5

Related Questions