2013-07-19 26 views
13

Tôi đang sử dụng ng-boilerplate và phải thêm khả năng sử dụng các mẫu khác nhau trong sản xuất, dựa trên cấu hình người dùng.Làm cách nào để thử nghiệm A/B với các mẫu AngularJS?

.config(function config($stateProvider) { 
$stateProvider.state('demo', { 
    url: '/demo', 
    views: { 
     "main": { 
     controller: 'DemoCtrl', 
     templateUrl: 'demo/demo.tpl.html' 
     } 
    } 
    }); 
}) 

ý tưởng hiện tại của tôi là làm cho templateUrl động

templateUrl: 'demo/demo'+userService.getTemplate()+'.tpl.html' 

và có nhiều file mẫu, như:

  • demo.tpl.html (mặc định)
  • demo. b.tpl.html (phiên bản b)
  • demo.c.tpl.html (phiên bản c)

trong khi chức năng userService cung cấp phiên bản mẫu để sử dụng, ví dụ: ".b"

Bạn có đồng ý không? Có cách tiếp cận nào tốt hơn/dễ hơn cho vấn đề này không?

+0

Vâng, dịch vụ có sẵn trong chức năng cấu hình không? –

+1

Bạn nói đúng, đề xuất của tôi thậm chí không hoạt động ... Không tiêm được. –

+0

Dịch vụ người dùng có phải là cổng quản trị kết thúc ở nơi họ "định cấu hình" các tùy chọn mặc định của họ không? Các dữ liệu cần phải được preflight phải không? –

Trả lời

11

AngularJS standard $routeProvider có thể chấp nhận chức năng cho templateUrl. Nhưng bạn không thể tiêm dịch vụ vào chức năng này.

ui-routertemplateProvider tham số vào đó bạn có thể tiêm những gì bạn muốn và bạn nên quay trở lại một cái gì đó như thế này cho mẫu từ xa trường hợp:

$stateProvider.state('demo', { 
    templateProvider: function ($http, $templateCache, $stateParams, userService) { 
     var url = 'demo/demo' + userService.getTemplate() + '.tpl.html'; 
     return $http.get(url, { cache: $templateCache }).then(function (response) { 
      return response.data; 
     }); 
    } 
}) 
1

này có thể đạt được sử dụng tiêu chuẩn góc, bạn chỉ cần nhìn vào nó từ góc độ khác!

Tôi khuyên bạn nên sử dụng $templateCache. Khi bạn tải ứng dụng, bạn có thể điền trước bộ nhớ cache mẫu $ với phiên bản mẫu người dùng đã chọn.

Bạn có thể làm một cái gì đó giống như

$templateCache.put("page-header.html", '<h1>MyAwesomeStartup</h1><h2>Buy now!?!?!</h2>'); 

Ngoài ra nếu bạn không phản đối ý tưởng, bạn có thể đặt mẫu vào trang bằng cách sử dụng cú pháp script tag, nơi id == các templateURL bạn sử dụng trong của bạn $ routeProvider.

<script type="text/ng-template" id="page-header.html"> 
    <h1>MyAwesomeStartup</h1><h2>Buy now!?!?!</h2> 
</script> 

Và ng sẽ tải trực tiếp từ thẻ tập lệnh.

+0

có vẻ hơi khắc nghiệt và không thể quản lý được đối với thử nghiệm a/b. Đây là một khởi hành rất lớn từ cách một "bình thường" viết ng apps – electblake

+0

Đây là một giải pháp rất thú vị! Tôi nghĩ rằng đây là một lựa chọn tuyệt vời để thực hiện thử nghiệm AB một cách kín đáo. – Vatsu1

2

Tôi sẽ không lưu giữ dịch vụ vì dịch vụ sẽ là một phần của tệp js. Mà sẽ là tĩnh (dưới điều kiện bình thường)

Đây là cách tôi sẽ làm điều đó, Trong html tập tin tôi sẽ đưa

window.abConfig = "defaultVersion"; 

Trong app.js tôi sẽ đưa

.config(function config($stateProvider) { 
$stateProvider.state('demo', { 
    url: '/demo', 
    views: { 
     "main": { 
     controller: 'DemoCtrl', 
     templateUrl: function() { 
      return 'demo/demo' + window.abConfig + '.tpl.html'; 
     } 
     } 
    } 
    }); 
}) 

loại của nó của cách Hacky, nhưng nó mang lại cho tôi sự linh hoạt để quyết định phiên bản nào sẽ hiển thị cho người dùng ở cấp độ máy chủ. Tôi có thể yêu cầu viết logic trước khi người dùng tải xuống nội dung dựa trên hoạt động trước đó của người dùng, mà tôi không thể làm từ javascript phía máy khách.

+0

điểm thưởng để khái quát hóa cấu hình – electblake

0

Tôi có một cách khác dựa trên cùng một nguyên tắc

Ngoại trừ việc bạn không phải thực sự yêu cầu chế độ xem với $ http.

Vì vậy, bạn có thể cho phép ui-router xử lý phần đó.

Điều này dễ dàng hơn khi bạn có kiến ​​trúc chế độ xem phức tạp.

.state('public.index', { 
      url: '/', 
      views: { 
       "": { 
        template: '<div ui-view="abTestDummyView"></div>', 
        controller: ['landing', '$http', function(landing, $http) { 
         alert('Showing AB Test Landing #' + landing); 
         // increment landing stats 
         $http.get('http://stats.domain.com', {landing: landing}); 
        }], 
        controllerAs: 'landingCtrl', 
       }, 
       "[email protected]": { 
        templateProvider: ['landing', function(landing) { 
         // inject a view based on its name 
         return "<div ui-view=\"ab" + landing + "\"></div>"; 
        }] 
       }, 
       "[email protected]": { 
        template: "INJECTED AB1" 
        // replace by templateUrl: "/real path/" 
       }, 
       "[email protected]": { 
        template: "INJECTED AB2" 
        // replace by templateUrl: "/real path/" 
       } 
      }, 
      resolve: { 
       landing: function() { 
        return Math.floor((Math.random() * 2) + 1); 
       } 
      } 
     }) 
Các vấn đề liên quan