12

I am looking to use Optimizely on a site where we will use Angularjs, but from what I understand, that will be difficult because the whole purpose of Angularjs is to not manipulate the DOM, and Optimizely works by manipulating the DOM.

Does anyone have any guidance toward documents as to how to make using these tools together possible? Perhaps a structure where I could create directives to help the tool work?

Tyler Riggs
  • 121
  • 1
  • 3
  • 3
    "the whole purpose of AngularJS is to not manipulate the DOM" – huh? I assure you, AngularJS manipulated DOM a lot. – millimoose Feb 20 '14 at 23:25

5 Answers5

2

Yes, but you'll need to use the Optimizely's Javascript API.

http://developers.optimizely.com/javascript/

For anything more in depth you could also look at doing your own bucketing and using custom dimensions

Own Bucketing Example: https://github.com/tomfuertes/gaab

Custom Dimensions Docs: https://support.google.com/analytics/answer/2709829?hl=en

Edit:

On a high level Optimizely is a front end abstraction to a system that buckets and manipulates the DOM. It's meant to be used by non-devs or devs who want to use the reporting piece. You can still get to the same thing if you're custom coding an angular app by writing your own bucketing, splits, and features with a separate analytics tool like GA. Sounds daunting but is fairly simple if you take a look at the gaab sample code above.

TomFuertes
  • 6,855
  • 5
  • 32
  • 48
2

First, you need to make the "Activation Mode" of the experiment "Manual".

Then, to make Optimizely check if the experiment should run (ie meets the URL target) you need to call window.optimizely.push(["activate"]). This tells Optimizely to do the same thing it would do on a normal full page load. So depending on your situation, you can call the optimizely api from a few different locations...

In the run method of the app when views load

This works when what your experiment changes isn't tied to dynamic pieces that angular might make after the view loads. The $routeChangeSuccess event won't work with activating Optimizely because it fires before there's any DOM to manipulate.

app.run(function run($rootScope){
    $rootScope.$on('$viewContentLoaded', function() {
        window.optimizely = window.optimizely || [];
        window.optimizely.push(["activate"]);
    });
});

A more explicit way is to call window.optimizely.push(["activate"]) just in the controllers or directives that will actually have experiments. This way you can control the exact timing of the activate, like after data is loaded. I prefer this method because, more often than not, you're going to have to call the optimizely API to log a custom event to log that the user completed the desired goal anyway, so if I'm doing that event tracking explicitly, I might as well activate optimizely explicitly. Here's a service I inject when I need to activate or log events...

(function () {
    'use strict';

    function Optimizely($window) {
        $window.optimizely = $window.optimizely || [];

        this.Activate = function () {
            $window.optimizely.push(["activate"]);
        };

        this.TrackEvent = function (eventName) {
            $window.optimizely.push(["trackEvent", eventName]);
        };
    }

    angular.module('myApp').service('Optimizely', Optimizely);
}());

Usage in a controller...

function MyCtrl(Optimizely) {
    Optimizely.Activate();
    Optimizely.TrackEvent("my_goal_success");
}
JeremyWeir
  • 23,396
  • 10
  • 89
  • 106
  • If you want to remove an item on a certain page or event I am imaging that you would want that to take place in TrackEvent? – Winnemucca Jan 26 '16 at 20:43
1

I'm not sure how Optimizely works, but with Visual Website Optimizer there is a feature that allows us to add a variation using JS. We manipulate the content like so:

// get Angular scope from a known DOM element
e = document.getElementById('some-dom-id');
scope = angular.element(e).scope();
// update the model with a wrap in $apply(fn) which will refresh the view for us
scope.$apply(function() {
    scope.campaign.headline = 'This is a headline.';
}); 
timelf123
  • 607
  • 1
  • 8
  • 26
0

Optimizely is using jQuery to manipulate the DOM. jQuery works with all XML documents. The DOM resulting from Angular.js (I have on experience with that) is still just a DOM. So you can modify it.

But knowing how Optimizely works, you can also just put Angular.js sugar JavaScript code into the Optimizely variation code. Or jQuery. Or any other JS framework, or plain old JavaScript. It does not matter. The variation code will get evaled by Optimizely, and if it's valid JS (which it becomes if you use Angular.js code and the library is loaded) it will be executed. So you can do all the modification you want through your Angular.js syntax.

Optimizely will just decide when to do it and run it on the page. It will also do tracking for you. There should be no issues with firing events for Optimizely to track from Angular.js at all.

simbabque
  • 50,588
  • 8
  • 69
  • 121
  • How can I run angular code from outside the scope of angular? Would I have to define window level helper functions that can be accessed when optimizely runs? – timelf123 Feb 25 '14 at 20:11
  • Is there a scope? As I said, I am not familiar with angular. I played around a little with jquery and angular in http://jsfiddle.net/KzxB9/ and it is entirely possible to add DOM structures that angular will interact with. Remember Optimizely runs on the page where your JS is already there. Everything that is global is accessible somehow. If you can do it in the dev console, you can use it from Optimizely. – simbabque Feb 25 '14 at 22:17
  • Angular actually uses a subset of jQuery called jqLite. – dmur Sep 18 '14 at 17:36
0

im trying to use an input field to bind to my model use optimizely to change the input field and then force angular to reload the field

but it seems angular needs the .trigger('input') event to fire which works in firebug but not in the optimizely editor

//the optimizely editor would add this line (users etc) $('.debug.edit-ab-test'.val('abc');

//doesnt work in the editor, i've tried setInterval and setTimeout to delay etc $('.debug.edit-ab-test input[type="text"]').trigger('input');

user2045103
  • 51
  • 1
  • 2