Home > Technical & Creative Skills > Programming, Servers & Scripts

Programming For Non-Programmer Affiliates, pt 3: Reacting To User Input Or Time (15)


05-01-2015 04:17 PM #1 caurmen (Administrator)
Programming For Non-Programmer Affiliates, pt 3: Reacting To User Input Or Time

Once again, brothers and sisters, let us delve into the eldrich, occult world of ... programming.

Or to put it another way - let's make your landers even more effective.

In this, the final part (for now) of my basic introduction to programming for affiliates, we're going to look at making your landing pages change and react based on what your visitors do.

We'll cover how to change parts of the page based on where they click; look at how your outsourced programmers might have done this on landers you already have (so that you can easily change them); look at timing-based changes; and even touch on animation!

Let's get going!


What You'll Need For This Tutorial

If you haven't read them already, Part 1 and Part 2 of this course are here and here, respectively. We won't be using code from those two parts, but we will be using the concepts in them. If you get stuck here, there's a good chance that having a look through those earlier parts will unstick you.

Other than that, you don't need to know any Javascript, just HTML and CSS.

You can easily apply the techniques I'll show you here to your existing landers, and that's probably the best way to learn. However, if you want a sample lander to experiment with, here's the code for a simple tester to use whilst you're learning:

Code:
<head>
<title>Parameter Passing Test</title>
</head>
<body>

<div id="question"><h1>Do You Like Money?</h1>

<button id="yes">Yes</button>
</div>

<div id="answer" style="display:none"><h1>You're In Luck, Then!</h1>

<p><a href="http://www.motleyfool.com">So Do These Guys!</a>
</div>

</body>
Unlike previous tutorials, you won't need to do any setup on your tracker for this part!


Reacting To User Input: Clicking

The simplest way we'll probably want to react to user input is when they click on something in our lander.

The classic use of this in affiliate marketing is for the "Rules Lander" - a series of pledges that the user has to click through before he or she is "allowed" to click onto the offer. See Finch's classic post on the psychology behind the Rules Lander - this kind of interaction really works.

So how do we make it happen? Well, it's really simple. All that we're doing with any event where the user clicks and a piece of content is replaced is (usually) hiding one HTML block and replacing it with another. We do that very simply by changing the CSS on the div from display:none to display:block.



In order to make that happen, we first have to find the div we want to change, and then we have to change its .style property, just like we changed its innerHTML property in earlier parts of this series.

Start by adding a script block (see part 1 of the tutorial - "<script type="text/javascript"></script>" ), and within that add these two lines:

Code:
document.getElementById('question').style.display = "none" ;
document.getElementById('answer').style.display = "block" ;
Take a moment to look over each of those lines and make sure you understand what they do! The only new point here is that unlike "innerHTML", "style" has sub-properties for each individual possible CSS style - color, width, background-color, and so on. We can change ALL of them with Javascript just by accessing them as we do here - style.color, style.width, etc. If you're confused by anything in those lines, post below and I'll explain further!

Otherwise, try running that lander. It looks like it hasn't worked - certainly nothing changes. But if you look, you'll see that "question" (which should, according to the HTML, be visible) is hidden, and "answer" (which is set to be hidden in the HTML) is visible. The Javascript works, but it works as soon as the page loads. We need to set it to trigger on the user's clicking.

To do that, we first need to create our own function. We've discussed functions before, in Part 1, but now we're going to create one of our own. It's actually very simple to do.

To create a function, you start by typing "function". Then you give it a name - in this case, "showhide". Then you add the parameters for the function - in this case, our function won't take any parameters, so we just add two brackets: () .

Finally, you enclose the code that the function is meant to run in curly brackets, just like our IF statement from part 2: { then the code then }.

Here's how it all comes together:

Code:
function showhide(){
	document.getElementById('question').style.display = "none" ;
	document.getElementById('answer').style.display = "block" ;
}


Add that into your lander, replacing the two lines we added above.

Why do we do this? Well, now, whenever we want this code to run, we can just type "showhide()" in our Javascript. That's a lot quicker!

In addition, that code won't run unless we type "showhide()" in our code. Try running your lander again now - you'll see that the question is visible and the answer isn't. If you add

showhide();


at the bottom just above </script>, you'll see that the code functions as before - in other words, the Javascript runs. Remove that once you've tested it.

The shortness of functions is particularly useful when we combine it with the "onclick" attribute of HTML, which is what makes the magic happen here.

Any HTML tag - <a>, <p>, <div>, <img>, etc - can have an "onclick" element added to it just like a style, a class or an ID. Anything in the "onclick" is executed as Javascript when the element is clicked.

So in this case, just change the opening button tag to be:

<button id="yes" onclick="showhide();">


Now click the button - and you'll see it magically change!

This functionality opens up all sorts of possibilities:





Using this to build a multiple question lander

That's literally all the coding knowledge you need to build a questions-based lander. Just remember that you'll need to assign a different ID name for each section.

To make it more efficient, you'll probably also want to modify showhide() to take the name of the element to hide and the name of the element to show as parameters. That's really simple to do - all parameters do is pass values as variables so that you can, for example, use one function to show and hide multiple things.

Here's a tutorial on Javascript function parameters, and here's how the code would look with parameters assigned:

Code:
function showhide(showthis, hidethis){
	document.getElementById(hidethis).style.display = "none" ;
	document.getElementById(showthis).style.display = "block" ;
}
You'd then modify the button to be:

<button id="yes" onclick="showhide('answer', 'question');">


where 'answer' and 'question' are the ids of the divs you want to show and hide - so you could have showhide('question2', 'question'); to hide your first question and show your second, showhide('question3', 'question2'); to show your third and hide your second, and so on.



But My Lander's Code Looks Different To this! Meet JQuery

If you've had a questions-based lander coded or used code from somewhere else (such as my ready-made questions script), you may have seen that the syntax is different. There's no onclick function, and the Javascript code looks weird, with dollar signs and unfamiliar functions everywhere.

JQuery is a code library for Javascript that's very widely used, because it changes and extends what Javascript can do. Many questions landers will use JQuery, because it has built-in show and hide functions that make life easier.

The link above - http://stmforum.com/forum/showthread...r-Your-Landers - goes through standard questions lander JQuery in some detail. If you need to modify a JQuery based lander, that'll give you a good starting point!




But What If I Want Time-Based Change?

We don't always want our lander to respond based on user interaction. Sometimes, we just want to have something happen after a little while - like having our CTA get larger, or having a "last few remaining!" notice pop up. Or even having a countdown timer!

This is all simple stuff to do.

We start by creating a function, just as we did above. In this case, let's create a function to make our "Yes" button become much bigger:

Code:
function bigbutton(){
	document.getElementById("yes").style.fontSize = "xx-large";
}
As above, make sure you know what's going on in that function, and ask below if you don't understand anything!

Now, we use a Javascript timing event - a special sort of function that tells Javascript to execute code after a certain amount of time.

In this case, we'll use the function setTimeout(), which executes the code once after a certain amount of time. It's really easy to use: you just list the function to call as its first parameter, and the time in milliseconds to wait as the second parameter:

setTimeout(bigbutton, 3000);


Note that you don't use the () after the name of the function here. Why? Well, the answer can be summarised as "because Javascript is weird". It's just a quirk you need to remember.

Add this line after the function above, and reload the page. You'll see "Yes" get bigger after 3 seconds!


Creating A Javascript-Based Timer

If you want something to change repeatedly, on the other hand, you use a different function: setInterval. It works the same way as "setTimeout", but after it's activated, its timer restarts. Then it activates again, restarts, and so on.

In other words, setInterval(blah, 1000) will call the function blah() every second.

We can use this for a lot of things, but the most obvious is to create a timer - which is actually really easy to do!

To start with, we need a <span> HTML element containing only the numbers of the countdown. Add this code just above <script in your lander:

<p>This question will only be available for <span id="countdown">100</span> seconds.


Reload. You'll see that the countdown has appeared - but it's not counting down yet. Let's fix that.

You already know everything you need to know to make the countdown happen! Have a go at writing the code to do it just now. If you get stuck, or once you have code that you think is right, read on!

...

...

OK, we need to do two things. Firstly, we need to create a function that reduces that number by one. That's really easy to do, because we can just use innerHTML to pull the number, then do math on it:

Code:
function countdown(){
	document.getElementById("countdown").innerHTML = document.getElementById("countdown").innerHTML - 1; 
	}
Then, we just put a line of Javascript in below that line to call that function every second:

setInterval(countdown, 1000);


And that's all there is to it! Reload, and watch your countdown, well, count down!




Animating your lander

Finally, what if you want to add a bit of animation? These sudden changes are all very well, but they look pretty ugly - how do we make them change smoothly rather than jump?

Well, thanks to CSS3, it's actually incredibly easy to add smooth animation.

To cause an element to smoothly transition between one state and another, you just need to add the CSS3 "Transition" style to that element. In our example lander, just add this into the <head> block of the HTML:

Code:
<style>
#yes {
  -webkit-transition: all 1s;
  -moz-transition: all 1s;
  -o-transition: all 1s;
  transition: all 1s;
}
</style>
What that code will do is tell the element with the id of "yes" (our button) to transition smoothly over 1 second any time we change any of its styles (that's what the "all" means). We have to have the 4 lines in there to cover all browsers, as they all have different requirements for transition CSS: it's annoying but easy to remember.

Add that and reload your lander: you'll see that the "yes" element now smoothly animates as it gets larger. Try changing the time listed - if you put 10s rather than 1s in each line, it'll animate over 10 seconds.

Unfortunately, there are a few wrinkles to this. In particular, it's very tricky to get an element to smoothly disappear and then have another element appear in its place. There's a lot of reasons behind this, but the short version is that if you want to do a smooth animated fade in or fade out, you'll probably need to use an animation library or jQuery - both beyond the scope of this article!

Nonetheless, there's lots of interesting things you can do with simple animations: have your CTA gradually get larger, smoothly change heights or widths of elements (to give a "carousel" effect for images, for example) and more.


And That's It For Now!

If you've had any problems following this tutorial, don't worry! The mistake is probably mine, not yours: programming is notoriously difficult to teach! Let me know what part you got stuck on, below, and I'll help you get past it and update this tutorial to help future readers!

If you did get through the entire tutorial, here are a few follow-up questions to test what you've learned in this final part:



I hope you found this series useful! It may be back at some time in the future - if there's anything else you desperately want to know, ask in the comments!


02-16-2016 06:52 PM #2 ekentran1558 (AMC Alumnus)

This is awesome! Thank you for taking your time out to put all these tutorial together. I'm a noob and was really struggling with understanding all these codes! This really helped me a lot.


02-17-2016 11:04 AM #3 caurmen (Administrator)

@ekentran1558 - No problem!


02-17-2016 11:10 AM #4 iAmAttila (Veteran Member)

awesome tutorial caurmen!


02-18-2016 05:46 AM #5 ekentran1558 (AMC Alumnus)

Hi Caurmen,

I've been trying to figure this out for a bit now and was wondering if you could help. I've tried other things but haven't been successful with the codes for the methods that I have in mind.

Here's the code:

<div class="clear"></div>
<div><a target="_top" class="button5" href="http://Voluum.com/click" onclick="exit_a1() 'alert("message")';">SELECT</a></div>
</div>

What i'm trying to do here is have an alert message pop up, the user press ok, the user is then redirected to my offer page. Please advise.

-Ken


02-18-2016 11:16 AM #6 caurmen (Administrator)

You'll need to make some changes to the second line to make that work.

Here's the corrected version:

Code:
<div><a target="_top" class="button5" href="http://Voluum.com/click" onclick="alert('message'); window.location.href = 'http://www.google.com';">SELECT</a></div>
What's going on here? Well, first of all, you need to use single-quotes around your text (message) so that the HTML parser doesn't get confused. Otherwise, the browser reads the " after the "onclick" and goes "right, that's the start of the code", then gets to the first " in your code and says "right, that's the end of the code. Wait, that makes no sense."

Using single quotes means that the HTML parser, which runs before your Javascript code, doesn't make that mistake.

Secondly, if you're going to do this, you need to redirect people in the Javascript rather than assuming the link will do it. window.location.href = is the Javascript way to send people to a new page (or one of them), so we add it after the alert, meaning it'll be run after the user clicks on "OK". We add a semicolon after the alert message to indicate that what follows is a new instruction.

Thirdly, you've got quotes around your alert - 'alert should be just alert. You don't need the quotes and they'll cause the Javascript parser to lose the plot

Finally, I'm not sure what exit_a1() was meant to do? It looks like a function called from elsewhere in the landing page.

Hope that helps!


02-19-2016 02:01 AM #7 ekentran1558 (AMC Alumnus)

That really clears it up. I'm in my second month and wanting to hit 100 mph with a bunch of ideas only to keep getting lost. haha

Thank you so much!


02-21-2016 06:12 AM #8 ekentran1558 (AMC Alumnus)

Hi Caurmen,

I have a few more questions that I'm a little confused with.

So I got the alert script working on the lp when the user select the offer. However, when trying to add an exit pop at the very end, both the alert message and the exit pop appears one after another.

Here's my code:

<script language="javascript">var PreventExitPop = true;function ExitPop() {if(PreventExitPop != false) {return "message!"}}window.onbeforeunload = ExitPop;</script>

First the the user select the offer, the alert message would pop up. Which is expected, but the the exit pop also pops up after that before going to the offer.

Another issue that I am trying to figure out is an exit pop with redirect. Here's the code I found from google is this:

<script language="javascript">
(function() {
setTimeout(function() {
var __redirect_to = 'http://google.com';//

var _tags = ['button', 'input', 'a'], _els, _i, _i2;
for(_i in _tags) {
_els = document.getElementsByTagName(_tags[_i]);
for(_i2 in _els) {
if((_tags[_i] == 'input' && _els[_i2].type != 'button' && _els[_i2].type != 'submit' && _els[_i2].type != 'image') || _els[_i2].target == '_blank') continue;
_els[_i2].onclick = function() {window.onbeforeunload = function(){};}
}
}

window.onbeforeunload = function() {
setTimeout(function() {
window.onbeforeunload = function() {};
setTimeout(function() {
document.location.href = __redirect_to;
}, 500);
},5);
return 'message';
}
}, 500);
})();

The problem when using this code is that it disable the "alert(" code. Also, sometimes it works and sometimes redirect works but sometimes it doesn't.

It looks more complicated than I thought.

Here are my questions;

1. How can I make the alert and the exit pop work on the same lander without any interference from one another?

For the first scenario: If the offer were selected, only the alert would come up. If the user exits or hit the back button, only the exit pop would come up.

2. Is there a simpler code or way for me to code what I'm trying to do in the second scenario?

My first thought was two separate code. The first was the exit pop follow by the back button redirect but that didn't work.

Please advise.


08-04-2016 02:16 AM #9 aloeveraa1491 (Member)

Thanks for the guides!

Quick question: For the javascript based timer, how do you set it so that the timer stops at 0?
Because right now, the counter keeps counting down from 0, -1, -2, -3 till infinite


Edit: I found the answer on stackoverflow, and it's working for me!

http://stackoverflow.com/questions/1...t-reaches-to-0


<span id="counter">5</div>

<script type="text/javascript">
function countdown() {
var i = document.getElementById('counter');
i.innerHTML = parseInt(i.innerHTML)-1;
if (parseInt(i.innerHTML)==0) {
clearInterval(timerId);
}
}
var timerId = setInterval(function(){ countdown(); },1000);
</script>


09-08-2016 02:45 AM #10 joyshan (AMC Alumnus)

Hello Caurman

I ripped a lander and found a piece of javascript that I don't know what it can do, so could you please explain it briefly? Thanks!

I guess that it do a redirect job, am I right? If I delete it, will the lander work well?

<script>
;;
(function($) {
if (!$.browser && 1.9 <= parseFloat($.fn.jquery)) {
var a = {
browser: void 0,
version: void 0,
mobile: !1
};
navigator && navigator.userAgent && (a.ua = navigator.userAgent, a.webkit = /WebKit/i.test(a.ua), a.browserArray = "MSIE Chrome Opera Kindle Silk BlackBerry PlayBook Android Safari Mozilla Nokia".split(" "), /Sony[^ ]*/i.test(a.ua) ? a.mobile = "Sony" : /RIM Tablet/i.test(a.ua) ? a.mobile = "RIM Tablet" : /BlackBerry/i.test(a.ua) ? a.mobile = "BlackBerry" : /iPhone/i.test(a.ua) ? a.mobile = "iPhone" : /iPad/i.test(a.ua) ? a.mobile = "iPad" : /iPod/i.test(a.ua) ? a.mobile = "iPod" : /Opera Mini/i.test(a.ua) ? a.mobile = "Opera Mini" : /IEMobile/i.test(a.ua) ? a.mobile = "IEMobile" : /BB[0-9]{1,}; Touch/i.test(a.ua) ? a.mobile = "BlackBerry" : /Nokia/i.test(a.ua) ? a.mobile = "Nokia" : /Android/i.test(a.ua) && (a.mobile = "Android"), /MSIE|Trident/i.test(a.ua) ? (a.browser = "MSIE", a.version = /MSIE/i.test(navigator.userAgent) && 0 < parseFloat(a.ua.split("MSIE")[1].replace(/[^0-9\.]/g, "")) ? parseFloat(a.ua.split("MSIE")[1].replace(/[^0-9\.]/g, "")) : "Edge", /Trident/i.test(a.ua) && /rv[0-9]{1,}[\.0-9]{0,})/.test(a.ua) && (a.version = parseFloat(a.ua.match(/rv[0-9]{1,}[\.0-9]{0,})/)[1].replace(/[^0-9\.]/g, "")))) : /Chrome/.test(a.ua) ? (a.browser = "Chrome", a.version = parseFloat(a.ua.split("Chrome/")[1].split("Safari")[0].replace(/[^0-9\.]/g, ""))) : /Opera/.test(a.ua) ? (a.browser = "Opera", a.version = parseFloat(a.ua.split("Version/")[1].replace(/[^0-9\.]/g, ""))) : /Kindle|Silk|KFTT|KFOT|KFJWA|KFJWI|KFSOWI|KFTHWA|KF THWI|KFAPWA|KFAPWI/i.test(a.ua) ? (a.mobile = "Kindle", /Silk/i.test(a.ua) ? (a.browser = "Silk", a.version = parseFloat(a.ua.split("Silk/")[1].split("Safari")[0].replace(/[^0-9\.]/g, ""))) : /Kindle/i.test(a.ua) && /Version/i.test(a.ua) && (a.browser = "Kindle", a.version = parseFloat(a.ua.split("Version/")[1].split("Safari")[0].replace(/[^0-9\.]/g, "")))) : /BlackBerry/.test(a.ua) ? (a.browser = "BlackBerry", a.version = parseFloat(a.ua.split("/")[1].replace(/[^0-9\.]/g, ""))) : /PlayBook/.test(a.ua) ? (a.browser = "PlayBook", a.version = parseFloat(a.ua.split("Version/")[1].split("Safari")[0].replace(/[^0-9\.]/g, ""))) : /BB[0-9]{1,}; Touch/.test(a.ua) ? (a.browser = "Blackberry", a.version = parseFloat(a.ua.split("Version/")[1].split("Safari")[0].replace(/[^0-9\.]/g, ""))) : /Android/.test(a.ua) ? (a.browser = "Android", a.version = parseFloat(a.ua.split("Version/")[1].split("Safari")[0].replace(/[^0-9\.]/g, ""))) : /Safari/.test(a.ua) ? (a.browser = "Safari", a.version = parseFloat(a.ua.split("Version/")[1].split("Safari")[0].replace(/[^0-9\.]/g, ""))) : /Firefox/.test(a.ua) ? (a.browser = "Mozilla", a.version = parseFloat(a.ua.split("Firefox/")[1].replace(/[^0-9\.]/g, ""))) : /Nokia/.test(a.ua) && (a.browser = "Nokia", a.version = parseFloat(a.ua.split("Browser")[1].replace(/[^0-9\.]/g, ""))));
if (a.browser)
for (var b in a.browserArray) a[a.browserArray[b].toLowerCase()] = a.browser == a.browserArray[b];
$.extend(!0, $.browser = {}, a)
}
})(jQuery);
(function() {
(function() {
$.browser.webkit || $.event.add(window, "load", function() {
$("a[href][rel~=noreferrer], area[href][rel~=noreferrer]").each(function() {
var b, e, c, g, d, f, h;
b = this;
c = b.href;
$.browser.opera ? (b.href = "http://www.google.com/url?q=" + encodeURIComponent(c), b.title || (b.title = "Go to " + c)) : (d = !1, g = function() {
b.href = "javascript:void(0)"
}, f = function() {
b.href = c
}, $(b).bind("mouseout mouseover focus blur", f).mousedown(function(a) {
a.which === 2 && (d = !0)
}).blur(function() {
d = !1
}).mouseup(function(a) {
if (!(a.which ===
2 && d)) return !0;
g();
d = !1;
setTimeout(function() {
f()
}, 500);
return !1
}), e = "<html><head><meta http-equiv='Refresh' content='0; URL=http://domainname/&quot;+$(&quot;&lt;p/&gt;&quot.text(c).html()+&quot;' /></head><body></body></html>", $.browser.msie ? $(b).click(function() {
var a;
switch (a = this.target || "_self") {
case "_self":
case window.name:
a = window;
break;
default:
a = window.open(null, a)
}
a = a.document;
a.clear();
a.write(e);
a.close();
return !1
}) : (h = "data:text/html;charset=utf-8," +
encodeURIComponent(e), $(b).click(function() {
this.href = h;
return !0
})))
})
})
})()
}).call(this);
</script>


09-08-2016 11:43 AM #11 caurmen (Administrator)

Hmm, that's pretty complex. On a quick look - not a full code audit - it looks to be doing something significantly more complex than a simple redirect.

It's detecting the useragent then performing different things based on which browser is detected. Looking at the code, there's a good chance that it's deliberately obfuscating what it's doing too, although I'm not certain on that. (The very short variable names and multiple reassignments are what make me think there might be something fishy going on.)

It could also be that this Javascript depends on other scripts loaded on the page - were there other scripts loaded or included in the lander?

I'd be wary of running a lander with this code intact. However, there's a good chance that removing it will break some of the page's functionality.

It's very hard to say more on what the code does without it being properly formatted (so that it's easier to see where the code blocks start, end and indent), and without putting quite a lot of time into it.

(I also checked this with a very high-level senior developer friend of mine, and his opinion is the same as mine - obfuscated code, hard to tell what it does without reformatting it. Probably best to avoid running it on your landers.)


09-09-2016 05:24 AM #12 joyshan (AMC Alumnus)

Thanks caurmen.

I am really appreciated that you took your time to check this code.

I have deleted some pieces of JavaScript with obfuscated code that I don't know at all, and the lander works properly. After reading all your threads about JavaScript I can understand some easy scripts and clean the landers I ripped. Your tutorial is clear and newbie friendly.

Awesome.


09-09-2016 09:40 AM #13 caurmen (Administrator)

Cool, glad it helped!

Pro tip given that lander looked like it had some obfuscation going on: check the CSS for scripts too. Most people don't know this but there are ways to embed Javascript in CSS as well.


02-06-2017 03:08 AM #14 thetailend (AMC Alumnus)

This is gold!

I've been doing the Codecademy JS course and I'm constantly worrying whether some of the things im learning are useful for AM or not. These series show me how they can be applied to AM - so so soooo helpful!

Please keep it going


02-06-2017 11:14 AM #15 caurmen (Administrator)

@thetailend - Being able to program is a major unfair advantage as an affiliate. Use it ruthlessly!


Home > Technical & Creative Skills > Programming, Servers & Scripts