2

Optimizely A/B test service uses .replaceWith("new HTML") extensively to produce easy A/B testing. This has the side effect of removing any event listeners that were listening to events from the replaced elements, even if the new elements would have same IDs/classes.

Example:

  1. DOM contains:

    <div class="something">
      <button id="myButton"></button>
    </div>
    
  2. Listened by: $("#myButton").click(function() { console.log('clicked!'); });

  3. Replaced by: $(".something").replaceWith("some new HTML, containing #myButton");

After step 3, hitting the #myButton does not work anymore, as the original DOM element was destroyed and a new one added.

What would be a good and "clean" way to solve this issue ?

Possible solutions

  1. Know your codebase and "re add" the appropriate event listeners in Optimizely's experiment.
    • problem: A/B testers might not be real software devs, think this is a hassle.
    • does not seem like a very clean way
  2. Find a way to execute code after Optimizely, add all event listeners that way. Is there a good way to do this ?

  3. Use "event delegation using $.on()" as described here: how to replace HTML with jQuery but keep event bindings

    • problem: hard to predict what exactly will be A/B tested and replaced

Edit: I am using jQuery 1.11.x

Community
  • 1
  • 1
elnygren
  • 5,000
  • 4
  • 20
  • 31
  • Why don't you just use `on()` for any possible a\b targets? – Parris Varney Jan 18 '16 at 14:53
  • I have some `.blur()` and `.click()` calls in my current problem atm. Aren't those just aliases for `.on('blur',fn)` and `.on('click', fn)` ? – elnygren Jan 18 '16 at 15:01
  • 1
    They are not aliases. A crude explanation is `$('identifier').on()` will listen to any elements that match `'identifier'` whereas `click()` or `blur()` will attach listeners only to existing elements. More info at: http://stackoverflow.com/questions/9122078/difference-between-onclick-vs-click – Parris Varney Jan 18 '16 at 15:15
  • jQuery API Doc on .blur(): "This method is a shortcut for .on( "blur", handler )" (https://api.jquery.com/blur/)... -.- Is this just bad wording in the docs or am I looking at the wrong place? – elnygren Jan 18 '16 at 16:37
  • 1
    Things may have changed, but I think that blurb is somewhat confusing. Check out the section on "Delegated Events" at https://api.jquery.com/on/. I *think* the shortcut is for `on(event, handler)`, whereas you probably want `on(event, delegatedElement, handler)`. – Parris Varney Jan 18 '16 at 17:03

2 Answers2

1

I'm not sure that there's a "clean" way to do this since the events attached to the old element may not be applicable to the new one. Imagine a form element being replaced by a div: what should happen with onchange or onblur events?

Optimizely tries to cater to two different types of users simultaneously: power users and novices. The WYSIWYG can't do complicated variations, so if you're editing the code then it's expected that you know what you're doing.

Generally speaking, that means option 1 above. Two reasonable ways to do that would be:

  1. Transform the old element into the new one, rather than just replace it
  2. Hide the old element, add the new one, then proxy events from the new element to the old one

Unless of course the main codebase is binding events with event delegation, in which case keeping the same IDs/classes should suffice. If you have access to the original codebase (this is often not the case for people working in the Optimizely editor -- I work for the largest 3rd party testing agency and we can't make any changes to the client's actual codebase) then you should upgrade to event delegation anyway.

If you have access to the main site code then you certainly could create a callback attached to the window (Optimizely scopes all it's code) which your Optimizely code calls when it's finished, but again, event delegation would likely be a better option.

When you say you're using jQuery 1.11.x, do you mean on your site, or what's included by Optimizely? If what's included by Optimizely, is it the trimmed version or the full version (Optimizely Project Home-->Settings-->Javascript)?

  • I have access to the codebase and am using jQuery there (I've set Optimizely to not ship jQuery). It seems like I want to look more into event delegation as this would make it easier for our A/B tester. Perhaps it is good practice otherwise too. – elnygren Jan 19 '16 at 07:25
0

Shouldn’t you be able to use jQuery’s onRemove() to first setup listeners for the events that will happen behind Optimizely’s “magic”, e.g. 2200494?

Community
  • 1
  • 1
Forelight
  • 305
  • 5
  • 13