Getting API Parameter Data from Google Optimize - javascript

Is there a way to get Google Optimize to return specific data values or even JSON objects for use with experiment callbacks?
We are using Google Optimize without using the visual editor. Instead, we simply want it to indicate which layout pattern to request from a separate API we set up a long time ago.
function gtag() {dataLayer.push(arguments)}
function implementExperimentA(value) {
if (value == '0') {
// Provide code for visitors in the original.
} else if (value == '1') {
// Provide code for visitors in first variant.
} else if (value == '2') {
// Provide code for visitors in section variant.
}
...
}
gtag('event', 'optimize.callback', {
name: '<experiment_id_A>',
callback: implementExperimentA
});
This code example is everywhere and basically what I want to use, but instead of value==1 etc, I want to to be able to use value as a request parameter.
$.get(url, {layoutId: value});
LayoutIds are not integers however. They are unique strings. So again, my question: Is there a way to get Google Optimize to return specific data values or even JSON objects for use with experiment callbacks? Or do I need to map all the Experiment indexes to their correlating API parameter values within my javascript code?

Related

How to provide an XMLHttpRequest promise to a JavaScript function

Messing around with an autocomplete plugin available at https://www.npmjs.com/package/bootstrap-4-autocomplete, and the following works:
$('#id').autocomplete({
source: {'test1':1, 'test2':2, 'test1':3}
});
Instead of local JSON, will need to make an XMLHttpRequest and was thinking something like the following, and while I don't get an error, I also don't get anything:
$('#id').autocomplete({
source: function() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
return JSON.parse(this.responseText);
}
};
xhttp.open(method, url, true);
xhttp.send();
}
});
The plugin's author made the following remark a while back:
I don't have plans to directly invoke any url inside the lib. What you
can do is set autocomplete to your textfield after your ajax call
returns, which you can do with jQuery, like this:
$.ajax('myurl').then((data) => $('#myTextfield').autocomplete({
source: data }));
You don't have to worry about setting autocomplete to a field multiple
times, it is supposed to work like this when you need to change the
source.
Tried it and as expected, $.ajax() initiated an XMLHttpRequest request upon page load, and not as desired when the user enters a character into the search input.
How am I able to make an XMLHttpRequest to source the data into the plugin? I am assuming that I should be using a promise, however, if not, still would appreciate any assistance.
Thanks
Well, that's how plugin supposed to work. Its meat and potatoes is createItems function, called on keyup event - and responsible for filling out that dropdown with items. And here's its key part (1.3.0 version):
function createItems(field: JQuery < HTMLElement > , opts: AutocompleteOptions) {
const lookup = field.val() as string;
// ...
let count = 0;
const keys = Object.keys(opts.source);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const object = opts.source[key];
const item = {
label: opts.label ? object[opts.label] : key,
value: opts.value ? object[opts.value] : object,
};
if (item.label.toLowerCase().indexOf(lookup.toLowerCase()) >= 0) {
items.append(createItem(lookup, item, opts));
if (opts.maximumItems > 0 && ++count >= opts.maximumItems) {
break;
}
}
}
// skipped the rest
}
As you can see, each time createItems is called, it goes through source object, grepping all the items containing lookup string.
So all the data parts are expected to be there - and to be processable synchronously. That's the plugin's way, with all good and bad coming out of this approach.
The best thing the plugin's author could've suggested here (without going against what plugin is about) is using AJAX to prepopulate the data before calling autocomplete. And that's what he did in that comment actually.
Now, what can be done here? One might think it's enough just to transform createItems into an async function - for example, calling source if it's a function and expecting its result to be a Promise. It seems to be seductively simple excluding that lookup loop in process - and just take the the results of that AJAX call to repopulate source...
But that's not so simple, unfortunately: there are several caveats to be aware of. What should happen, for example, if user stops typing (triggering first AJAX call), then types some more, then stops once again (triggering another AJAX call) - but the first one actually arrives later? The corresponding bug was plaguing a lot of autocomplete implementations I've been working with, sadly - it's not that easy to reproduce if you're testing only with fast network connections (let alone only on localhost).
That's just one of the reasons the author decided against extending that plugin, it seems. After all, it was built to solve one specific task - and it does this well. So unless you want to fork it and essentially rewrite it into 'two strategies' one, I'd suggest considering looking somewhere else.

Reading a subset of documents using Couchbase View

I have around 25M documents in my cluster. I need to read 1M documents at a time without any specific criterion. I don't have the access to the keys. So I need to create a view which will emit documents till I reach a counter which goes up to 1M.
I have written a Map function inside which I am trying to create a static variable, but JS doesn't support static variables. I am not sure how to do this operation. The map function which I have written is just to return 1000 documents and it is full of errors. Can someone help me with this functionality?
function (doc, meta) {
value = foo();
if(value < 1000)
{
emit(meta.id, null);
}else{
return;
}
}
function incrementor(){
if(typeof incrementor.counter == 'undefined'){
incrementor.counter = 0;
}
return ++incrementor.counter;
}
Reading a subset of documents with Views can be done using pagination: http://blog.couchbase.com/pagination-couchbase
The Map function is called for each mutation stored in the bucket so a counter approach like this does not make sense. If you want to split your indexes, you need to do that based on the content of the document. But you should really use pagination. This can also be achieved with N1Ql by the way.

Concurrent beforeSave calls allowing duplicates

In an effort to prevent certain objects from being created, I set a conditional in that type of object's beforeSave cloud function.
However, when two objects are created simultaneously, the conditional does not work accordingly.
Here is my code:
Parse.Cloud.beforeSave("Entry", function(request, response) {
var theContest = request.object.get("contest");
theContest.fetch().then(function(contest){
if (contest.get("isFilled") == true) {
response.error('This contest is full.');
} else {
response.success();
});
});
Basically, I don't want an Entry object to be created if a Contest is full. However, if there is 1 spot in the Contest remaining and two entries are saved simultaneously, they both get added.
I know it is an edge-case, but a legitimate concern.
Parse is using Mongodb which is a NoSQL database designed to be very scalable and therefore provides limited synchronisation features. What you really need here is mutual exclusion which is unfortunately not supported on a Boolean field. However Parse provides atomicity for counters and array fields which you can use to enforce some control.
See http://blog.parse.com/announcements/new-atomic-operations-for-arrays/
and https://parse.com/docs/js/guide#objects-updating-objects
Solved this by using increment and then doing the check in the save callback (instead of fetching the object and checking a Boolean on it).
Looks something like this:
Parse.Cloud.beforeSave("Entry", function(request, response) {
var theContest = request.object.get("contest");
theContest.increment("entries");
theContest.save().then(function(contest) {
if (contest.get("entries") > contest.get("maxEntries")) {
response.error('The contest is full.');
} else {
response.success();
}
});
}

Call Functions Based On Query String Using JavaScript

On my web app, the user is asked a question and can choose only one of two answers. Yes or no. A query string is created based on their answer.
The following code carries the query string through the URL of every page:
var navlinks = document.getElementsByClassName("qString");
$(navlinks).prop("href", function() { return this.href + location.search; })
There are only 2 query strings, ?choice=yes and ?choice=no.
Once the user is taken through the app, if they navigate to either park01.html, park02.html, or park03.html from any other page, data will be pulled accordingly via a called function().
Here's my concept in pseudocode:
// I assume I should store specific html pages to a variable
var parkPages = ["park01.html", "park02.html", "park03.html”];
if (user clicks on specified html pages stored in variable) {
and the url contains = ?choice=yes;
Then call these functions: funcA(), funcB(), funcC();
}
else {
the url contains = ?choice=no;
Then call these functions: funcD(), funcE(), funcF();
}
Does the concept make sense? And what does the syntax look like?
If you're simply looking for a concrete translation of your pseudocode into JavaScript, based on your last comment, this should be what you need:
if (location.search === "?choice=yes") {
funcA();
funcB();
funcC();
}
else {
funcD();
funcE();
funcF();
}
Though at this stage, I'd recommend spending less time here and more on instructional/tutorial based websites.

How to achieve this structure for an autocomplete feature?

Here is, more or less, the general workflow:
The user types something on a input element;
Onkeyup, it will grab values from our backend script, and choose one.
After choosing, onblur, we will grab that value and use it to query the database for some data,
With the data returned from the DB he will execute other commands on an external server.
Then it will grab that values and use them to fill some input elements that are there waiting to be filled in, once the user chooses is option from the autocomplete element.
With that data in place, the user can then change the values, and hit save for yet another "ajax adventure..."
So, here, we are on steps 1 and 2 only (so I believe):
This is what I have been able to accomplish with the help of this article. That I'm trying to understand and adapt.
//1) WHEN WILL verificaInput BE CALLED?
$(document).ready(function verificaInput(inputString) {
if (inputString.length == 0) {
$('#sugestoes').hide();
} else {
$.post('modelAutocompleteTeste.php',
{nomeDominio: $('#nome-dominio').val()},
function(dadosResposta){
if(inputString.length > 3) {
$('#sugestoes').show();
//2) WHAT SHOULD I PUT HERE?
}
},
"json"
);
}
}
About 1: We must NOT use inline js calls. Where should we call/use the events like onkeyup and onblur etc?
About 2:
view source
print?
function(dadosResposta){
This will contain the response from our server side script, if the input string is greater then 3, it will show our suggestions. Now, inside this suggestion I will need to populate some elements (<li>) containing ALL the data returned in json format from our server side script (it's PHP - using json_encode())?
If so, is this the proper place to loop over and create the li elements?
More then answers, I would like to ask for some advice; I'm lost and stuck.
To get you started...
$(document).ready(function() {
$('#your_input_field').bind('keyup', function() {
var theVal = $(this).val();
if (theVal.length > 3) {
verificaInput(theVal);
} else {
$('#sugestoes').hide();
}
});
});
function verificaInput(inputString) {
if (inputString.length == 0) {// this will never be true
$('#sugestoes').hide();// so this will never be necessary
} else {
$.post('modelAutocompleteTeste.php',
{nomeDominio: $('#nome-dominio').val()},
function(dadosResposta){
if(inputString.length > 3) {
$('#sugestoes').show();
//2 here you should include a function name that will allow interaction with the provided list
}
},
"json"
);
}
}

Categories