javascriptcssangularjsangular-ui-routermultiple-views

Multiple views for large screens, single view for small screens


I have seen a design interface here, and I liked it.

enter image description here

I was doing it with AngularJS, and ui-router which allows to have multiple views on a single page.

I have an issue for smartphone, because I want to display only one view, not two like tablets/desktops.

Question : What would be the best way to display only one view for small screens, and two for larger screens ?

I had basic ideas :

Idea 1 (not so so good) : I was thinking to create multiple routes, then route to one or the other route depending the screen size.

Inside angular config

app.config(function($stateProvider) {
  $stateProvider
    .state('listForLargeScreens', {
      url: "/listForLargeScreens",
      views: {
        "primary": { templateUrl: "list.html" },
        "secondary": { templateUrl: "detail.html" }
      }
    })
    .state('listForSmallScreens', {
      url: "/listForSmallScreens",
      views: {
        "primary": { templateUrl: "list.html" }
      }
    })
    ...;

Inside a random controller

app.controller('RandomCtrl', function ($scope, $state) {
   $scope.changePage = function () {
       if (isLargeScreen) {
           $state.go('indexForLargeScreens');
       } else {
           $state.go('indexForSmallScreens');
       }
   }
});

Problem : this idea seems to me too "dirty" for maintaining.

Idea 2 : I was thinking to declare primary and secondary views, then I could hide with CSS the secondary one with CSS :

Inside angular config

app.config(function($stateProvider) {
  $stateProvider
    .state('list', {
      url: "/",
      views: {
        "primary": { templateUrl: "list.html" },
        "secondary": { templateUrl: "detail.html" }
      }
    })
    .state('detail', {
      url: "/detail/:id",
      views: {
        "secondary": { templateUrl: "list.html" },
        "primary": { templateUrl: "detail.html" }
      }
    })
    ...;

Inside html

 <div ui-view="main"></div>
 <div ui-view="secondary"></div> <!-- For small screens, hide this view with CSS -->

Problem : different URLS can have the same views, but with inverted priorities, see :

enter image description here

So, on small screens, it could work, but on larger screens, in some URLs, views can be inverted, (see the image above), so in HTML, list.html and detail.html templates will be inverted too.

It could solve the problem if I could invert <div ui-view="primary"></div> and <div ui-view="secondary"></div> on some views...


Solution

  • I've just found on scotch.io a piece of code which is the key for that problem.

    The idea 2 on the question was almost the answer, but I had a problem with different URLs which where using same views, but with inverted priorities.

    ui-router allows with multiple named views, to get ancestors, so I have to create a piece of html which declares ui-views :

    Inside angular config :

    $stateProvider.state('list', {
        url: '/list',
        views: {
            '': { templateUrl: 'partial-list.html' },
            'primary@list': { 
                templateUrl: 'list.html',
                controller: 'ListCtrl as ctrl'
            },
            'secondary@list': { 
                templateUrl: 'detail.html',
                controller: 'DetailCtrl as ctrl'
            }
        }
    }).state('detail', {
        url: '/detail/:id',
        views: {
            '': { templateUrl: 'partial-detail.html' },
            'primary@list': { 
                templateUrl: 'detail.html',
                controller: 'DetailCtrl as ctrl'
            },
            'secondary@list': { 
                templateUrl: 'list.html',
                controller: 'ListCtrl as ctrl'
            }
        }
    });
    

    Inside partial-list.html :

    <div ui-view="primary"></div>
    <div ui-view="secondary" class="hide-it-for-small-screens"></div>
    

    Inside partial-detail.html :

    <div ui-view="secondary" class="hide-it-for-small-screens"></div>
    <div ui-view="primary"></div>
    

    It works ! :)