0

I am writing a simple UI for a product query. On load the page reveals a list of products from a RESTful API call. It uses ng-repeat to decorate the data and render it in a list. At rendering time, the app checks for mobile. The requirement is that if the user is on a desktop, it will open in a new window. If mobile, new tab. (Please don't debate the merits of new window. That is not negotiable.)

What I need is something to tell the app, when the user clicks on a product for the detail view, whether to render either a new tab or new window.

My questions is whether or not this belongs in a directive? If so, can you describe to me roughly how that would flow?

I'm including the code below. Let me know if you need more code/info to help answer the question.

HTML

<section>
  <div class="headerWrap box-shadow">
    <h2 class="box-shadow">Product Selection</h2>
  </div>
  <ul class="products">
    <li ng-repeat="product in products" class="productPane box-shadow">
        <a ng-show="isMobile" ng-href="#/products/{{product.product_id}}" ng-click="getProduct('mobile')">
            <div class="productMeta box-shadow">
                <img ng-src="{{product.image}}">
                <h3>{{product.name}}</h3>
                <p>{{(product.price/100) | currency: "&euro;" : 2}}</p>
            </div>
        </a>
        <a ng-show="!isMobile" ng-click="getProduct('notMobile')">
            <div class="productMeta box-shadow">
                <img ng-src="{{product.image}}">
                <h3>{{product.name}}</h3>
                <p>{{(product.price/100) | currency: "&euro;" : 2}}</p>
            </div>
        </a>
    </li>
  </ul>
</section>

Controllers

var DemoControllers = angular.module('DemoControllers', []);

DemoControllers.controller('ProductListCtrl', ['$scope', '$http', 'list',
function ($scope, $http, list) {
    list.getList().success(function (data, status, headers, config) {
        $scope.products = data.products;
    });
}]);

DemoControllers.controller('ProductDetailCtrl', ['$scope', '$http', '$routeParams', 'product',
function ($scope, $http, $routeParams, product) {
    $scope.product_id = $routeParams.product_id;
    product.getProduct().success(function (data, status, headers, config) {
        $scope.selected = data; 
    };
}]);

Services

var DemoServices = angular.module('DemoServices', []);

DemoServices.factory('list', ['$http', function ($http) {
  return {
    getList: function () {
        return $http.get('https://s3-eu-west-1.amazonaws.com/developer-application-test/cart/list');
    }
  }
}]);

DemoServices.factory('product', ['$http', function ($http, id) {
  return {
    getProduct: function ($http, id) {
        return $http.get('https://s3-eu-west-1.amazonaws.com/developer-application-test/cart/' + id + '/detail');
    }
  }
}]);
Kraken
  • 5,043
  • 3
  • 25
  • 46

1 Answers1

1

I suppose you could do it in a directive, but the code is so simple and you don't really need to repeat it much, so I am not sure if it makes any difference.

I found some helpful stuff here: Detecting a mobile browser

Here is a plunker demonstrating window size detection and opening a link depending on whether it is of a mobile size or desktop size (the sizing is arbitrary and can be set to whatever you want)

Plunker Demo

The code consists of a simple function that detects the window size:

$scope.check = false;
function detectmob() {
 if(window.innerWidth <= 800 && window.innerHeight <= 600) {
   return true;
 } else {
   return false;
 }
}
$scope.check = detectmob();

Then the function you attach to your ng-click to open the link:

$scope.openLink = function(link){
  if($scope.check) {
      window.open(link, '_blank');
  } else {
      window.open(link, 'new_window', 'toolbars=0,width=400,height=320,left=200,top=200,scrollbars=1,resizable=1')
  }
}

Apparently if you just set the _blank attribute, you are leaving it up to the browser to decide whether to open a new window or tab. In modern browsers, I think the default would usually be a new tab. On mobile, obviously it is going to be a new tab.

If we provide the parameters for creating a new window however, it will create the new window. The new_window parameter is merely a placeholder.

EDIT: So I decided to explore the idea a bit further and I built a directive that encapsulates all the logic into an attribute you can attach to a button. I must say, after playing with it a bit, I much prefer this method.

Here is the code:

app.directive('linkOpener', function() {
  return {
    restrict: 'A',
    scope: {
      theLink: '@'
    },
    link: function(scope, elem, attrs) {
      var theLink

      attrs.$observe('theLink', function(value){
        return theLink = value;
      });

      var check = false;
      function detectmob() {
        if(window.innerWidth <= 800 && window.innerHeight <= 600) {
          return true;
        } else {
          return false;
        }
      }

      check = detectmob();

      var openLink = function(){
        if(check) {
          window.open(theLink, '_blank');
        } else {
          window.open(theLink, 'new_window', 'toolbars=0,width=400,height=320,left=200,top=200,scrollbars=1,resizable=1')
        }
      }
      elem.on('click', openLink);
    }
  }
})

Plunker with controller logic and directive

Community
  • 1
  • 1
tpie
  • 6,021
  • 3
  • 22
  • 41